하루 노트 2020

[Do it 개정7판] 선택 위젯 만들기 본문

프로그래밍/안드로이드

[Do it 개정7판] 선택 위젯 만들기

haru0118 2020. 4. 10. 05:00

책: Do it 안드로이드 앱 프로그래밍 (개정 7판)
날짜: 20-04-10 
내용: Chapter02-07    

도구: 안드로이드 스튜디오
언어: 자바
환경: Windows10

 


 

07-1. 나인패치 이미지 알아보기

 

 

[1] 나인패치 이미지

 

이미지뷰를 XML 레이아웃에 추가해서 화면에 보여줄 때 이미지가 나타나는 영역보다

원본 이미지가 작으면 시스템이 이미지 크기를 자동으로 늘려준다.

 

이 기능은 해상도가 서로 다른 단말에서도 일정한 비율로 이미지의 크기를 지정하면

이미지가 자동으로 그 크기에 맞게 늘어나거나 줄어들게 하므로 아주 유용한 기능이다.

 

하지만 이미지가 늘어나거나 줄어들 때 이미지 왜곡이 발생한다.

이러한 이미지 왜곡을 해결하기 위해 나인패치 이미지를 사용한다.

 

 

나인패치 이미지 ( Nine Patch )

서로 다른 해상도를 가진 여러 단말에 dp 단위로 뷰의 크기를 맞추다 보면

이미지 크기가 자동 조정되면서 왜곡되는 현상이 발생하는데 이를 해결하기 위한 것

 

나인패치 이미지는 가로와 세로 끝부분의 픽셀들은 흰색 또는 검은색으로 지정되어 있다.

ㅇㅇㅇ9.png 처럼 확장자 앞에 .9 를 붙여야 한다.

 

안드로이드에서는 이 방식으로 이름을 지은 파일을 원본 이미미지의 가로, 세로 끝부분의 픽셀을

모두 나인패치 이미지의 정보를 담은것으로 인식한다.

 

흰색 : 늘어나지 않는 영역

검정색 : 늘어나는 영역

 

나인패치 이미지는 포토샵에 png나 jpg와 같은 이미지보다 가로, 세로 크기가 2픽셀씩 

큰 이미지를 새로 만들고 원본 이미지를 가운데에 복사하면 된다.

그러면 가장자리 한 픽셀씩을 흰색 또는 검정색으로 바꿀 수 있다.

 

 

 

 

[2] 나인패치 이미지 사용해보기

 

 

 

 

1) 메인 액티비티 xml 만들기 ( activity_main.xml )

 

아래 예제는 각각의 버튼 크기가 다르기 때문에 버튼에 설정된 이미지는

버튼 크기에 따라 자동으로 늘어난다.

 

위에 3개는 일반 이미지 / 아래 3개는 나인패치 이미지

 

 

 


 

07-2. 새로운 뷰 만들기

 

API에서 제공하는 뷰를 사용해서 새로운 뷰를 정의할 수 있다.

API에서 제공하는 뷰를 사용하려면 API의 뷰를 상속해야 한다.

 

onDraw( ) : 뷰가 화면에 보이기 전에 호출되는 메소드

해당 메소드를 재정의하면 원하는 내용물을 뷰에 그릴수 있다.

 

invalidate( ) : 그래픽을 다시 그린다. ( 이때 자동으로 onDraw( ) 메소드가 호출된다. )

 

* on은 주로 어떤 상황이되면 자동으로 호출되는 메소드들이다.

 

 

 

[1] 버튼 클래스 정의하기 ( API 상속 )

 

AppCompatButton 클래스를 상속해야 한다.

2개의 생성자를 반드시 추가해야 에러가 발생하지 않는다.

 

public MyButton( Context context )

public MyButton( Context context, AttributeSet attrs )

 

Context : 안드로이드는 UI객체를 만들때 반드시 전달받아야 한다.

AttributeSet : XML 레이아웃에 추가한 버튼 속성이 들어온다.

 

setBackgroundColor( ) : 배경색을 설정

setTextSize( ) : 글자색을 설정

 

