Рассмотрим создания пользовательских компонентов в 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