Пользовательский переключатель (Toggle) в Android

апреля
09
2012
Метки: android custom view toggle

Рассмотрим создания пользовательских компонентов в Android на примере переключателя (Toggle). В приведенном примере будет представлено два типа переключателя: с двумя и с тремя состояниями.

Ниже представлен результат выполнения программы.

Рис 1. Пользовательский переключатель (Toggle) в Android
Рис 1. Пользовательский переключатель (Toggle) в Android

Приступим к созданию пользовательского компонента. Рассмотрим создание только переключателя на два состояния, со вторым типом переключателя не составит труда разобраться, используя исходный текст программы. Для начала создадим разметку будущего элемента:

toggle.xml

<?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:

colors.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>

strings.xml

<?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>

Класс пользовательского компонента:

Toggle.java

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:

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"

Теперь можно использовать эти свойства. Ниже рабочий пример:

main.xml

<?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

Напишите первое сообщение!

Вы должны войти под своим аккаунтом чтобы оставлять комментарии