zoukankan      html  css  js  c++  java
  • 【Android】自己定义控件实现可滑动的开关(switch)

    ~转载请注明来源:http://blog.csdn.net/u013015161/article/details/46704745

    介绍

    昨天晚上写了一个Android的滑动开关, 即SlideSwitch。

    效果例如以下:
    这里写图片描写叙述

    实现

    实现的思路事实上非常easy。监听控件上的touch事件,并不断刷新,让滑块在手指的位置上绘出,达到滑块跟着手指滑动的显示效果。
    先看一下代码:
    SlideSwitch.java (7月3日有改动:在touch事件里调用onStateChangedListener前添加判空)

    package com.incell.view;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    
    public class SlideSwitch extends View{
    
        private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); //抗锯齿
    
        boolean isOn = false;
        float curX = 0;
        float centerY; //y固定
        float viewWidth;
        float radius;
        float lineStart; //直线段開始的位置(横坐标,即
        float lineEnd; //直线段结束的位置(纵坐标
        float lineWidth;
        final int SCALE = 4; // 控件长度为滑动的圆的半径的倍数
        OnStateChangedListener onStateChangedListener;
    
        public SlideSwitch(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        public SlideSwitch(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public SlideSwitch(Context context) {
            super(context);
        }
    
    
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            // TODO Auto-generated method stub
            curX = event.getX();
            if(event.getAction() == MotionEvent.ACTION_UP)
            {
                if(curX > viewWidth / 2)
                {
                    curX = lineEnd;
                    if(false == isOn)
                    {
                        //仅仅有状态发生改变才调用回调函数, 下同
                        if(null != onStateChangedListener)
                        {
                            onStateChangedListener.onStateChanged(true);
                        }
                        isOn = true;
                    }
                }
                else
                {
                    curX = lineStart;
                    if(true == isOn)
                    {
                        if(null != onStateChangedListener)
                        {
                            onStateChangedListener.onStateChanged(false);
                        }
                        isOn = false;
                    }
                }
            }
            /*通过刷新调用onDraw*/
            this.postInvalidate();
            return true;
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // TODO Auto-generated method stub
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            /*保持宽是高的SCALE / 2倍, 即圆的直径*/
            this.setMeasuredDimension(this.getMeasuredWidth(), this.getMeasuredWidth() * 2 / SCALE);
            viewWidth = this.getMeasuredWidth();
            radius = viewWidth / SCALE;
            lineWidth = radius * 2f; //直线宽度等于滑块直径
            curX = radius;
            centerY = this.getMeasuredWidth() / SCALE; //centerY为高度的一半
            lineStart = radius;
            lineEnd = (SCALE - 1) * radius;
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            // TODO Auto-generated method stub
            super.onDraw(canvas);
    
            /*限制滑动范围*/
            curX = curX > lineEnd?lineEnd:curX;
            curX = curX < lineStart?

    lineStart:curX; /*划线*/ mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(lineWidth); /*左边部分的线,绿色*/ mPaint.setColor(Color.BLUE); canvas.drawLine(lineStart, centerY, curX, centerY, mPaint); /*右边部分的线,灰色*/ mPaint.setColor(Color.GRAY); canvas.drawLine(curX, centerY, lineEnd, centerY, mPaint); /*画圆*/ /*画最左和最右的圆,直径为直线段宽度。 即在直线段两边分别再加上一个半圆*/ mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(Color.GRAY); canvas.drawCircle(lineEnd, centerY, lineWidth / 2, mPaint); mPaint.setColor(Color.BLUE); canvas.drawCircle(lineStart, centerY, lineWidth / 2, mPaint); /*圆形滑块*/ mPaint.setColor(Color.LTGRAY); canvas.drawCircle(curX, centerY, radius , mPaint); } /*设置开关状态改变监听器*/ public void setOnStateChangedListener(OnStateChangedListener o) { this.onStateChangedListener = o; } /*内部接口。开关状态改变监听器*/ public interface OnStateChangedListener { public void onStateChanged(boolean state); } }

    凝视应该非常具体了。主要有下面几点。
    1、重写了onMeasure方法,使控件高度依赖于控件的宽度

    这样不论在布局文件里怎样设置。总能保证控件的宽高比
    2、控制好滑块的活动范围
    3、定义内部接口OnStateChangedListener,并在自己定义控件里定义了其对象以及从外部赋值的方法setOnStateChangedListener,以便对开关状态更改事件进行监听并调用回调

    使用及Demo

    在布局文件里加入该控件就可以使用。Demo效果为动图展示效果(demo里颜色为绿色,动图为蓝色是由于绿色会导致截取gif时出问题,暂时更改的)。
    Demo中布局文件例如以下:
    activity_main.xml:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    
        <com.example.slideswitchexample.SlideSwitch
            android:id="@+id/slide_switch"
            android:layout_width="200dp"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"/>
    
    </RelativeLayout>
    

    Demo中Activity代码例如以下:
    MainActivity.java

    package com.example.slideswitchexample;
    
    import com.example.slideswitchexample.SlideSwitch.OnStateChangedListener;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.widget.Toast;
    
    public class MainActivity extends Activity {
    
        SlideSwitch sSwitch;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            sSwitch = (SlideSwitch) this.findViewById(R.id.slide_switch);
            sSwitch.setOnStateChangedListener(new OnStateChangedListener(){
    
                @Override
                public void onStateChanged(boolean state) {
                    // TODO Auto-generated method stub
                    if(true == state)
                    {
                        Toast.makeText(MainActivity.this, "开关已打开", 1000).show();
                    }
                    else
                    {
                        Toast.makeText(MainActivity.this, "开关已关闭", 1000).show();
                    }
                }
    
            });
        }
    
    
    }
    

    点此下载Demoproject

  • 相关阅读:
    GAN生成对抗网络-DCGAN原理与基本实现-深度卷积生成对抗网络03
    【我的遇见】
    【笔记汇总贴】
    vtr搭建并使用ipv6免流上校园网教程(CentOs8避坑指南)
    国科大抢课避坑+选课指南+教务系统操作
    论文:Bottom-Up and Top-Down Attention for Image Captioning and Visual Question Answering-阅读总结
    bernoulli, multinoulli distributions 讲解
    论文:Show, Attend and Tell: Neural Image Caption Generation with Visual Attention-阅读总结
    论文:Show and Tell: A Neural Image Caption Generator-阅读总结
    【吴恩达课程使用】pip安装pandas失败-anaconda各种玄学T-T-从新开始搭建环境
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/6689777.html
Copyright © 2011-2022 走看看