zoukankan      html  css  js  c++  java
  • 可滑动的ToggleButton(开关)

    2013-12-28 17:25:01

    网上看到一篇关于可滑动的ToogleButton的文章,有代码,觉得挺好,但是不符合我的要求,因此在他的代码基础上改了一些。(作者看到了勿喷啊,实在找不到原文了,只好把代码下载地址贴出来。)

    源码下载地址: http://download.csdn.net/detail/zshq280017423/4240703

    先来两张效果图:

    然后上代码:

    最主要的类是SlipButton.java

      1 package com.util;
      2 
      3 import android.content.Context;
      4 import android.graphics.Bitmap;
      5 import android.graphics.BitmapFactory;
      6 import android.graphics.Canvas;
      7 import android.graphics.Matrix;
      8 import android.graphics.Paint;
      9 import android.util.AttributeSet;
     10 import android.util.Log;
     11 import android.view.MotionEvent;
     12 import android.view.View;
     13 import android.view.View.OnTouchListener;
     14 
     15 import com.view.SlipButton.R;
     16 
     17 public class SlipButton extends View implements OnTouchListener {
     18 
     19     private float DownX, NowX;// 按下时的x,当前的x
     20     private float btn_on_left = 0;
     21     private float btn_off_left = 0;
     22 
     23     private boolean NowChoose = false;// 记录当前按钮是否打开,true为打开,flase为关闭
     24     private boolean isChecked;
     25     private boolean OnSlip = false;// 记录用户是否在滑动的变量
     26     private boolean isChgLsnOn = false;
     27 
     28     private OnChangedListener ChgLsn;
     29     private Bitmap bg_on;
     30     private Bitmap bg_off;
     31     private Bitmap slip_btn;
     32 
     33     public SlipButton(Context context) {
     34         super(context);
     35         init();
     36     }
     37 
     38     public SlipButton(Context context, AttributeSet attrs) {
     39         super(context, attrs);
     40         init();
     41     }
     42 
     43     private void init() { // 初始化
     44         bg_on = BitmapFactory.decodeResource(getResources(),
     45                 R.drawable.split_left_1);
     46         bg_off = BitmapFactory.decodeResource(getResources(),
     47                 R.drawable.split_right_1);
     48         slip_btn = BitmapFactory.decodeResource(getResources(),
     49                 R.drawable.split_1);
     50 
     51         btn_off_left = bg_off.getWidth() - slip_btn.getWidth();
     52 
     53         setOnTouchListener(this); // 设置监听器,也可以直接复写OnTouchEvent
     54     }
     55 
     56     @Override
     57     protected void onDraw(Canvas canvas) {// 绘图函数
     58         super.onDraw(canvas);
     59 
     60         Matrix matrix = new Matrix();
     61         Paint paint = new Paint();
     62         float x;
     63 
     64         if (NowX < (bg_on.getWidth() / 2)) { // 滑动到前半段与后半段的背景不同,在此做判断
     65             x = NowX - slip_btn.getWidth() / 2;
     66             canvas.drawBitmap(bg_off, matrix, paint);// 画出关闭时的背景
     67         } else {
     68             x = bg_on.getWidth() - slip_btn.getWidth() / 2;
     69             canvas.drawBitmap(bg_on, matrix, paint);// 画出打开时的背景
     70         }
     71 
     72         if (OnSlip) {// 是否是在滑动状态,
     73             if (NowX >= bg_on.getWidth()) {// 是否划出指定范围,不能让游标跑到外头,必须做这个判断
     74                 x = bg_on.getWidth() - slip_btn.getWidth() / 2;// 减去游标1/2的长度...
     75             } else if (NowX < 0) {
     76                 x = 0;
     77             } else {
     78                 x = NowX - slip_btn.getWidth() / 2;
     79             }
     80         } else {// 非滑动状态
     81             if (NowChoose) {// 根据现在的开关状态设置画游标的位置
     82                 x = btn_off_left;
     83                 canvas.drawBitmap(bg_on, matrix, paint);// 初始状态为true时应该画出打开状态图片
     84             } else {
     85                 x = btn_on_left;
     86             }
     87         }
     88         if (isChecked) {
     89             canvas.drawBitmap(bg_on, matrix, paint);
     90             x = btn_off_left;
     91             isChecked = !isChecked;
     92         }
     93 
     94         if (x < 0) {// 对游标位置进行异常判断...
     95             x = 0;
     96         } else if (x > bg_on.getWidth() - slip_btn.getWidth()) {
     97             x = bg_on.getWidth() - slip_btn.getWidth();
     98         }
     99         canvas.drawBitmap(slip_btn, x, 0, paint);// 画出游标.
    100 
    101     }
    102 
    103     public boolean onTouch(View v, MotionEvent event) {
    104         switch (event.getAction()) {// 根据动作来执行代码
    105             case MotionEvent.ACTION_DOWN:// 按下
    106                 if (event.getX() > bg_on.getWidth()
    107                         || event.getY() > bg_on.getHeight()) {
    108                     return false;
    109                 }
    110                 OnSlip = true;
    111                 DownX = event.getX();
    112                 NowX = DownX;
    113                 break;
    114 
    115             case MotionEvent.ACTION_MOVE:// 滑动
    116                 Log.d("David", "event.getX = " + event.getX());
    117                 Log.d("David", "event.getY = " + event.getY());
    118                 NowX = event.getX();
    119                 boolean LastChoose = NowChoose;
    120 
    121                 if (NowX >= (bg_on.getWidth() / 2)) {
    122                     NowChoose = true;
    123                 } else {
    124                     NowChoose = false;
    125                 }
    126 
    127                 if (isChgLsnOn && (LastChoose != NowChoose)) { // 如果设置了监听器,就调用其方法..
    128                     ChgLsn.OnChanged(NowChoose);
    129                 }
    130                 break;
    131 
    132             case MotionEvent.ACTION_UP:// 松开
    133                 OnSlip = false;
    134                 break;
    135             default:
    136         }
    137         invalidate();// 重画控件
    138         return true;
    139     }
    140 
    141     public void SetOnChangedListener(OnChangedListener l) {// 设置监听器,当状态修改的时候
    142         isChgLsnOn = true;
    143         ChgLsn = l;
    144     }
    145 
    146     public interface OnChangedListener {
    147         abstract void OnChanged(boolean CheckState);
    148     }
    149 
    150     public void setCheck(boolean isChecked) {
    151         this.isChecked = isChecked;
    152         NowChoose = isChecked;
    153     }
    154 
    155     @Override
    156     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    157 
    158         int measuredHeight = measureHeight(heightMeasureSpec);
    159         int measuredWidth = measureWidth(widthMeasureSpec);
    160         setMeasuredDimension(measuredWidth, measuredHeight);
    161     }
    162 
    163     private int measureHeight(int measureSpec) {
    164 
    165         /*int specMode = MeasureSpec.getMode(measureSpec);
    166         int specSize = MeasureSpec.getSize(measureSpec);
    167 
    168         // Default size if no limits are specified.
    169 
    170         int result = 500;
    171         if (specMode == MeasureSpec.AT_MOST){
    172             // Calculate the ideal size of your
    173             // control within this maximum size.
    174             // If your control fills the available
    175             // space return the outer bound.
    176 
    177             result = specSize;
    178         } else if (specMode == MeasureSpec.EXACTLY){
    179             // If your control can fit within these bounds return that value.
    180             result = specSize;
    181         }*/
    182         return bg_on.getHeight();
    183     }
    184 
    185     private int measureWidth(int measureSpec) {
    186 
    187         /*int specMode = MeasureSpec.getMode(measureSpec);
    188         int specSize = MeasureSpec.getSize(measureSpec);
    189 
    190         // Default size if no limits are specified.
    191         int result = 500;
    192         if (specMode == MeasureSpec.AT_MOST){
    193             // Calculate the ideal size of your control
    194             // within this maximum size.
    195             // If your control fills the available space
    196             // return the outer bound.
    197             result = specSize;
    198         } else if (specMode == MeasureSpec.EXACTLY){
    199             // If your control can fit within these bounds return that value.
    200             result = specSize;
    201         }*/
    202         return bg_on.getWidth();
    203     }
    204 }

    代码比较简单,而且注释比较详细。

    说一些几个问题:

    1. onTouch()方法中得到的event.getX()和event.getY()是什么值?取值范围是多少?

        刚开始我以为不管咱们的SlipButton放在什么位置,得到的event.getX()值因该是相对屏幕的坐标值,~~其实是错误的,event.getX()只有你的触摸点在当前SlipButton view的布局范围之内才会取到值的。但是值的范围可不仅仅是你的SlipButton view的大小哦,因为一旦你的触摸点在view范围之内触摸到,那么触摸点就可以移到View之外的任何地方了,所以取值范围应该是全屏哦,因此我们在代码里做了如下判断:

    1 if (event.getX() > bg_on.getWidth()
    2              || event.getY() > bg_on.getHeight()) {
    3      return false;
    4 }

    2. measureWidth()和measureHeight()为什么会返回一个固定值?

        首先根据用途,我们自定义的SlipButton View根本没有必要去由调用者调整大小,因为这个ToggleButton本身就是起到开关作用的,在应用中应该是一致的,所以我让这两个方法返回固定值。关于onMeasure()方法根详细的描述,请看我的另一篇文章:http://www.cnblogs.com/wlrhnh/p/3479928.html

    下载源码,请猛戳这里。

  • 相关阅读:
    Angular Material Starter App
    缺少标识符、字符串或数字
    jquery ajax post 传递数组 ,多checkbox 取值
    Circular dependencies cannot exist in RelativeLayout
    第二次作业
    第一次作业
    第一次作业
    软工实践个人总结
    第01组 Beta版本演示
    第01组 Beta冲刺(4/5)
  • 原文地址:https://www.cnblogs.com/wlrhnh/p/3495597.html
Copyright © 2011-2022 走看看