要做这样一种开关。

当开关在左边时,都是灰色的,向右滑动的时候,滑到一半的时候,改变颜色,变成绿色;

当开关在右边是,都市绿色的,向左滑动的时候,滑动一半的时候,改变颜色,变成灰色。

这里就要涉及要可滑动最大距离,以及你现在滑动的距离。通过这个来比较,改变颜色。

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;/*** 自定义开关按钮, *  **/
public class PushSlideSwitchView extends View{/** Switch底部灰色样式图片 */private Bitmap mSwitchBgUnseleted;/** Switch底部绿色样式图  */private Bitmap mSwitchBgSeleted;/** Switch灰色的球  */private Bitmap mSwitchBallUnseleted;/** Switch绿色的球  */private Bitmap mSwitchBallSeleted;private float mCurrentX = 0;/** Switch 开关状态,默认是  开:true  */private boolean mSwitchOn = true;/** Switch 最大移动距离   */private int mMoveLength;/** 第一次按下的有效区域 */private float mLastX = 0;/** 绘制的目标区域大小  */private Rect mDest = null; /** 截取源图片的大小  *//** Switch 移动的偏移量  */private int mMoveDeltX = 0;/** 画笔工具  */private Paint mPaint = null;/** Switch 状态监听接口  */private OnSwitchChangedListener switchListener = null;private boolean mFlag = false;/** enabled 属性 为 true */private boolean mEnabled = true;/** 最大透明度,就是不透明 */private final int MAX_ALPHA = 255;/** 当前透明度,这里主要用于如果控件的enable属性为false时候设置半透明 ,即不可以点击 */private int mAlpha = MAX_ALPHA;/** Switch 判断是否在拖动 */private boolean mIsScrolled =false;public PushSlideSwitchView(Context context) {this(context, null);}public PushSlideSwitchView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public PushSlideSwitchView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init();}/*** 初始化相关资源*/public void init() {mSwitchBgSeleted = BitmapFactory.decodeResource(getResources(),R.drawable.push_button_selected_bg);mSwitchBgUnseleted = BitmapFactory.decodeResource(getResources(),R.drawable.push_button_unselected_bg);mSwitchBallSeleted = BitmapFactory.decodeResource(getResources(),R.drawable.push_button_ball_selected);mSwitchBallUnseleted = BitmapFactory.decodeResource(getResources(),R.drawable.push_button_ball_unselected);mMoveLength = mSwitchBgSeleted.getWidth() - mSwitchBallSeleted.getWidth();//绘制区域大小mDest = new Rect(0, 0, mSwitchBgSeleted.getWidth(), mSwitchBgSeleted.getHeight());mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setAlpha(255);mPaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {setMeasuredDimension(mSwitchBgSeleted.getWidth(), mSwitchBgSeleted.getHeight());}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);/*System.out.println("---onDraw()---mMoveDeltX= " + mMoveDeltX +"  mSwitchBgUnseleted.getWidth()= " + mSwitchBgUnseleted.getWidth() +"  mSwitchBallSeleted.getWidth()= " + mSwitchBallSeleted.getWidth() +"  mMoveLength = " + mMoveLength);*/canvas.saveLayerAlpha(new RectF(mDest), mAlpha, Canvas.MATRIX_SAVE_FLAG| Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG| Canvas.FULL_COLOR_LAYER_SAVE_FLAG| Canvas.CLIP_TO_LAYER_SAVE_FLAG);//如果是关闭的if(!mSwitchOn){if(mMoveDeltX > 0){//向右滑动了if(mMoveDeltX < mMoveLength/2){//滑动距离小于一半canvas.drawBitmap(mSwitchBgUnseleted, 0, 0, null); //灰色背景canvas.drawBitmap(mSwitchBallUnseleted, mMoveDeltX, 0, null); //灰色按钮}else{//滑动距离大于一半canvas.drawBitmap(mSwitchBgSeleted, 0, 0, null); //绿色背景canvas.drawBitmap(mSwitchBallSeleted, mMoveDeltX, 0, null); //绿色按钮}}else{canvas.drawBitmap(mSwitchBgUnseleted, 0, 0, null); //灰色背景canvas.drawBitmap(mSwitchBallUnseleted, 0, 0, null); //灰色按钮}}else{if(mMoveDeltX < 0){//向右滑动了if(Math.abs(mMoveDeltX) < mMoveLength/2){//滑动距离小于一半canvas.drawBitmap(mSwitchBgSeleted, 0, 0, null); //绿色背景canvas.drawBitmap(mSwitchBallSeleted, mSwitchBgSeleted.getWidth() - mSwitchBallSeleted.getWidth() + mMoveDeltX, 0, null); //绿色按钮}else{//滑动距离大于一半canvas.drawBitmap(mSwitchBgUnseleted, 0, 0, null); //灰色背景canvas.drawBitmap(mSwitchBallUnseleted, mSwitchBgSeleted.getWidth() - mSwitchBallSeleted.getWidth() + mMoveDeltX, 0, null); //灰色按钮}}else{canvas.drawBitmap(mSwitchBgSeleted, 0, 0, null); //绿色背景canvas.drawBitmap(mSwitchBallSeleted, mMoveLength, 0, null); //绿色按钮}}canvas.restore();}@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stub//如果Enabled属性设定为true,触摸效果才有效if(!mEnabled){return true;}switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mLastX = event.getX();break;case MotionEvent.ACTION_MOVE:mCurrentX = event.getX();mMoveDeltX = (int) (mCurrentX - mLastX);//System.out.println("===============" + mMoveDeltX);if(mMoveDeltX > 3){//设置了3这个误差距离,可以更好的实现点击效果mIsScrolled = true;}// 如果开关开着向右滑动,或者开关关着向左滑动(这时候是不需要处理的)if ((mSwitchOn && mMoveDeltX > 0) || (!mSwitchOn && mMoveDeltX < 0)) {mFlag = true;mMoveDeltX = 0;}if (Math.abs(mMoveDeltX) > mMoveLength) {mMoveDeltX = mMoveDeltX > 0 ? mMoveLength : -mMoveLength;}invalidate();break;case MotionEvent.ACTION_UP://如果没有滑动过,就看作一次点击事件if(!mIsScrolled){mMoveDeltX = mSwitchOn ? mMoveLength : -mMoveLength;mSwitchOn = !mSwitchOn;if (switchListener != null) {switchListener.onSwitchChange(this, mSwitchOn);}invalidate();mMoveDeltX = 0;break;}mIsScrolled = false;if (Math.abs(mMoveDeltX) > 0 && Math.abs(mMoveDeltX) < mMoveLength / 2) {mMoveDeltX = 0;invalidate();} else if (Math.abs(mMoveDeltX) > mMoveLength / 2&& Math.abs(mMoveDeltX) <= mMoveLength) {mMoveDeltX = mMoveDeltX > 0 ? mMoveLength : -mMoveLength;mSwitchOn = !mSwitchOn;if (switchListener != null) {switchListener.onSwitchChange(this, mSwitchOn);}invalidate();mMoveDeltX = 0;} else if (mMoveDeltX == 0 && mFlag) {// 这时候得到的是不需要进行处理的,因为已经move过了mMoveDeltX = 0;mFlag = false;}default:break;}invalidate();return true;}/** * 设置 switch 状态监听 * */public void setOnChangeListener(OnSwitchChangedListener listener) {switchListener = listener;}/** * switch 开关监听接口*  */public interface OnSwitchChangedListener{public void onSwitchChange(PushSlideSwitchView switchView, boolean isChecked);}@Overridepublic void setEnabled(boolean enabled) {// TODO Auto-generated method stubmEnabled = enabled;mAlpha = enabled ? MAX_ALPHA : MAX_ALPHA/2;Log.d("enabled",enabled ? "true": "false");super.setEnabled(enabled);invalidate();}/** 自动判断切换至相反的属性 : true -->false ;false -->true */public void toggle() {setChecked(!mSwitchOn);}/** 设置选中的状态(选中:true   非选中: false) */public void setChecked(boolean checked) {mSwitchOn = checked;invalidate();}
}

