自定义控件,可拖动的开关:SlideSwitch

可以拖动的开关,开关滑块随着手指拖动而变化。

  使用 int 值来区分状态,相比使用boolean值区分状态使代码更加容易理解、更容易些代码。有三种状态: 白天、黑夜、滚动状态。

  canvas画布在滚动状态时,如何画开、关两种状态。

  供用户回调的监听器在哪设置?  

    点击事件、滑块没有滑满就松手、滑块滑满了。这三个地方添加回调方法。

自定义控件:先看构造方法:

    public SlideSwitchButton(Context context) {
        this(context, null);
    }

    public SlideSwitchButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public SlideSwitchButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context) {
        this.context = context;
        Resources resources = getResources();
        switch_light = BitmapFactory.decodeResource(resources,
                R.drawable.switch_on);
        switch_night = BitmapFactory.decodeResource(resources,
                R.drawable.switch_off);
        switch_thumb = BitmapFactory.decodeResource(resources,
                R.drawable.switch_thumb);

        // 进行缩放
        float sx = MyApplication.myApp.screenWidth / switch_light.getWidth()
                - 1;
        float sy = 1 + sx / 4;
        switch_light = BitmapUtil.toScaleBitmap(switch_light, sx, sy);
        switch_night = BitmapUtil.toScaleBitmap(switch_night, sx, sy);
        switch_thumb = BitmapUtil.toScaleBitmap(switch_thumb, sy, sy);

        switch_width = switch_light.getWidth();
        switch_height = switch_light.getHeight();
        thumb_width = switch_thumb.getWidth();

        paint = new Paint();
        paint.setColor(Color.GRAY);
        paint.setTextSize(DensityUtil.dip2px(context, 13));
        paint.setTypeface(Typeface.DEFAULT_BOLD);
    }

该构造方法内初始化了我们需要的图片资源,看一下成员变量:

private Context context;// 上下文
    private Bitmap switch_light;// 白天模式的图片
    private Bitmap switch_night;// 夜间模式的图片

    private String light_text = "白天";
    private String night_text = "黑夜";

    private static final int SWITCH_LIGHT = 0;// 白天状态
    private static final int SWITCH_NIGHT = 1;// 夜间状态
    private static final int SWITCH_SCROLL = 2;// 滚动状态

    private int status = SWITCH_LIGHT;// 默认处于白天状态

    private Paint paint;
    private Bitmap switch_thumb;// 按钮

    private int thumb_width;// 按钮的宽度
    private int switch_width;// 开关的宽度
    private int switch_height;// 开关的高度
    private int left;// 左边界

    private int startX;// 按下起点横坐标
    private int endX;// 滑动时、离开时横坐标
    private boolean actionUp = false;// 手指离开

    private OnSwitchListener listener;// 监听器

接下来就是自定义控件的三大方法,先看onMeasure方法:仅仅就是测量一下,可能不需要这个方法

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(switch_width, switch_height);
        left = switch_width - thumb_width;
    }

onDraw方法:是该自定义控件最核心方法

  根据状态来绘画开关。白天、黑夜这两种比较好画。

    滚动时,根据滑块滑动的位置,滑块左边画白天、右边画黑夜。

    滑动距离小于指定值时,当做点击事件,开关切换状态。

    滑块滑动时,大于指定值时,根据是否超过中间线而松手,超过了则状态切换,没超过则状态不变。

    滑动满时,即从左往右滑,滑动了满格时,即一直滑到底,判断滑块位置是否到边界,到达则切换状态。

  

  难点:

    canvas.drawBitmap(bitmap,src,dst,paint)方法,src指要裁剪的区域,dst指要放在哪里。一般两个都一样。

    屏幕适配问题。drawText(..)