단, 다음 방법은 px단위로만 설정이 가능해 sp단위를 사용하기 위해서는

아래와 같은 방법을 사용해야 한다. ( [2] 참고 )

 

 

 

 

 

onDraw( ) 메소드와 onTouchEvent( ) 메소드를 재정의

onTouchEvent( ) : 뷰가 터치될 때 호출되는 함수

 

onTouchEvent( ) 메소드가 호출되면서 전달되는 MouseEvent 객체에는 getAction( ) 메소드가 있어서

손가락이 눌렸는지, 눌린 상태로 드래그되는지 또는 손가락이 떼어졌는지를 알 수 있다.

 

getAction( ) 메소드는 정수형 값으로 이 상태를 반환한다.

이때 MotionEvent 객체의 ACTION_DOWN, ACTION_MOVE 등 상수로 정의되어있다.

 

 

손가락이 눌렸을 때 배경색과 글자색을 바꾸었다면 invalidate( ) 메소드를 호출하여 뷰를 다시 그린다.

뷰가 다시 그려진다면 onDraw( ) 메소드가 자동으로 동작한다.

 

 

 

 

[2] setTextSize( )메소드 sp단위로 설정하기

 

1. res / values / dimens 추가하기

2. dimens.xml 내에 텍스트 사이즈 정의하기

3. 가져와서 사용하기

 

dimens.xml 파일은 크기 값등을 정의할 수 있는 파일이다.

dimens.xml 파일에 <dimen> dp,sp 또는 다른 단위의 크기 값을 정의하면 소스코드에서 참조할 수 있다.

 

참조할 때는 Resources 객체의 getDimension( ) 메소드를 사용한다.

이 메소드에서 반환하는 값은 픽셀 갑승로 자동 변환된 값이다.

 

 

 

 

 

 

[3] 새로 만든 뷰 사용하기

 

직접 정의한 위젯은 XML 레이아웃에 추가할 때 패키지 이름까지 작성해야 한다.

 

 

 

[4] 실행화면

 

 

처음 실행

 

버튼 눌렀다 뗐을 떼

 


 

07-3. 레이아웃 정의하고 카드뷰 넣기

 

[1] 레이아웃을 상속해서 새로운 레이아웃 만들기

 

처음 실행
이미지01 클릭
이미지02 클릭

 

1) layout1.xml 추가하기

 

 

2) Layout1.java 추가하기 ( LinearLayout 상속 )

 

ㅁ 생성자 만들기 ( init 메소드에서 처리 )

=> Layout1 자바파일과 layout1.xml 파일을 인플레이션해서 연결해줌

 

 

3) activity_main.xml 작성하기

 

 

4) MainActivity.java 작성하기

 

 

 

[2] 카드뷰 사용하기

 

카드뷰는(CardView) 프로필과 같은 간단 정보를 넣기 위해각 영역을 구분하는 역할을 한다.

 

 

처음 실행화면
이미지01 버튼 클릭
이미지 버튼02 클릭

 

1) 팔레트에서 카드뷰 다운받기

 

 

2) layout1.xml 수정하기

 

CardView 클래스 설정

 

cardBackgroundColor : 배경색

cardCornerRadius : 모서리 둥글게

cardElevation : 올라온 느낌

cardUseCompatPadding : 기본패딩 적용

 

 

 


 

07-4. 리싸이클러뷰 만들기

 

( 리싸이클러뷰 참고 url : https://recipes4dev.tistory.com/154 )

 

선택위젯( Selection Widget ) -> 어댑터( Adapter ) 패턴 사용

선택 위젯에 데이터를 넣을 때 위젯이 아닌 어댑터에 설정해야 하며 화면에 보이는 뷰도 어댑터에서 만든다.

즉 리스트 모양의 뷰에 보이는 각각의 아이템은 뷰가 아닌 어댑터에서 관리한다.

 

 

 

[1] 기본 리싸이클러뷰 만들기

 

 

실행화면

 

리싸이클러뷰 만드는 순서

activitiy_main.xml -> Person.java -> person_item.xml -> PersonAdapter.java -> MainActivity.java

 

 

 

 

1) activitiy_main.xml 