就是这样一个类,就可以了。

在xml文件中可以这样引用:

<com.app.view.PushSlideSwitchViewandroid:id="@+id/push_set_warm_switchview"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:layout_marginRight="15dip"android:enabled="true" />

在这里附上需要引用的四张图片

    

在java代码中我们通过设置switchView.setOnChangeListener()来监听是否打开和关闭。

如果是单个的使用,使用上面的完全没有问题。

但是这里还涉及到一个问题,如果是listview,假如每个item里面都有一个这样的开关,在应用权限设置里面可能会看到这样的操作场景。

以前用其他的自定义滑动开关会发现,如果上下滑动几次,就会乱套,左边的会跳到右边,有的右边会跳到左边。这个也解决了这个问题。

java代码如下

package com.example.compoundbuttonview;import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;import com.example.compoundbuttonview.view.MySlideSwitchView;
import com.example.compoundbuttonview.view.MySlideSwitchView.OnSwitchChangedListener;
/***/
public class MainActivity2 extends Activity {private ListView listview;List<Map<String, Object>> tempListData = new ArrayList<Map<String, Object>>();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main2);initView();for (int i = 0; i < 50; i++) {HashMap datamap = new HashMap<String, Object>();datamap.put("index", i+1);datamap.put("checked", i%2==0?true:false);tempListData.add(datamap);}MyAdapter adapter = new MyAdapter(MainActivity2.this);listview.setAdapter(adapter);}private void initView() {listview = (ListView) findViewById(R.id.listView1);}class MyAdapter extends BaseAdapter {private LayoutInflater inflater = null;private Context context;public MyAdapter(Context context) {this.context = context;inflater = LayoutInflater.from(context);}@Overridepublic int getCount() {return tempListData.size();}@Overridepublic Object getItem(int position) {return tempListData.get(position);}@Overridepublic long getItemId(int position) {return position;}public void modifyStates(int position) {}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {ViewHolder holder;if (convertView == null) {convertView = inflater.inflate(R.layout.main2_listview_item, null);holder = new ViewHolder();holder.index = (TextView) convertView.findViewById(R.id.item_index);holder.SlideSwitchView = (MySlideSwitchView) convertView.findViewById(R.id.item_SwitchView);// 使用tag来存储数据convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}holder.index.setText(tempListData.get(position).get("index") + "");holder.SlideSwitchView.setChecked((Boolean) tempListData.get(position).get("checked"));holder.SlideSwitchView.setOnChangeListener(new OnSwitchChangedListener() {@Overridepublic void onSwitchChange(MySlideSwitchView switchView, boolean isChecked) {tempListData.get(position).put("checked", isChecked);}});return convertView;}}class ViewHolder {public MySlideSwitchView SlideSwitchView;public TextView index;}}

xml布局文件如下:

main2.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:android1="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="1dip" ><ListViewandroid1:id="@+id/listView1"android1:layout_width="match_parent"android1:layout_height="wrap_content" ></ListView></LinearLayout>

item.xml

<pre name="code" class="html"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:android1="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="60dip"android:gravity="center_vertical"android:orientation="horizontal"android:padding="1dip" ><TextViewandroid:id="@+id/item_index"android:layout_width="0dip"android:layout_height="60dip"android:layout_weight="1"android:layout_marginLeft="15dip"android:gravity="center_vertical"android:singleLine="true"android:text="1"android:textColor="#555"android:textSize="16sp" /><com.example.compoundbuttonview.view.MySlideSwitchViewandroid:id="@+id/item_SwitchView"android:layout_width="wrap_content"android:layout_height="60dip"android:layout_marginRight="15dip"android:layout_gravity="center"android:enabled="true" /></LinearLayout> 

好了,由于代码全部贴出来了。就没有做成资源去下载,代码有注释,看一下就懂,其实很好用。

Android自定义view 滑动开关 支持左右滑动 适用于listview相关推荐

