Довільний перемикач (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

Напишіть перше повідомлення!

Ви повинні увійти під своїм аккаунтом щоб залишати коментарі