메인 액티비티에 리싸이클러뷰 추가하기

 

 

 

 

2) Person 클래스 정의하기

어댑터를 만들기 전에 어댑터 안에 들어갈 각 아이템의 데이터를 담아둘 클래스를 정의

 

 

 

3) Person_item.xml 작성하기

리스트에 반복 될 화면 제작

 

 

4) PersonAdapter 클래스 정의하기 (어댑터 + 뷰홀더)

어댑터 : 데이터를 바탕으로 리사이클러뷰에 표시될 아이템 뷰를 생성한다

뷰홀더 : 화면에 표시될 아이템 뷰를 저장하는 객체

 

 

 

 

자세히1) 

 

 

자세히2) 

 

public class PersonAdapter extends RecyclerView.Adapter<PersonAdapter.ViewHolder>

 

필수 구현 메소드 3가지

01. public ViewHolder onCreateViewHolder( ) : 뷰홀더 객체가 만들어질 때 자동으로 호출

02. onBindViewHolder( ) : 재사용될 때 자동으로 호출

03. getItemCount( ) : 전체 아이템 개수 반환

 

onCreateViewHolder( ) 메소드 안에서 인플레이션을 진행하기 위해서는 Context 객체가 필요한데

파라미터로 전달되는 뷰그룹 객체의 getContext( ) 메소드를 이용하면 Context 객체를 참조할 수 있다.

 

onBindViewHolder( ) 메소드는 재활용할 수 있는 뷰홀더 객체를 파라미터로 전달하기 때문에

그 뷰홀더에 현재 아이템에 맞는 데이터만 설정하면 된다.

 

리싸이클러뷰는 아이템 개수만큼 객체로 만들어지지 않는다.

메모리를 효율적으로 사용하려면 뷰홀더에 뷰 객체를 넣어두고 사용자가 스크롤하여 보이지 않게 된 뷰 객체를

새로 보일 쪽에 재사용하는 것이 효율적이기 때문이다. 이 과정에서 뷰홀더가 재사용된다.

 

 

자세히3)

어댑터가 각가의 아이템을 위한 Person 객체를 ArrayList 안에 넣어 관리하기 때문에

이 어댑터를 사용하는 소스 코드에서 어댑터에 Person 객체를 넣거나 가져갈 수 있도록

addItem( ), setItems( ), getItem( ), setItem( ) 메소드를 추가한다.

 

 

5) MainActivity.java 작성하기

 

레이아웃 매니저는 리싸이클러뷰가 보일 기본적인 형태를 설정할 때 사용한다.

LinearLayoutManager : 세로방향(Vertical), 가로방향(Horizontal)

GridLayoutManager : 격자모양

 

 

 

+ 격자모양으로 보여주기

 

 

 

 

[2] 리싸이클러뷰 기능 추가하기 ( 아이템 클릭 시 토스트 메시지 출력 )

 

 

클릭 이벤트는 리싸이클러뷰가 아니라 각 아이템에 발생하게 되므로 

뷰홀더 안에서 클릭 이벤트를 처리하도록 작성한다.

 

뷰홀더의 생성자로 뷰 객체가 전달되므로 이 뷰 객체에 OnClickListener를 설정한다.

그러면 이 뷰를 클릭했을 때 그 리스너의 onClick( ) 메소드가 호출된다.

 

그런데 이 리스너 안에서 토스트 메시지를 띄우게 되면 클릭했을 때의 기능이 변결될 때마다

어댑터를 수정해야하는 문제가 생긴다. 따라서 어댑터 객체 밖에서 리스너를 설정하고 설정된 리스너 쪽으로

이벤트를 전달받도록 하는것이 좋다.

 

 

실행화면

 

 

 

1) OnPersonItemClickListener 인터페이스 작성

 

아이템 뷰가 클릭되면 자동으로 호출될 메소드 작성

뷰홀더 객체, 뷰 객체, 뷰의 position 정보가 전달되도록 설정 ( position : 몇 번째 아이템인지를 구분할 수 있는 인덱스 )

 

 

2) PersonAdapter.java 수정

 