@Override
    protected void onDraw(Canvas canvas) {
        if (status == SWITCH_LIGHT) {
            // 处于白天状态
            canvas.drawBitmap(switch_light, 0, 0, paint);
            canvas.drawBitmap(switch_thumb, 0, 0, paint);
            canvas.drawText(light_text, thumb_width,
                    DensityUtil.dip2px(context, 16), paint);
        } else if (status == SWITCH_NIGHT) {
            // 处于夜间状态
            canvas.drawBitmap(switch_night, 0, 0, paint);
            canvas.drawBitmap(switch_thumb, left, 0, paint);
            canvas.drawText(night_text, DensityUtil.dip2px(context, 5),
                    DensityUtil.dip2px(context, 16), paint);
        } else {
            // 滚动状态
            if (actionUp) {//滑块在中间位置的哪边?
                if (endX < switch_width / 2) {
                    status = SWITCH_LIGHT;
                } else {
                    status = SWITCH_NIGHT;
                }
                actionUp = false;
                invalidate();

                if (listener != null) {
                    listener.onSwitched(this,status == SWITCH_LIGHT);
                }

                return;
            }
              //使滑块滑动时手势居于中间
            int start = endX - thumb_width / 2;

            if (start <= 0)// 左边界
                start = 0;
            if (start > left)// 右边界
                start = left;

            // 向右滑,由白天滑向黑夜

            // 画黑夜
            drawBitmap(canvas, new Rect(0, 0, endX, switch_height), new Rect(0,
                    0, endX, switch_height), switch_night);

            // 画白天
            drawBitmap(canvas, new Rect(endX, 0, switch_width, switch_height),
                    new Rect(endX, 0, switch_width, switch_height),
                    switch_light);

            // TODO:滚动时画字,跟随着消息、展现
            // canvas.drawText(night_text, 5, 16, paint);
            // canvas.drawText(light_text, thumb_width, 16, paint);

            // 画按钮
            canvas.drawBitmap(switch_thumb, start, 0, paint);

            if (start == left) {// 已经滑到底
                status = SWITCH_NIGHT;
                if (listener != null) {
                    listener.onSwitched(this,false);
                }
            } else if (start == 0) {
                status = SWITCH_LIGHT;
                if (listener != null) {
                    listener.onSwitched(this,true);
                }
            }
        }
    }
/**
     * 使用canvas画图,dst表示要显示在哪,src表示要切割的区域
     *
     * @param canvas
     * @param src
     * @param dst
     * @param bitmap
     */
    public void drawBitmap(Canvas canvas, Rect src, Rect dst, Bitmap bitmap) {
        dst = (dst == null ? new Rect(0, 0, bitmap.getWidth(),
                bitmap.getHeight()) : dst);

        canvas.drawBitmap(bitmap, src, dst, paint);
    }

onTouch方法:判断手指位置,不断重绘

  判断点击事件

  判断当前状态,是白天就不要再往白天滑,是黑夜就不要再往黑夜滑。

@Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            startX = (int) event.getX();
            break;

        case MotionEvent.ACTION_MOVE:
            endX = (int) event.getX();

            if (Math.abs(startX - endX) < 8) {
                return true;
            }

            if (startX < endX) {
                // 向右滑,由白天滑向黑夜
                if (startX > switch_night.getWidth() - thumb_width) {// 已经是黑夜
                    status = SWITCH_NIGHT;
                    return true;
                }
            } else {
                // 向左滑,由黑夜滑向白天
                if (startX < thumb_width) {// 已经是白天
                    status = SWITCH_LIGHT;
                    return true;
                }
            }

            status = SWITCH_SCROLL;
            break;

        case MotionEvent.ACTION_UP:
            endX = (int) event.getX();

            if (Math.abs(startX - endX) < 8) {
                // 作为点击事件,切换状态,
                status = Math.abs(status - 1);

                if (listener != null) {
                    listener.onSwitched(this,status == SWITCH_LIGHT);
                }
                break;
            }
            actionUp = true;
            break;
        }

        invalidate();

        return true;
    }

设置监听器,比较简单啦:

/**
     * 设置监听器
     *
     * @param listener
     */
    public void setOnSwitchListener(OnSwitchListener listener) {
        this.listener = listener;
    }

    /**
     * 自定义接口回调
     *
     * @author baiiu
     *
     */
    public interface OnSwitchListener {
        /**
         *
         * @param slideSwitch
         *            本开关对象
         * @param isLight
         *            true,表示于白天。 false表示夜晚
         */
        public abstract void onSwitched(SlideSwitchButton slideSwitch,
                boolean isLight);
    }

设置方法,供用户调用:

    /**
     * 设置开关状态,true表示白天
     */
    public void setSwitch(boolean isLight) {
        status = isLight ? SWITCH_LIGHT : SWITCH_NIGHT;
    }
时间: 2024-07-29 20:39:02

自定义控件,可拖动的开关:SlideSwitch的相关文章

Android自定义控件(一)——开关控件