  1. Android自定义View,跟随手指滑动效果

    Android自定义View,实现跟随手指滑动效果, 效果如下: 一,重写onTouchEvent方法 最后返回true 二,在MotionEvent.ACTION_MOVE情况下改变自定义view ...

  2. Android 自定义View实现圆形头像(适用于任意布局)

    先看效果图: 先来说下我的思路:首先我需要在自定义View中动态获取头像id,那么就需要在attrs文件中,写一个关于该View类的自定义属性.这里仿照ImageView,取名为src,类型为refe ...

  3. Android自定义View(二)---拉刷新ListView 下之事件分发源码解析

    贴出来自定下拉刷新的源码,其主要部分已经贴出来了,欢迎拍砖. git@git.oschina.net:gezihua/supro.git package com.example.gezihua.mya ...

  4. android 自定义view滚动条,Android自定义View实现等级滑动条的实例

    Android自定义View实现等级滑动条的实例 实现效果图: 思路: 首先绘制直线,然后等分直线绘制点: 绘制点的时候把X值存到集合中. 然后绘制背景图片,以及图片上的数字. 点击事件down的时候 ...

  5. android 高仿 探探卡片滑动,Android自定义View仿探探卡片滑动效果

    Android自定义View仿探探卡片滑动这种效果网上有很多人已经讲解了实现思路,大多都用的是RecyclerView来实现的,但是我们今天来换一种实现思路,只用一个自定义的ViewGroup来搞定这 ...