어댑터 클래스가 새로 정의한 리스너 인터페이스 구현하도록 설정

 

 

아이템뷰에 OnClickListener 설정하기

아이템 뷰 클릭 시 미리 정의한 다른 리스너의 메소드 호출

 

외부에서 리스너를 설정할 수 있도록 메소드 추가 ( setOnItemClickListener )

 

 

onItemClick 메소드가 호출되었을 때 다시 외부에서 설정된 메소드가 호출

 

 

 

3) MainActivity.java 수정

 

어댑터 객체에 setOnItemClickListener 메소드를 호출하면서 리스너 객체를 설정하였다.

이렇게 하면 각 아이템이 클릭되었을 때 이 리스너의 onItemClick 메소드가 호출된다.

onItemClick 메소드 안에서는 어댑터 객체의 getItem 메소드를 이용해 클릭된 아이템 객체를 확인한다.

 

 

//

내가 사용하는 앱들만봐도 리싸이클러뷰는 앱 개발에 있어 많이 사용되는것 같다.

하지만 소스코드를 한 두 번보고 이해하기에는 어렵다 ㅠㅠ

지금은 전부다 이해하기 어렵지만 반복해서 보면서 익숙해져야겠다.

 

 


 

07-5. 스피너 사용하기

 

스피너는 일반적으로 윈도우에서 콤보박스로 불린다.

안드로이드 단말에서는 손가락으로 쉽게 터치할 수 있도록 별도의 창으로 선택할 수 있는 데이터 아이템들이 표현된다.

 

 

실행화면

 

 

 

[1] 스피너 만들기

 

OnItemSelectedListener : 스피너 객체가 아이템 선택 이벤트를 처리할 수 있도록 사용하는 리스너

onItemSelected( ) : 스피너의 한 아이템이 선택되면 자동으로 호출되는 메소드

 

스피너 객체도 선택 위젯이므로 setAdapter( ) 메소드의 파라미터로 어댑터 객체를 전달해야 한다.

 

ArrayAdapter : API에서 제공하는 기본 어댑터 ( 배열로된 데이터를 아이템으로 추가할 때 사용 )

simple_spinner_item : API에서 제공하는 레이아웃

 

스피너는 항목을 선택하기 위한 창이 따로 있기 때문에 항목을 선택하는 창을 위한 레이아웃도 설정해야한다.

이때 사용하는 메소드가 setDropDownViewResource( ) 메소드이다.

 

 

 

public ArrayAdapter ( Context context, int textViewResourceId, T[] objects )

 

 

1) Context 객체 : 액티비티인  this를 전달

2) 뷰를 초기화할 때 사용되는 XML 레이아웃의 리소스 ID : android.R.layout.simple_spinner_item을 전달

3) 아이템으로 보일 문자열 데이터들의 배열 : items 

 

 

 

 


 

[ 도전13. 리싸이클러뷰에 고객 정보 추가하기 ]

 

실행화면

 

 

1) activity_main.xml

 

 

2) info.xml

 

 

3) infofile.java

 

 

4) infoAdapter.java

 

 

 

5) MainActivity.java

 

 

+ 나중에 해볼만한 기능

 

1) 데이터 입력시 기존 입력한 데이터 폼 삭제

2) 리싸이클러뷰의 아이템 클릭시 상세 프레그먼트로 전환

 

 

 

[ 도전14. 쇼핑 상품 화면 구성하기 ]

 

실행화면

 

 

1) activity_main.xml

 

 

2) shop_list.xml

 

 

3) Shop.java

 

 

4) ShopAdapter.java

 

 

5) MainActivity.java

 

 

6) OnShopItemClickListener.java

 

 

 

+ 나중에 해볼만한 기능

 

1) GridLayout에 이미지크기를 wrap_content로 설정하면 사진별로 마음대로 출력된다.

   이미지 width 값을 숫자dp로 값을 주지말고 다른 방법으로 해보면 좋을 것 같다.

 

리싸이클러뷰를 만드는것은 어느정도 손에 익었는데 

인터페이스를 생성하고 Listener 객체를 생성해 상호작용하는게 아직 어렵다.

계속해서 보고 공부해야겠다.