Android自定义滑动开关按钮

一、效果图

二、主要技术点

  1.自定义View

  2.自定义属性

三、自定义控件的步骤

  1.自定义类继承自View或View的子类;

  2.重写构造方法

    (1)MyView(Context);  // 在代码中new 对象时调用此方法

    (2)MyView(Context,AttributeSet);  // 在XML布局文件中声明此View,创建对象时,由系统自动调用

    (3)MyView(Context,AttributeSet,int);  // 与方法2用法一样,只是多了一个参数:默认样式

  3.重写相关方法,实现我们的需求,一般要重写的方法:

    (1)onMeasure(int,int);  // 系统测量控件大小时调用该方法

    (2)onLayout(boolean,int,int,int,int);  // 系统为该view 指定位置时调用此方法,子view的位置,自身只有建议权,决定权在父view的手中。一般不需要重写。

    (3)onDraw(Canvas);  // 为本view绘制内容时,调用该方法。

四、为新控件添加自定义属性的步骤:

  1.在attrs.xml文件中声明属性,有属性名(name)和格式(format)。如

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- 声明属性集的名称 -->
    <declare-styleable name="MyToggleBtn">
        <!-- 声名一个属性  name是my_background   类型为 引用类型      引用资源ID -->
        <attr name="my_background" format="reference" />
        <!-- 声名一个属性  name是my_slide_btn   类型为 引用类型      引用资源ID -->
        <attr name="my_slide_btn" format="reference" />
        <!-- 声名一个属性  name是curr_state   类型为 boolean 类型 -->
        <attr name="curr_state" format="boolean" />
    </declare-styleable>

</resources>

  2.在布局文件中使用新属性,使用之前必须先声明命名空间,如xmlns:gnnuit="http://schemas.android.com/apk/res/com.gnnuit.togglebutton",其中“http://schemas.android.com/apk/res/”为Android固定的格式,“com.gnnuit.togglebutton”为应用程序的包名,与AndroidManifest.xml声明的包名一样。

<com.gnnuit.togglebutton.MyToggleButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        gnnuit:curr_state="true"
        gnnuit:my_background="@drawable/switch_background"
        gnnuit:my_slide_btn="@drawable/slide_button" />

  3.在自定义View的构造方法中,通过解析AttributeSet对象,获得所需要的属性值。

四。核心代码

package com.gnnuit.togglebutton;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class MyToggleButton extends View implements android.view.View.OnClickListener {
    private Bitmap backgroundBitmap;// 背景图片
    private Bitmap slideButtonBitmap;// 滑动按钮图片
    private Paint paint;
    private boolean currentState = false;// 当前状态
    private float left_slide;// 滑动按钮的左边界位置
    private float startX, lastX;// 记录滑动按钮滑动时的开始和结束位置
    private boolean isSlide = false;// 记录是否移动滑动按钮
    private float dist;

    /**
     * 在布局文件中声明此View,创建时由系统自动调用该构造方法
     *
     * @param context
     * @param attrs
     */
    public MyToggleButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 获取自定义属性
        currentState = attrs.getAttributeBooleanValue("http://schemas.android.com/apk/res/com.gnnuit.togglebutton", "curr_state", false);

        int backgroundResourceId = attrs.getAttributeResourceValue("http://schemas.android.com/apk/res/com.gnnuit.togglebutton", "my_background", -1);
        if (backgroundResourceId == -1) {
            throw new RuntimeException("请设置背景图片");
        }
        backgroundBitmap = BitmapFactory.decodeResource(getResources(), backgroundResourceId);

        int slideBtnResourceId = attrs.getAttributeResourceValue("http://schemas.android.com/apk/res/com.gnnuit.togglebutton", "my_slide_btn", -1);
        if (slideBtnResourceId == -1) {
            throw new RuntimeException("请设置背景图片");
        }
        slideButtonBitmap = BitmapFactory.decodeResource(getResources(), slideBtnResourceId);

        if (currentState) {
            left_slide = backgroundBitmap.getWidth() - slideButtonBitmap.getWidth();
        }
        initView();// 初始化
    }

    /**
     * 初始化
     */
    private void initView() {
        // 初始化图片
        // backgroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
        // slideButtonBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);
        // 初始化画笔
        paint = new Paint();
        paint.setAntiAlias(true);// 设置抗锯齿
        // 设置点击事件
        setOnClickListener(this);
    }

    @Override
    /**
     * 测量尺寸的回调方法
     */
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(backgroundBitmap.getWidth(), backgroundBitmap.getHeight());// 设置控件的宽和高,单位是像素
    }

    @Override
    /**
     * 绘制当前View的内容
     */
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(backgroundBitmap, 0, 0, paint);
        canvas.drawBitmap(slideButtonBitmap, left_slide, 0, paint);
    }

    @Override
    public void onClick(View v) {
        if (!isSlide) {
            currentState = !currentState;
            flushState();// 刷新界面
        }
    }

    /**
     * 刷新当前状态
     */
    private void flushState() {
        if (currentState) {
            left_slide = backgroundBitmap.getWidth() - slideButtonBitmap.getWidth();
        } else {
            left_slide = 0;
        }
        invalidate();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            isSlide = false;
            startX = lastX = event.getX();
            break;

        case MotionEvent.ACTION_MOVE:
            lastX = event.getX();
            dist = lastX - startX;
            if (Math.abs(dist) > 5) {
                isSlide = true;
                left_slide += dist;
                flushShow();
                startX = event.getX();
            }
            break;
        case MotionEvent.ACTION_UP:
            if (isSlide) {
                if (left_slide > (backgroundBitmap.getWidth() - slideButtonBitmap.getWidth()) / 2) {
                    left_slide = backgroundBitmap.getWidth() - slideButtonBitmap.getWidth();
                    currentState = true;
                } else {
                    left_slide = 0;
                    currentState = false;
                }
                flushShow();
            }
            break;
        }
        return true;
    }

    /**
     * 刷新当前View
     */
    private void flushShow() {
        int maxLeftSlide = backgroundBitmap.getWidth() - slideButtonBitmap.getWidth();
        // left_slide的范围为0=<left_slide<=maxLeftSlide
        if (left_slide > maxLeftSlide) {
            left_slide = maxLeftSlide;
            currentState = true;
        } else if (left_slide < 0) {
            left_slide = 0;
            currentState = false;
        }
        invalidate();
    }
}
时间: 2024-10-16 19:44:28

