07-1 나인패치 이미지 알아보기
- 그래픽 프로그램에서 만든 버튼 이미지를 표시하면 단말에 따라 왜곡현상이 일어날 수 있기 때문에 해결 방법을 찾아야했다.
- 나인패치(Nine Patch) 이미지 왜곡 해결 방안이다.
- 수정한 이미지의 파일 이름은 ooo.9.png 처럼 파일 확장자 앞에 9을 붙이면 안드로에서는 그 파일을 원본 이미지의 가로, 세로 끝부분의 픽셀을 모두 나인패치 이미지의 정보를 담은 것으로 인식한다.
> SampleNinePatch 프로젝트
▼ activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Small"
android:textColor="#ffffffff"
android:background="@drawable/button_image_01"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MediumMediumMedium"
android:textColor="#ffffffff"
android:background="@drawable/button_image_01"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LongLongLongLongLongLongLong"
android:textColor="#ffffffff"
android:background="@drawable/button_image_01"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Small"
android:textColor="#ffffffff"
android:background="@drawable/button_image_02"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MediumMediumMedium"
android:textColor="#ffffffff"
android:background="@drawable/button_image_02"/>
<Button
android:id="@+id/btn6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LongLongLongLongLongLongLong"
android:textColor="#ffffffff"
android:background="@drawable/button_image_02"/>
a
</LinearLayout>
07-2 새로운 뷰 만들기
- 뷰의 영역과 크기는 그 뷰를 포함하고 있는 레이아웃의 영향을 받아 정해진다. 이때 개발자가 뷰의 상태에 따라 추가적인 코드를 넣을 수 콜백 메서드가 호출됨
- 뷰가 스스로의 크기를 정할 때 자동으로 호출되는 메서드는 onMeasure()이 스스로를 레이아웃에 맞게 그릴 때는 onDraw() 메서드가 자동으로 호출
■ onDraw() 메서드와 invalidate() 메서드 이해하기
- 새로운 뷰를 클래스로 정의하고 그 안에 onDraw() 메서드를 다시 정의한 후 필요한 코드를 넣어 기능을 구현하면 다른 모양으로 보이는 뷰를 직접 만들 수 있는 것
> SampleView 프로젝트
1단계
▼ Mybutton.java
public class MyButton extends AppCompatButton {
public MyButton(Context context) {
super(context);
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
}
- MainActivit.java 말고 MyButton 클래스를 만들고 androidx.appcompat.widget.AppCompatButton 클래스를 상속받는다.
- MyButton.java 파일이 만들어지면 클래스 안족에 빨간 줄이 표시된다. Alt + insert 눌러서 생성자를 생성한다
- 세 개 중 두 개가 필수 생성자이다. 하나는 Context 객체만 파라미터로 전달받고, 두 번째 생성자는 Context와 AttributeSet 객체를 파라미터로 전달받는다.
- 안드로이드는 UI 객체를 만들 때 Context 객체를 전달받도록 되어 있으므로 생성자에는 항상 Context 객체가 전달되어야 한다.
- AttributSet 객체는 XML레이아웃에서 태그에 추가하는 속성을 전달받기 위한 것
- 생성자가 두 개이므로 이 뷰가 초기화될 때 필요한 코드는 init() 메서드를 만들어 그 안에 정의한다. 그러면 어떤 생성자가 호출되든 상관없이 동일한 초기화 작업이 진행되도록 만들 수 있다.
2단계
▼ Mybutton.java
public class MyButton extends AppCompatButton {
public MyButton(Context context) {
super(context);
init(context);
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
setBackgroundColor(Color.CYAN);
setTextColor(Color.BLACK);
float textSize = getResources().getDimension(R.dimen.text_size);
setTextSize(textSize);
}
}
- init() 메서드에서는 Context 객체를 전달하도록 했으며 init() 메서드 안에서는 뷰의 배경색과 글자색을 설정하도록 했다.
- 배경색을 설정할 때는 setBackgroundColor(), 글자색은 setTextColor() 메서드를 호출하면 됩니다.
- 글자 크기를 조절하려면 setTextSize() 메서드를 이용해야 하는데 픽셀 단위 설정만 할 수 있기 때문에, sp 단위를 사용하는 것이 좋다. 하지만 sp 단위 설정으로 글자 크기를 조절하려면 소스 코드가 아니라 XML 파일을 사용해야 한다.
3단계
app/res/values 폴더 안에 dimens.xml 파일을 하나 만들자.
▼ dimens.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="text_size">16sp</dimen>
</resources>
- dimes.xml 파일은 크기 값 등을 정의할 수 있는 파일
- 소스 코드에서 참조할 때는 Resources 객체의 getDimension() 메서드를 사용한다. 이 메서드에서 변환하는 값은 픽셀 값으로 자동 변환된 값이다.
4단계
MyButton.java 클래스에 onDraw() 메서드와 onTouchEvent() 메서드를 재정의 해보자.
▼ Mybutton.java
package com.ogrg.techtown.sampleview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import androidx.appcompat.widget.AppCompatButton;
public class MyButton extends AppCompatButton {
public MyButton(Context context) {
super(context);
init(context);
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
setBackgroundColor(Color.CYAN);
setTextColor(Color.BLACK);
float textSize = getResources().getDimension(R.dimen.text_size);
setTextSize(textSize);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.d("MyButton", "onDraw() 호출됨.");
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d("MyButton", "onTouchEvent() 호출됨.");
int action = event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
setBackgroundColor(Color.BLUE);
setTextColor(Color.RED);
break;
case MotionEvent.ACTION_OUTSIDE:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
setBackgroundColor(Color.CYAN);
setTextColor(Color.BLACK);
break;
}
invalidate();
return true;
}
}
- MotionEvent 객체에는 getAction() 메서드가 있어서 손가락이 눌렸는지, 눌린 상태로 드래그되는지 또는 손가락이 떼어졌는지 알 수 있게 코드를 작성했다. getAction() 메서드는 정수형 값으로 이 상태를 반환한다.
5단계
activity_main.xml 코드를 수정하자.
▼ activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.ogrg.techtown.sampleview.MyButton
android:id="@+id/button"
android:layout_width="200dp"
android:layout_height="80dp"
android:layout_centerInParent="true"
android:text="시작하기"
/>
</RelativeLayout>
- MyButton은 직접 정의한 위젯이므로 XML 레이아웃이기 때문에 패키지 이름까지 함께 넣어야 한다.
07-3 레이아웃 정의하고 카드뷰 넣기
- 레이아웃을 상속해서 새로운 레이아웃을 만들고 그 안에 카드뷰를 넣어보자.
> SampleLayout 프로젝트
1단계
레이아웃에 사용될 XML파일과 소스 코드를 만든다.
▼ layout.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:id="@+id/imageView"
android:layout_width="80dp"
android:layout_height="80dp"
app:srcCompat="@mipmap/ic_launcher" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="이름"
android:textSize="30sp"/>
<TextView
android:id="@+id/textView4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="전화번호"
android:textSize="25sp"
android:textColor="#FF0000FF"/>
</LinearLayout>
</LinearLayout>
- XML 파일과 매칭될 클래스 파일을 만들어야 한다.
▼ Layout1.java
package com.ogrg.techtown.samplelayout;
import android.content.Context;
import android.text.Layout;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
public class Layout1 extends LinearLayout {
public Layout1(Context context) {
super(context);
init(context);
}
public Layout1(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.layout, this, true);
}
}
- init() 메서드 안에서는 LayoutInflater 객체를 참조했다. 이 객체는 시스템 서비스로 제공되므로 getSystemService() 메서드를 호출하면서 파라미터로 Context.LAYOUT_INFLATER_SERVICE 로 전달하면 객체가 반환된다.
- 이 객체의 inflate() 메서드를 호출하면서 XML 레이아웃 파일을 파라미터로 전달하면 인플레이션(XML 파일의 객체화)이 진행된다.
- 인플레이션 과정이 끝나면 XML 레이아웃 파일 안에 넣어둔 이미지뷰나 텍스트뷰를 찾아서 참조할 수 있다. 액티비티에서 사용했던 findViewById() 메서드를 동일하게 호출하면 됨
2단계
XML 레이아웃 파일 안에 넣어둔 이미지뷰나 텍스트뷰를 찾아서 참조할 수 있도록 findViewById를 이용해 이미지뷰와 텍스트뷰를 찾아내기
▼ Layout1.java
package com.ogrg.techtown.samplelayout;
import android.content.Context;
import android.text.Layout;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
public class Layout1 extends LinearLayout {
ImageView imageView;
TextView textView, textView2;
public Layout1(Context context) {
super(context);
init(context);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.layout, this, true);
imageView = findViewById(R.id.imageView);
textView = findViewById(R.id.textView3);
textView2 = findViewById(R.id.textView4);
}
public void setImage(int resId){
imageView.setImageResource(resId);
}
public void setName(String name){
textView.setText(name);
}
public void setMobile(String moblie){
textView.setText(moblie);
}
public Layout1(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.layout, this, true);
}
}
- 이미지뷰에 보이는 이미지를 바꿀 수 있는 메서드 중의 하나가 setImageResource() 메서드인데 이 메서드는 app/res/drawable 폴더 안에 들어있는 이미지 파일을 참조하는 정수 값을 파라미터로 전달받는다.
3단계
레이아웃을 상속한 뷰를 메인 액티비티에 추가하기
07-4 리싸이클러뷰 만들기
- 세로 모양으로 된 화면 컨트롤
07-5 스피터 사용하기
Mission 13 리싸이클러뷰에 고객 정보 추가하기
Mission 14 쇼핑 상품 화면 구성하기
'컴퓨터 공학 > Android' 카테고리의 다른 글
[안드로이드 스튜디오] 데드락 발생 이유? (1971) | 2019.12.09 |
---|---|
[안드로이드 스튜디오]ems란? (1828) | 2019.12.09 |
[Do it 개정6판_안드로이드 스튜디오]둘째마당_15 푸시 서비스와 센서 및 단말 기능 사용하기 (0) | 2019.12.03 |
[Do it 개정6판_안드로이드 스튜디오]둘째마당_11 단말에 데이터베이스와 내용 제공자 만들기 (0) | 2019.12.03 |
[Do it 개정6판_안드로이드 스튜디오]둘째마당_10 서버에 데이터 요청하고 응답받기 (0) | 2019.12.03 |
댓글