Розглянемо створення довільних компонентів в Android на прикладі перемикача (Toggle). У наведеному прикладі буде представлено два типи перемикача: з двома та з трьома станами.
Нижче представлений результат виконання програми.
Рис 1. Довільний перемикач (Toggle) в Android
Приступимо до створення довільного компонента. Розглянемо створення тільки перемикача на два стани, з другим типом перемикача не важко розібратися, використовуючи вихідний текст програми. Для початку створимо розмітку майбутнього елементу:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:gravity="center"
android:orientation="horizontal"
android:padding="0dip"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="@+id/left_label"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center"
android:layout_gravity="center"
android:text="@string/on"
android:textColor="@color/active_toggle_color" />
<TextView
android:id="@+id/right_label"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:gravity="center"
android:layout_gravity="center"
android:text="@string/off"
android:textColor="@color/non_active_toggle_color" />
</LinearLayout>
У розмітці використовуються тільки стандартні елементи, тому принцип їх побудови обговорюватися не буде. Замість цього наведемо необхідні файли colors.xml і strings.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="active_toggle_color">#FFFFFF</color>
<color name="non_active_toggle_color">#CCCCCC</color>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, ToggleViewActivity!</string>
<string name="app_name">ToggleView</string>
<string name="left">left</string>
<string name="center">center</string>
<string name="right">right</string>
<string name="on">On</string>
<string name="off">Off</string>
</resources>
Клас компонента користувача:
package com.seostella.toggleview.view;
import com.seostella.toggleview.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class Toggle extends RelativeLayout {
protected String leftText;
protected String rightText;
protected TextView leftTextView;
protected TextView rightTextView;
protected int activeColor;
protected int nonActiveColor;
protected int leftDrawable;
protected int rightDrawable;
protected Context context;
protected AttributeSet attrs;
protected OnStateChangeListener onStateChangeListener;
protected boolean leftOptionSelected = false;
public Toggle(Context context) {
super(context);
}
public Toggle(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
this.attrs = attrs;
init(context, attrs);
}
public Toggle(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
this.attrs = attrs;
init(context, attrs);
}
public void setOnStateChangeListener(
OnStateChangeListener onStateChangeListener) {
this.onStateChangeListener = onStateChangeListener;
}
public void setLeftText(String leftText) {
this.leftText = leftText;
if (leftTextView != null) {
leftTextView.setText(this.leftText);
}
}
public void setRightText(String rightText) {
this.rightText = rightText;
if (rightTextView != null) {
this.rightTextView.setText(rightText);
}
}
public void setActiveColor(int color) {
this.activeColor = color;
}
public void setNonActiveColor(int color) {
this.nonActiveColor = color;
}
public void setLeftDrawable(int drawable) {
this.leftDrawable = drawable;
}
public void setRightDrawable(int drawable) {
this.rightDrawable = drawable;
}
protected void init(Context context, AttributeSet attrs) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (inflater != null) {
inflater.inflate(getView(), this);
}
final TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.Toggle);
leftText = a.getString(R.styleable.Toggle_leftText);
rightText = a.getString(R.styleable.Toggle_rightText);
activeColor = getContext().getResources().getColor(
R.color.active_toggle_color);
nonActiveColor = getContext().getResources().getColor(
R.color.non_active_toggle_color);
setLeftDrawable(R.drawable.toggle_left);
setRightDrawable(R.drawable.toggle_right);
}
protected int getView() {
return R.layout.toggle;
}
protected void initTextViews() {
leftTextView = (TextView) this.findViewById(R.id.left_label);
leftTextView.setText(leftText);
leftTextView.setOnClickListener(leftTextOnClickListener);
rightTextView = (TextView) this.findViewById(R.id.right_label);
rightTextView.setText(rightText);
rightTextView.setOnClickListener(rightTextOnClickListener);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
initTextViews();
selectLeft();
}
private OnClickListener leftTextOnClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
selectLeft();
}
};
private OnClickListener rightTextOnClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
selectRight();
}
};
protected void selectLeft() {
if (!leftOptionSelected) {
this.setBackgroundResource(leftDrawable);
leftTextView.setTextColor(activeColor);
rightTextView.setTextColor(nonActiveColor);
leftOptionSelected = true;
if (onStateChangeListener != null) {
onStateChangeListener.stateChanged();
}
}
}
protected void selectRight() {
if (leftOptionSelected) {
this.setBackgroundResource(rightDrawable);
leftTextView.setTextColor(nonActiveColor);
rightTextView.setTextColor(activeColor);
leftOptionSelected = false;
if (onStateChangeListener != null) {
onStateChangeListener.stateChanged();
}
}
}
public void setLeftOptionSelected(boolean selected) {
if (selected) {
selectLeft();
} else {
selectRight();
}
}
public boolean isLeftOptionSelected() {
return leftOptionSelected;
}
public interface OnStateChangeListener {
public void stateChanged();
}
}
Всі ключові моменти реалізації перемикача зосереджені в методі init(). Також, використовуючи цей метод, Ви можете модифікувати вигляд перемикача для своїх потреб.
protected void init(Context context, AttributeSet attrs) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (inflater != null) {
inflater.inflate(getView(), this);
}
final TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.Toggle);
leftText = a.getString(R.styleable.Toggle_leftText);
rightText = a.getString(R.styleable.Toggle_rightText);
activeColor = getContext().getResources().getColor(
R.color.active_toggle_color);
nonActiveColor = getContext().getResources().getColor(
R.color.non_active_toggle_color);
setLeftDrawable(R.drawable.toggle_left);
setRightDrawable(R.drawable.toggle_right);
}
Рядками
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
if (inflater != null) {
inflater.inflate(getView(), this);
}
пов'язуємо клас Toggle з розміткою toggle.xml (метод getView() повертає R.layout.toggle)
Для текстових елементів лівого і правого станів перемикача використовуються відповідні значення атрибутів leftText і rightText (про їх створення піде мова нижче):
final TypedArray a = getContext().obtainStyledAttributes(attrs,
R.styleable.Toggle);
leftText = a.getString(R.styleable.Toggle_leftText);
rightText = a.getString(R.styleable.Toggle_rightText);
Значення кольору і зображення-фон береться із системних властивостей, хоча могли б також заповнюватися з використанням атрибутів розмітки:
activeColor = getContext().getResources().getColor(
R.color.active_toggle_color);
nonActiveColor = getContext().getResources().getColor(
R.color.non_active_toggle_color);
setLeftDrawable(R.drawable.toggle_left);
setRightDrawable(R.drawable.toggle_right);
Повернемося до призначених для користувача атрибутам leftText і rightText. Щоб використовувати їх в розмітці, необхідно їх додати в файл властивостей attr.xml:
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<declare-styleable name="Toggle">
<attr name="leftText" format="string" />
<attr name="rightText" format="string" />
<attr name="centerText" format="string" />
</declare-styleable>
</resources>
а в розмітці додати схему:
xmlns:custom="http://schemas.android.com/apk/res/com.seostella.toggleview"
Тепер можна використовувати ці властивості. Нижче робочий приклад:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.seostella.toggleview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello" />
<com.seostella.toggleview.view.Toggle
android:id="@+id/on_off_toggle_view"
custom:leftText="@string/on"
custom:rightText="@string/off"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="20dp"
android:gravity="center_horizontal" />
<com.seostella.toggleview.view.ToggleThree
android:id="@+id/toggle3_view"
custom:leftText="@string/left"
custom:centerText="@string/center"
custom:rightText="@string/right"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="20dp"
android:gravity="center_horizontal" />
</LinearLayout>
Щоб визначити, який перемикач активний, використовуйте метод isLeftOptionSelected(), який повертає true якщо перемикач в лівому положенні і false - якщо в правому. Також Ви можете додати слухач OnStateChangeListener, який буде миттєво повідомляти про зміну стану перемикача:
Toggle toggle = (Toggle)findViewById( R.id.on_off_toggle_view );
toggle.setOnStateChangeListener( new OnStateChangeListener() {
@Override
public void stateChanged() {
Log.d(TAG, "stateChanged");
}
});
Завантажити вихідний текст програми можна за наступним посиланням - ToggleView