Android自定义滑动开关按钮的相关文章

Android 自定义的开关按钮——SwitchButton

本文转自:http://blog.csdn.net/swust_chenpeng/article/details/19967501 我将原文的控件进行了一些修改,去掉了原来控件的外边框,只留下重要的遮罩.背景和滑块.并且可以在布局文件中预览(预览效果不是太好,凑合看看还可以).自己修改了下监听器,增加了一些方法.总之目前已经和官方的控件差不多了.重要的是可以自定义控件的大小了! 上面粉红色的那个就是我们自定义的控件了,下面的两个是用的官方的控件,自己改样式.基本处于没用的级别. 好了,现在我们开

android 自定义滑动按钮

第一接触公司项目就让我画页面,而且还涉及到我最讨厌的自定义view  但是没办法,讨厌也必须要做啊,经过百度上资源的查找,终于写出了一个滑动控件.废话不多说,上代码. package com.etong.cpms.widget; import com.etong.cpms.activity.R; import android.content.Context;  import android.graphics.Bitmap;  import android.graphics.BitmapFacto

Android 自定义 HorizontalScrollView 打造再多图片(控件)也不怕 OOM 的横向滑动效果

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38140505 自从Gallery被谷歌废弃以后,Google推荐使用ViewPager和HorizontalScrollView来实现Gallery的效果.的确HorizontalScrollView可以实现Gallery的效果,但是HorizontalScrollView存在一个很大的问题,如果你仅是用来展示少量的图片,应该是没问题的,但是如果我希望HorizontalScr

android 自定义adapter和线程结合 + ListView中按钮滑动后状态丢失解决办法

adapter+线程 1.很多时候自定义adapter的数据都是来源于服务器的,所以在获取服务器的时候就需要异步获取,这里就需要开线程了(线程池)去获取服务器的数据了.但这样有的时候adapter的中没有数据. 如下面的代码: 这就是在initData中异步获取服务器的数据,然后实例化adatper,再将adapter赋给listView. 2.initData()中的代码是: 这里线程要睡眠5秒钟,是为了模仿网络的耗时操作 3.Handler: 在Handler中接收到数据后给list赋值后,

android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检索

我们的手机通讯录一般都有这样的效果,如下图: OK,这种效果大家都见得多了,基本上所有的Android手机通讯录都有这样的效果.那我们今天就来看看这个效果该怎么实现. 一.概述 1.页面功能分析 整体上来说,左边是一个ListView,右边是一个自定义View,但是左边的ListView和我们平常使用的ListView还有一点点不同,就是在ListView中我对所有的联系人进行了分组,那么这种效果的实现最常见的就是两种思路: 1.使用ExpandableListView来实现这种分组效果 2.使

Android自定义组件系列【10】——随ViewPager滑动的导航条

昨天在用到ViewPager实现滑动导航的时候发现微信的导航条效果是跟随ViewPager的滑动而动的,刚开始想了一下,感觉可以使用动画实现,但是这个滑动是随手指时时变化的,貌似不可行,后来再网上搜了一下,找到一个开源代码,结果打开一看大吃一惊,这么简单的效果代码居然大概有300多行,太占手机存储空间了!后来自己干脆重写ViewGroup使用scrollTo方法实现了一下,具体实现过程如下: package com.example.slideupdownviewpage; import andr

Android 自定义ScrollView ListView 体验各种纵向滑动的需求

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38950509,本文出自[张鸿洋的博客] 1.概述 群里的一个哥们有个需求是这样的:问题:主要功能就是:1.循环的一个滑动:2.每次滑动结束,保持每个Item的完整.然后我当时给他写了个Demo,所有代码都在Activity里面,后期看来其太恶心了,修改也不方便:貌似那哥们还因为那代码修改到12点,大大的赞一下这哥们的毅力,也深表歉意,今天特意把代码抽取成自定义的ScrollVi

Android双向滑动菜单完全解析,教你如何一分钟实现双向滑动特效

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9671609 记得在很早之前,我写了一篇关于Android滑动菜单的文章,其中有一个朋友在评论中留言,希望我可以帮他将这个滑动菜单改成双向滑动的方式.当时也没想花太多时间,简单修改了一下就发给了他,结果没想到后来却有一大批的朋友都来问我要这份双向滑动菜单的代码.由于这份代码写得很不用心,我发了部分朋友之后实在不忍心继续发下去了,于是决定专门写一篇文章来介绍更好的Android双向滑

Android 自定义RecyclerView 实现真正的Gallery效果

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38173061 ,本文出自:[张鸿洋的博客] 上一篇博客我使用自定义HorizontalScrollView写了一个具有HorizontalScrollView效果和ViewPager特性的横向图片轮播,详见:Android 自定义 HorizontalScrollView 打造再多图片(控件)也不怕 OOM 的横向滑动效果.其实制作横向滚动的不得不说另一个控件,就是Google