클래스업(ClassUp)에서도 그렇고 다른 앱을 만들 때에도 그렇지만 내가 원하는 뷰를 따로 만들고 싶은 경우가 있다. 즉, 커스텀 뷰(CustomView)를 만들어야 하는 상황이 있다.
보통 커스텀 뷰(CustomView)를 만드는 상황은 아래와 같다.
- 기존에 존재하는 뷰에 기능적인 부분을 조금 더 구현할 때.
- 기존에 존재하는 뷰에 커스텀한 속성을 넣고 싶을 때.
- 여러 뷰를 통합해서 하나의 뷰로 가져가면서 내가 원하는 기능 및 속성을 넣고 싶을 때.
- 여러 화면에서 같은 기능 및 속성을 가지는 뷰를 사용해야 할 때.
전부 일맥상통하는 말이지만 결국 코드를 조금 더 깔끔하게 짜고, 조금 더 구조적으로 정교하게 코딩하기 위해서인 것 같다.
그러면 안드로이드에서 간단하게 커스텀하는 방법을 적어보려고 한다.
커스텀하는 케이스에는 크게 2가지가 존재하는 것 같다.
- ViewGroup을 상속받고 만들어 둔 레이아웃(Layout) xml을 추가하는 경우.
- View를 상속받아서 구현하는 경우.
당연히 두가지를 전부 혼용할 수 있다.
ViewGroup을 상속받고 레이아웃을 추가하는 경우.
일단 먼저, xml로 레이아웃 파일을 만들어야 한다. 이 때, 신경쓰면 좋은 것은 merge 태그를 쓰면 좋다. 레이아웃의 DOM 구조가 깊으면 깊을 수록 속도에 영향을 주기 때문이다
<!-- custom_layout.xml -->
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
// ...
</merge>
위와 같이 구현하고 java코드는 아래와 같이 사용한다. 내가 만약 해당 xml파일의 레이아웃을 ConstraintLayout에 맞게 작성하였다면 아래와 같이 작성할 수 있다.
public class CustomView extends ConstraintLayout {
public CustomView(Context context) {
super(context);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public CustomView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private void init(Context context) {
View view = View.inflate(context, R.layout.custom_layout, this);
// ...
}
}
위와 같이 init 메소드에서 내가 xml에서 만든 레이아웃을 추가할 수 있다.
그러면 view.findViewById등의 메소드를 이용하여 xml에 만든 뷰를 접근할 수 있다.
merge를 사용한 레이아웃 내에 사용할 뷰들의 id는
이 커스텀 뷰가 추가될 Activity나 Fragment내에 존재하는
id와 겹치지 않도록 주의해야한다.
그러면 Activity와 Fragment의 레이아웃 xml파일에서는 아래와 같이 작성 가능하다.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.MyApp.CustomView
android:id="@+id/customView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" />
<!-- ... -->
</RelativeLayout>
즉, CustomView는 ConstraintLayout와 같은 타입이다.
이제 여기서 나만의 속성을 넣고 싶을 수 있다. 이 경우는 res/values/attrs.xml 파일을 생성한 후 원하는 키와 해당되는 값의 타입을 작성해주면 된다.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomView">
<attr name="boolKey" format="boolean" />
<attr name="intKey" format="integer" />
<attr name="stringKey" format="string" />
<!-- ... -->
</declare-styleable>
</resources>
이렇게 작성하면 아래와 같이 변경시킬 수 있다.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.MyApp.CustomView
android:id="@+id/customView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
custom:boolKey="true"
custom:intKey="1"
custom:stringKey="CustomView" />
<!-- ... -->
</RelativeLayout>
이렇게 한 후, Java 파일에서도 아래와 같이 수정해 준다
public class CustomView extends ConstraintLayout {
private boolean boolKey;
private int intKey;
private String stringKey;
// ...
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.CustomView,
0, 0
);
try {
boolKey = a.getBoolean(R.styleable.CustomView_boolKey, false));
intKey = a.getInt(R.styleable.CustomView_intKey, 0));
stringKey = a.getString(R.styleable.CustomView_stringKey);
} finally {
// release the TypedArray so that it can be reused.
a.recycle();
}
// ...
}
// ...
}
출처 : https://myksb1223.github.io/develop_diary/2019/03/23/CustomView-in-Android.html
참고 : https://devuryu.tistory.com/173
'Android' 카테고리의 다른 글
안드로이드 키보드 설정 ( 뷰가 밀려날때 ) (0) | 2020.02.23 |
---|---|
안드로이드 커스텀뷰 2) onDraw 방식 (0) | 2020.02.10 |
SQLite 정리된 블로그 (0) | 2019.11.21 |
JAVA Retrofit2 (0) | 2019.11.14 |
Geocoder 현재위치 받아오기 (0) | 2019.10.28 |