  6. Android 自定义View(四)实现股票自选列表滑动效果

    一.前言 Android 开发过程中自定义 View 真的是无处不在,随随便便一个 UI 效果,都会用到自定义 View.前面三篇文章已经讲过自定义 View 的一些案例效果,相关类和 API,还有事 ...

  7. Android 自定义View合集

    http://blog.csdn.net/u011507982/article/details/51199644 自定义控件学习  https://github.com/GcsSloop/Androi ...

  8. android 车辆轨迹,Android自定义view实现车载可调整轨迹线

    本文实例为大家分享了Android自定义view完成车载可调整轨迹线的具体代码,供大家参考,具体内容如下 同事做的view,拿过来做个记录. /** * */ package com.text.myv ...

  9. android 屏幕坐标色彩,Android自定义View实现颜色选取器

    Android 自定义View 颜色选取器,可以实现水平.竖直选择颜色类似 SeekBar 的方式通过滑动选择颜色. 效果图 xml 属性 1.indicatorColor 指示点颜色 2.indic ...

最新文章

  1. 难忘的一天——装操作系统(四)
  2. 计算机应用基础第九章在线测试答案,郑大计算机应用基础第9章节在线测试答案...
  3. CRM WebClient UI的浏览器打印实现
  4. 举报入口_违法和不良信息举报中心
  5. realme曝光全球首张6400万像素样张 大家品一品?
  6. 讲道理,我觉得TensorFlow太逊了
  7. 北京大学 | 软件工程理论与实践
  8. springboot电子阅览室app毕业设计源码016514
  9. html img标签的alt属性和title属性(说明)
  10. 频响测试软件的使用教程,频谱分析仪的使用方法与技巧
  11. 一个月攻克托业--复旦大学考生
  12. 漏洞复现篇——ewebeditor编辑器解析漏洞
  13. 为什么python代码运行不了_Python | 为什么优化代码?
  14. 台式电脑卸载了wifi精灵之后能够联网但是无法上网
  15. win10 安装oracle11g完整教程
  16. Pubmed数据库改版后如何做计量分析与知识图谱
  17. 如何设置Raspberry Pi Zero进行旅行
  18. Android系统的定制
  19. packet tracer 用命令配置路由器
  20. 选择排序——C语言代码

热门文章

  1. 申请注册GMAIL的免费企业邮箱
  2. [转帖]一个老程序员的心理话(三)
  3. 移动端浏览器有哪些,内核分别是什么
  4. 005. 组合总和 II
  5. 「纯前端容器」打造无缝平滑的用户体验
  6. chroma负载机恒压工作原理_一款恒压/恒流充电器工作原理分析
  7. Unity打开Windows虚拟键盘
  8. c语言选择结构作用,c语言选择结构程序设计教案
  9. Hive玩得好,头发就变少
  10. cdr怎么把矩形去掉一个边_cdr画矩形怎么把中间弄掉