Android開(kāi)發(fā)進(jìn)階自定義控件之滑動(dòng)開(kāi)關(guān)實(shí)現(xiàn)方法【附demo源碼下載】
本文實(shí)例講述了Android開(kāi)發(fā)進(jìn)階自定義控件之滑動(dòng)開(kāi)關(guān)實(shí)現(xiàn)方法。分享給大家供大家參考,具體如下:
自定義開(kāi)關(guān)控件

Android自定義控件一般有三種方式
1、繼承Android固有的控件,在Android原生控件的基礎(chǔ)上,進(jìn)行添加功能和邏輯。
2、繼承ViewGroup,這類(lèi)自定義控件是可以往自己的布局里面添加其他的子控件的。
3、繼承View,這類(lèi)自定義控件沒(méi)有跟原生的控件有太多的相似的地方,也不需要在自己的肚子里添加其他的子控件。
ToggleView自定義開(kāi)關(guān)控件表征上沒(méi)有跟Android原生的控件有什么相似的地方,而且在滑動(dòng)的效果上也沒(méi)有沿襲Android原生的地方,所以我們的自定義ToggleView選擇繼承View
同樣的自定義控件需要復(fù)寫(xiě)三個(gè)構(gòu)造方法
//在布局中使用該控件的時(shí)候,而且有額外的style屬性的時(shí)候調(diào)用該構(gòu)造方法, public ToggleView(Context context, AttributeSet attrs, int defStyle); //在布局中使用該控件的時(shí)候調(diào)用該構(gòu)造方法 public ToggleView(Context context, AttributeSet attrs) //在Java代碼中直接new該控件的時(shí)候,調(diào)用該構(gòu)造方法 public ToggleView(Context context)
因?yàn)槭亲远x的控件,所以屬性還是自己定義的比較好用一些。我們這里定義三個(gè)屬性
1、背景圖片
2、滑塊的圖片
3、布局中默認(rèn)的開(kāi)關(guān)的狀態(tài)
所以就需要用到了自定義屬性
在values目錄下,新建xml文件,attrs.xml
在里面定義自己的屬性
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="toggle"> <attr name="switchBackground" format="reference" /> <attr name="slidingBackground" format="reference" /> <attr name="toggleState" format="boolean" /> </declare-styleable> </resources>
<declare-styleable name屬性>是可以在R文件中找到該屬性名稱(chēng)的
<attr>標(biāo)簽中,一個(gè)標(biāo)簽寫(xiě)一個(gè)屬性 name屬性表示屬性名稱(chēng),format表示屬性類(lèi)型
這里定義了三個(gè)屬性名和屬性類(lèi)型。
屬性和自定義控件的三個(gè)構(gòu)造方法已經(jīng)完成,就我們就可以在布局文件中添加自定義的控件了
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:hss="http://schemas.android.com/apk/res/com.hss.toggle" android:layout_width="match_parent" android:layout_height="match_parent" > <com.hss.toggle.ToggleView android:id="@+id/toggleView" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_centerInParent="true" hss:switchBackground="@drawable/switch_background" hss:slidingBackground="@drawable/slide_button_background" hss:toggleState="true" > </com.hss.toggle.ToggleView> </RelativeLayout>
注意:在我自定義控件com.hss.toggle.ToggleView中,部分屬性是以android開(kāi)頭的,部分屬性是以hss(我自己定義的命名空間)開(kāi)頭的,這是為什么呢?
注意看本片代碼第二行,
xmlns:hss="http://schemas.android.com/apk/res/com.hss.toggle"
我在這里寫(xiě)著樣一行代碼,就說(shuō)明把values/attrs.xml中的每個(gè)條目都導(dǎo)入進(jìn)來(lái)了,就可以直接使用我在attrs.xml里面的屬性了
可以直接使用自定義的屬性之后,問(wèn)題應(yīng)該聚焦到怎么在Java代碼中獲取到我自定義的屬性的值呢?
根據(jù)命名空間和自定義屬性的name值獲取,看代碼:
String namespace = "http://schemas.android.com/apk/res/com.hss.toggle"; int toggle_switchbackground = attrs.getAttributeResourceValue(namespace, "switchBackground", -1); int toggle_slidingbackground = attrs.getAttributeResourceValue(namespace, "slidingBackground", -1); toggle_state = attrs.getAttributeBooleanValue(namespace, "toggleState", false);
看到?jīng)]?該方法用到了attr參數(shù),所以獲取自定義屬性值的操作應(yīng)該在兩個(gè)參數(shù)的那里面執(zhí)行。
整體的自定義控件的類(lèi)見(jiàn)代碼:
package com.hss.toggle;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
* 自定義開(kāi)關(guān)控件
* @author hss
*/
public class ToggleView extends View {
private static final String TAG = "ToogleView";
private Bitmap sliding_background;
private Bitmap switch_background;
private boolean isSliding = false;
private boolean toggle_state = false;
private int downX;
private mToggleStateChangeListener;
// 構(gòu)造方法,在xml文件布局的時(shí)候,指定了style的時(shí)候調(diào)用
public ToggleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
// 構(gòu)造方法,在xml文件中布局的時(shí)候,沒(méi)有指定style的時(shí)候調(diào)用
public ToggleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
//在Java代碼中 獲取到xml中自定義屬性對(duì)應(yīng)的值
String namespace = "http://schemas.android.com/apk/res/com.hss.toggle";
int toggle_switchbackground = attrs.getAttributeResourceValue(namespace, "switchBackground", -1);
int toggle_slidingbackground = attrs.getAttributeResourceValue(namespace, "slidingBackground", -1);
toggle_state = attrs.getAttributeBooleanValue(namespace, "toggleState", false);
Log.i(TAG,""+toggle_slidingbackground+" "+toggle_switchbackground);
// 設(shè)置自定義開(kāi)關(guān)的圖片
setToggleSwitchBackground(toggle_switchbackground);
setToggleSlidingBackground(toggle_slidingbackground);
setToggleState(toggle_state);
}
// 構(gòu)造方法 在代碼中new的時(shí)候調(diào)用
public ToggleView(Context context) {
this(context, null);
}
/**
* 給滑動(dòng)的控件設(shè)置背景圖片
*
* @param toggle_slidingbackground 圖片ID
*/
private void setToggleSlidingBackground(int toggle_slidingbackground) {
sliding_background = BitmapFactory.decodeResource(getResources(),toggle_slidingbackground);
}
/**
* 給背景的控件,設(shè)置背景圖片
*
* @param toggle_switchbackground 圖片ID
*/
private void setToggleSwitchBackground(int toggle_switchbackground) {
switch_background = BitmapFactory.decodeResource(getResources(),toggle_switchbackground);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//測(cè)量控件的大小,設(shè)置控件的大小為背景圖片的大小
setMeasuredDimension(switch_background.getWidth(),switch_background.getHeight());
}
@Override
protected void onDraw(Canvas canvas) {
//開(kāi)始畫(huà)自定義控件,使用canvas對(duì)象先把背景圖片畫(huà)上來(lái)
canvas.drawBitmap(switch_background, 0, 0, null);
if (isSliding) {
//如果是滑動(dòng)狀態(tài)
//控件距離左邊的相對(duì)距離為:(控件每時(shí)每刻的距離自己左上方的焦點(diǎn)的x軸距離)-(控件本身一半的x軸寬度)
int left = downX - sliding_background.getWidth() / 2;
//控件最大的滑動(dòng)距離(距離左邊最大的距離)就是:(背景圖片的寬度)-(滑塊圖片的寬度)
int rightAlign = switch_background.getWidth()- sliding_background.getWidth();
//如果距離左邊的距離小于0,,就不讓他繼續(xù)往左邊動(dòng)了
if (left < 0) {
left = 0;
} else if (left > rightAlign) {
//如果距離左邊的距離》應(yīng)該距離左邊的最大距離,也不讓他往右邊移動(dòng)了
left = rightAlign;
}
//控制好屬性之后就可以時(shí)時(shí)刻刻的跟著畫(huà)了
canvas.drawBitmap(sliding_background, left, 0, null);
} else {
//如果不滑動(dòng),則根據(jù)控件的屬性中開(kāi)關(guān)的狀態(tài),來(lái)畫(huà)滑塊的位置
if (toggle_state) {
//如果開(kāi)關(guān)狀態(tài)為真,滑塊移動(dòng)到最右邊
int left = switch_background.getWidth() - sliding_background.getWidth();
canvas.drawBitmap(sliding_background, left, 0, null);
} else {
//如果開(kāi)關(guān)狀態(tài)為假,滑塊移動(dòng)到最左邊
canvas.drawBitmap(sliding_background, 0, 0, null);
}
}
super.onDraw(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//重寫(xiě)觸摸事件
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
//開(kāi)始點(diǎn)擊的時(shí)候,是否滑動(dòng)置為真,獲取到當(dāng)前手指的距離
isSliding = true;
downX = (int) event.getX();
break;
case MotionEvent.ACTION_MOVE:
downX = (int) event.getX();
break;
case MotionEvent.ACTION_UP:
//當(dāng)點(diǎn)擊結(jié)束的時(shí)候?qū)⑹欠窕瑒?dòng)記為假,獲取到移動(dòng)的x軸的坐標(biāo)
downX = (int) event.getX();
isSliding = false;
//獲取到背景圖片中間的那個(gè)值
int center = switch_background.getWidth() / 2;
boolean state = downX > center;
//如果先后的狀態(tài)不相同,則將新的狀態(tài)賦給成員變量,然后調(diào)用監(jiān)聽(tīng)的方法
if (toggle_state != state) {
toggle_state = state;
if (null != mToggleStateChangeListener) {
mToggleStateChangeListener
.onToggleState(toggle_state);
}
}
break;
}
//調(diào)用一次onDraw()方法
invalidate();
return true;
}
//給自定義開(kāi)關(guān)控件設(shè)置監(jiān)聽(tīng)的方法
public void setOnToggleStateLinstener(OnToggleStateChangeListener listen){
mToggleStateChangeListener = listen;
}
public void setToggleState(boolean b) {
toggle_state = b;
}
//監(jiān)聽(tīng)回調(diào)接口,方法由實(shí)現(xiàn)接口的類(lèi)實(shí)現(xiàn)
public interface OnToggleStateChangeListener {
public void onToggleState(boolean state);
}
}
到此,我們的自定義控件部分的邏輯就寫(xiě)完了,,借下來(lái)再M(fèi)ainActivity中調(diào)用一下
package com.hss.toggle;
import android.app.Activity;
import android.os.Bundle;
import com.hss.toggle.ToggleView.OnToggleStateChangeListener;
import com.hss.toggle.utils.ToastUtil;
public class MainActivity extends Activity{
private ToggleView toggleView;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toggleView = (ToggleView) findViewById(R.id.toggleView);
toggleView.setOnToggleStateLinstener(new OnToggleStateChangeListener() {
@Override
public void onToggleState(boolean state) {
showToast(state);
}
});
}
//這里調(diào)用到的自己封裝的一個(gè)快速?gòu)桾oast的工具類(lèi)
private void showToast(boolean state) {
ToastUtil.makeSuddenlyToast(getApplicationContext(), state?"開(kāi)":"關(guān)");
}
}
ToastUtil類(lèi)如下:
package com.hss.toggle.utils;
import android.content.Context;
import android.widget.Toast;
/**
* @title Toast工具類(lèi)
* @author hss
*/
public class ToastUtil {
private static Toast toast;
/**
* 彈出短時(shí)間Toast
* @param context 上下文對(duì)象
* @param text 要彈出的文字
*/
public static void makeShortToast(Context context,String text){
toast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
toast.show();
}
/**
* 彈出長(zhǎng)時(shí)間的Toast
* @param context 上下文對(duì)象
* @param text 要彈出的文字
*/
public static void makeLongToast(Context context,String text){
toast = Toast.makeText(context, text, Toast.LENGTH_LONG);
toast.show();
}
/**
* 單例Toast
* @param context 上下文對(duì)象
* @param text 要彈出的文字
*/
public static void makeSuddenlyToast(Context context,String text){
if(toast==null){
toast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
}
toast.setText(text);
toast.show();
}
}
總結(jié)一下,其實(shí)本次自定義控件的步驟如下:
1、在values/attrs.xml自定義屬性和屬性值的數(shù)據(jù)類(lèi)型
2、在Java代碼中定義自定義控件類(lèi),繼承View或者ViewGroup或者Android原生的控件,實(shí)現(xiàn)構(gòu)造方法,獲取到自定義屬性的值,并且編寫(xiě)對(duì)應(yīng)的邏輯和點(diǎn)擊事件。
3、在布局文件中使用自定義控件和自定義屬性(注意命名空間)。
4、在MainActivity中調(diào)用
完整實(shí)例代碼點(diǎn)擊此處本站下載。
更多關(guān)于Android相關(guān)內(nèi)容感興趣的讀者可查看本站專(zhuān)題:《Android控件用法總結(jié)》、《Android視圖View技巧總結(jié)》、《Android操作SQLite數(shù)據(jù)庫(kù)技巧總結(jié)》、《Android操作json格式數(shù)據(jù)技巧總結(jié)》、《Android數(shù)據(jù)庫(kù)操作技巧總結(jié)》、《Android文件操作技巧匯總》、《Android編程開(kāi)發(fā)之SD卡操作方法匯總》、《Android開(kāi)發(fā)入門(mén)與進(jìn)階教程》及《Android資源操作技巧匯總》
希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。
相關(guān)文章
Android 自定義view模板并實(shí)現(xiàn)點(diǎn)擊事件的回調(diào)
這篇文章主要介紹了Android 自定義view模板并實(shí)現(xiàn)點(diǎn)擊事件的回調(diào)的相關(guān)資料,需要的朋友可以參考下2017-01-01
Android AS為xutils添加依賴(lài)過(guò)程圖解
這篇文章主要介紹了Android AS為xutils添加依賴(lài)過(guò)程圖解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
android dialog邊框去除白色邊框?qū)崿F(xiàn)思路及代碼
android dialog邊框含有白色真是美中不足啊,本文將介紹如何去除白色邊框,有思路及代碼,感興趣的朋友可以了解下2013-01-01
Android RadioButton 圖片位置與大小實(shí)例詳解
這篇文章主要介紹了Android RadioButton 圖片位置與大小實(shí)例詳解的相關(guān)資料,這里提供實(shí)例代碼及實(shí)現(xiàn)效果圖,需要的朋友可以參考下2016-11-11
Android自定義照相機(jī)Camera出現(xiàn)黑屏的解決方法
這篇文章主要介紹了Android自定義照相機(jī)Camera出現(xiàn)黑屏的解決方法,分析了黑屏出現(xiàn)的原因及參考解決方法,需要的朋友可以參考下2016-08-08
Android仿美團(tuán)淘寶實(shí)現(xiàn)多級(jí)下拉列表菜單功能
這篇文章主要介紹了Android仿美團(tuán)淘寶實(shí)現(xiàn)多級(jí)下拉列表菜單功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下2017-01-01
Android中EditText和AutoCompleteTextView設(shè)置文字選中顏色方法
這篇文章主要介紹了Android中EditText和AutoCompleteTextView設(shè)置文字選中顏色方法,本文給出了效果圖和實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-01-01
Android ListView的item背景色設(shè)置和item點(diǎn)擊無(wú)響應(yīng)的解決方法
在Android開(kāi)發(fā)中,listview控件是非常常用的控件,在大多數(shù)情況下,大家都會(huì)改掉listview的item默認(rèn)的外觀。2013-11-11