Google 在 API 14 开始才新增了Switch 控件. 因此,我们可以选择自己封装一个Switch . 效果如图: View主要代码: [java] view plaincopy public class SwitchView extends LinearLayout { private ImageView maskImage;              // 开关遮盖图片 private boolean open;                     // 开关当前状态 priv

搜索栏的自定义

刚开始接触开关样式的按钮是在IOS系统上面,它的切换以及滑动十分帅气,深入人心. 所谓的开关按钮,就是只有2个状态:on和off,下图就是系统IOS 7上开关按钮效果. 起初我在android上我只会使用CheckBox去满足对应的功能.后来,查看开发文档发现,android也有了自己的原生态开关控件,并且在4.0版本中又优化加入了新的类似控件--Switch控件,以及使用起来十分简单的ToggleButton,可是它们只是带有切换效果,而不带有滑动切换效果,并且Switch控件只支持高版本的系

SwitchButton 开关按钮 的多种实现方式

刚开始接触开关样式的按钮是在IOS系统上面,它的切换以及滑动十分帅气,深入人心. 所谓的开关按钮,就是只有2个状态:on和off,下图就是系统IOS 7上开关按钮效果. 起初我在android上我只会使用CheckBox去满足对应的功能.后来,查看开发文档发现,android也有了自己的原生态开关控件,并且在4.0版本中又优化加入了新的类似控件--Switch控件,以及使用起来十分简单的ToggleButton,可是它们只是带有切换效果,而不带有滑动切换效果,并且Switch控件只支持高版本的系

SwitchButton 开关按钮 的多种实现方式 (附源码DEMO)

http://blog.csdn.net/vipzjyno1/article/details/23707149 Switch开关android源码SwitchButton 刚开始接触开关样式的按钮是在IOS系统上面,它的切换以及滑动十分帅气,深入人心. 所谓的开关按钮,就是只有2个状态:on和off,下图就是系统IOS 7上开关按钮效果. 起初我在android上我只会使用CheckBox去满足对应的功能.后来,查看开发文档发现,android也有了自己的原生态开关控件,并且在4.0版本中又优化

Android开源--DragSortListview

項目地址:https://github.com/bauerca/drag-sort-listview 简介:DragSortListview是支持通过左右拖拉删除数据,上下拖拉排序的列表,缺点是当数据 太多时不好下拉. API简介: DragSortListView.DropListener>>该接口监听上下拖动时,位置变化的监听器; DragSortListView.RemoveListener>>该接口监听左右拖动时,滑动成功删除数据的接口; FloatViewManager:

【转】(五)unity4.6Ugui中文教程文档-------概要-UGUI Interaction Components

原创至上,移步请戳:(五)unity4.6Ugui中文教程文档-------概要-UGUI Interaction Components 4.Interaction Components 本节涵盖了处理交互,例如鼠标或触摸事件和使用键盘或控制器交互的 UI系统中的组件. 4.1 Selectable BaseClass 所有交互组件都有一些共同点.selectables是他们所有的控件的基类,这意味着他们都有共享状态,之间的前瞻转换和导航到其他使用键盘或控制器的selectables 的内置功能

(五)unity4.6Ugui中文教程文档-------概要-UGUI Interaction Components

 大家好,我是孙广东.   转载请注明出处:http://write.blog.csdn.net/postedit/38922399 更全的内容请看我的游戏蛮牛地址:http://www.unitymanual.com/forum.php?mod=guide&view=my 4.Interaction Components 本节涵盖了处理交互,例如鼠标或触摸事件和使用键盘或控制器交互的 UI系统中的组件. 4.1 Selectable BaseClass 所有交互组件都有一些共同点.sele

自定义控件基础01_菜单轮__viewPager_下拉框_自定义开关

1,自定义控件分类: 1.1组合控件:由安卓中原生的控件组合起来,配合动画达成的效果 1.2自定义控件 1.3组合控件案例演示: 案例:优酷菜单demo 三层圆环,按下menu键会通过动画效果消失在界面,点击小房子和中层圆环,最外层圆环消失 ①布局实现: 三层相对布局相互叠加(因为图片背景是透明的,所以可以叠加显示) 由于三个布局是叠加显示的,所以这个菜单选项要使用一个占据焦点比较强的(不然有可能点击不到)ImageButton控件 控件上background=”@android:color/t

【Android】自定义控件实现可滑动的开关(switch)

~转载请注明来源:http://blog.csdn.net/u013015161/article/details/46704745 介绍 昨天晚上写了一个Android的滑动开关, 即SlideSwitch.效果如下: 实现 实现的思路其实很简单,监听控件上的touch事件,并不断刷新,让滑块在手指的位置上绘出,达到滑块跟着手指滑动的显示效果. 先看一下代码: SlideSwitch.java package com.example.slideswitchexample; import andr