환경설정 페이지의 각 세팅은 일정한 패턴이 있기 때문에 이를 각각 구현한다면 너무나 큰 시간과 에너지의 낭비가 된다. 각 세팅을 xml에서 정의하고 코드 작성은 최소화하는 방법에 대해서 몇 차례 나눠서 정리를 할 생각이다.
달성해야 하는 목표는 아래와 같다.
- 환경설정의 각 세팅의 기본적인 UI 생성은 XML에서 하도록 한다.
- 설정 Activity는 하나만 만들도록 한다. AndroidManifest에서 설정 Activity만 수십개씩 관리하는 것도 힘들다. 하나의 SettingActivity로 모든 여러 설정 페이지를 다 구현한다.
- 세팅 항목의 초기화 변경시 UI 업데이트 등은 별도의 CommonSettingsHandler를 통해서 한다.
- 설정 페이지에서 Activity 종속적인 처리는 ActivityCycleListener를 통해서 한다.
- 설정 값의 기본적인 액션은 XML에서 다 제공한다.
* 다른 설정 페이지로 이동
* OS 웹 브라우저 열기
* WebView 브라우저로 열기
* 마켓 페이지 열기
* 앱의 다른 Activity로 이동하기
일단 오늘은 CommonSettingsView만 만들자. 생산물에 대한 정리이므로 자세한 설명은 생략한다. custom attribute 사용법은 구글 검색하면 더 자세히 나온다.
view하나에서 모든 값을 초기화할 필요가 있기 때문에 cumtom attribue를 정의한다.
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="settings_custom">
<attr name="titleText" format="string"/>
<attr name="subjectText" format="string"/>
<attr name="valueText" format="string"/>
<attr name="visibleCheck" format="boolean"/>
<attr name="visibleArrow" format="boolean"/>
<attr name="description" format="string"/>
<attr name="key" format="string"/>
<attr name="settingKey" format="string"/>
<attr name="action" format="string"/>
<attr name="actionParamTitle" format="string"/>
<attr name="actionParamLayout" format="reference"/>
<attr name="actionParamUrl" format="string"/>
</declare-styleable>
</resources>
실제로 사용할 때는 custom attribute는 아래와 같이 사용된다.
settings_main.xml
<com.mdiwebma.base.view.CommonSettingsView
android:layout_width="match_parent"
android:layout_height="wrap_content"
custom:titleText="Title"
/>
<com.mdiwebma.base.view.CommonSettingsView
android:layout_width="match_parent"
android:layout_height="wrap_content"
custom:subjectText="@string/confirm"
custom:valueText="@string/confirm"
custom:visibleArrow="true"
custom:description="@string/confirm"
custom:settingKey="test_int"
custom:action="@string/confirm"
/>
<com.mdiwebma.base.view.CommonSettingsView
android:layout_width="match_parent"
android:layout_height="wrap_content"
custom:subjectText="Another Test"
custom:valueText="@string/confirm"
custom:description="@string/confirm"
custom:action="com.mdiwebma.learninghabit.activity.HabitSettingsActivity"
custom:actionParamTitle="@string/confirm"
custom:actionParamLayout="@layout/settings_main"
/>
세팅 버튼 디자인, 최대한 간단하게 디자인 한다.
common_settings_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="vertical"
android:background="@drawable/setting_button_bg">
<LinearLayout
android:id="@+id/title_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title"
style="@style/settings_title"/>
</LinearLayout>
<LinearLayout
android:id="@+id/subject_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_gravity="center_vertical"
android:visibility="gone">
<TextView
android:id="@+id/subject_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_weight="5"
android:gravity="center_vertical"
android:text="Subject"
style="@style/settings_subject"/>
<TextView
android:id="@+id/value_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="4"
android:gravity="right"
android:text="Value text"
android:visibility="gone"
style="@style/settings_value_text"/>
<CheckBox
android:id="@+id/checkbox"
android:layout_width="18dp"
android:layout_height="18dp"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:layout_marginRight="5dp"
android:focusable="false"
android:clickable="false"
android:visibility="gone"
android:button="@drawable/selector_setting_checkbox"/>
<ImageView
android:id="@+id/arrow_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:src="@drawable/icon_arrow"
android:layout_gravity="center_vertical"
android:visibility="gone"/>
</LinearLayout>
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginLeft="15dp"
android:text="Description"
android:visibility="gone"
style="@style/settings_description"/>
</LinearLayout>
custom attribue를 초기화하고, view의 visibility를 조정한다. 값의 초기화와 Click 이벤트는 CommonSettingsHandler에 위임한다.
CommonSettingsView.java
package com.mdiwebma.base.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.widget.CheckBox;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import com.mdiwebma.base.annotation.ViewById;
import com.mdiwebma.base.logging.Dlog;
import com.mdiwebma.base.settings.Settings;
import com.mdiwebma.base.utils.InjectionUtils;
import com.mdiwebma.base.utils.StringUtils;
import com.mdiwebma.base.utils.ViewUtils;
import com.mdiwebma.learninghabit.R;
/**
* @author djkim
*/
public class CommonSettingsView extends FrameLayout implements View.OnClickListener {
@ViewById(R.id.title)
TextView title;
@ViewById(R.id.subject_text)
TextView subjectText;
@ViewById(R.id.value_text)
TextView valueText;
@ViewById(R.id.checkbox)
CheckBox checkBox;
@ViewById(R.id.arrow_icon)
ImageView arrowIcon;
@ViewById(R.id.description)
TextView description;
String key;
Settings setting;
String action;
String actionParamTitle;
String actionParamUrl;
int actionParamLayout;
public CommonSettingsView(Context context) {
this(context, null);
}
public CommonSettingsView(Context context, AttributeSet attrs) {
super(context, attrs);
InjectionUtils.injectViewById(this, inflate(getContext(), R.layout.common_settings_view, this));
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.settings_custom);
if (typedArray != null) {
String value;
value = typedArray.getString(R.styleable.settings_custom_titleText);
if (StringUtils.isNotEmpty(value)) {
ViewUtils.setVisible(findViewById(R.id.title_layout));
title.setText(value);
}
value = typedArray.getString(R.styleable.settings_custom_subjectText);
if (StringUtils.isNotEmpty(value)) {
ViewUtils.setVisible(findViewById(R.id.subject_layout));
subjectText.setText(value);
}
value = typedArray.getString(R.styleable.settings_custom_valueText);
if (StringUtils.isNotEmpty(value)) {
ViewUtils.setVisible(valueText);
valueText.setText(value);
}
if (typedArray.getBoolean(R.styleable.settings_custom_visibleArrow, false)) {
ViewUtils.setVisible(arrowIcon);
}
if (typedArray.getBoolean(R.styleable.settings_custom_visibleCheck, false)) {
ViewUtils.setVisible(checkBox);
}
value = typedArray.getString(R.styleable.settings_custom_description);
if (StringUtils.isNotEmpty(value)) {
ViewUtils.setVisible(description);
description.setText(value);
}
value = typedArray.getString(R.styleable.settings_custom_action);
if (StringUtils.isNotEmpty(value)) {
action = value;
}
value = typedArray.getString(R.styleable.settings_custom_actionParamTitle);
if (StringUtils.isNotEmpty(value)) {
actionParamTitle = value;
}
value = typedArray.getString(R.styleable.settings_custom_actionParamUrl);
if (StringUtils.isNotEmpty(value)) {
actionParamUrl = value;
}
int layout = typedArray.getResourceId(R.styleable.settings_custom_actionParamLayout, 0);
if (layout != 0) {
actionParamLayout = layout;
}
value = typedArray.getString(R.styleable.settings_custom_key);
if (StringUtils.isNotEmpty(value)) {
key = value;
}
value = typedArray.getString(R.styleable.settings_custom_settingKey);
if (StringUtils.isNotEmpty(value)) {
try {
setting = Settings.valueOf(value);
} catch (Exception ex) {
Dlog.notReached(ex);
}
}
if (action != null || setting != null) {
setOnClickListener(this);
} else {
setClickable(false);
}
if (context instanceof CommonSettingsHandler.Provider) {
((CommonSettingsHandler.Provider)context).getCommonSettingsHandler().onSettingsViewInflated(key, setting, this);
}
}
}
@Override
public void onClick(View v) {
if (getContext() instanceof CommonSettingsHandler.Provider) {
((CommonSettingsHandler.Provider)getContext()).getCommonSettingsHandler().onSettingsViewClicked(key, setting, this, action);
}
}
public void setValueText(String valueText) {
this.valueText.setText(valueText);
}
public String getValueText() {
return this.valueText.getText().toString();
}
public TextView getValueTextView() {
return this.valueText;
}
public void setChecked(boolean checked) {
checkBox.setChecked(checked);
}
public boolean isChecked() {
return checkBox.isChecked();
}
public CheckBox getCheckBoxView() {
return checkBox;
}
public ImageView getArrowIconView() {
return arrowIcon;
}
public TextView getDescriptionView() {
return description;
}
public String getActionParamTitle() {
return actionParamTitle;
}
public void setActionParamTitle(String actionParamTitle) {
this.actionParamTitle = actionParamTitle;
}
public String getActionParamUrl() {
return actionParamUrl;
}
public void setActionParamUrl(String actionParamUrl) {
this.actionParamUrl = actionParamUrl;
}
public int getActionParamLayout() {
return actionParamLayout;
}
public void setActionParamLayout(int actionParamLayout) {
this.actionParamLayout = actionParamLayout;
}
}