自定义ToggleButton选择控件

C#winform实现像触摸屏按钮那样的开关 触摸屏的按钮开发起来非常方便,只要设置好样式和文本,以及绑定的变量,一个开关就做好了。而用winform要实现同样的功能,要编写许多代码。 阅读详情

转载请注明出处:


以前的项目中有关于手势开关的按钮,发现自带的ToggleButton不是很好看,于是花了些时间,自定义了个ToggleButton。

先上效果图:

其中,圆形button是可以随手指左右滑动的。

大体思路是分以下几步: 首先是需要自定义属性:

在values文件夹下的attrs xml文件中自定义属性:

   <declare-styleable name="ToggleButton">
        <!-- 开关背景图片的属性 -->
        <attr name="switchBackgroundResource" format="reference"/>
        <attr name="switchBackgroundTrueResource" format="reference"/>
        <!-- 开关滑动块的属性 -->
        <attr name="slideButtonBackgroundResource" format="reference"/>
        <!-- 开关当前状态的属性, true 打开, false 关闭 -->
        <attr name="currentState" format="boolean"/>
    </declare-styleable>

然后ToggleButton 是继承自View基类,然后需要在xml文件中引入此控件,需要在一下构造函数中这样写:

/**
     * 当在xml代码中引用此自定义控件时, 需要使用此构造函数.
     *
     * @param context
     * @param attrs
     *            在布局文件中声明的各种属性.
     */
    public ToggleButton(Context context, AttributeSet attrs) {

         ……

          // 自定义的命名空间
        String namespace = "http://schemas.android.com/apk/res/com.zchz.app";

        // 取出自定义属性中背景图片
        int switchBackgroundID = attrs.getAttributeResourceValue(namespace, "switchBackgroundResource", -1);
        int switchBackgroundTrueID = attrs.getAttributeResourceValue(namespace, "switchBackgroundTrueResource", -1);
        // 取出自定义属性中滑动块图片
        int slideButtonBackgroundID = attrs.getAttributeResourceValue(namespace, "slideButtonBackgroundResource", -1);

        // 取出自定义属性中当前状态
        currentState = attrs.getAttributeBooleanValue(namespace, "currentState", false);

         ……

    }

在该构造函数中需要进行命名空间自定义,一些自定义属性的读取等等。

然后是提供对外修改当前开关的状态的方法currentState,

自定义控件比较重要的三个API分别是 onMesure(), onLayout(), onDraw(), 分别是进行对当前需要自定义View的内容属性的大小测量,具体在视图窗口中的布局(即位置的确定),以及最重要的一步:利用paint及cavas(画布)将自定义view展示出来。

为了实现能够手动滑动按钮实现开关切换的效果,需要复写onTouchEvent()方法来进行当前手指触碰控件的判断,当手指按下,手指移动,手指抬起的状态分别记录圆形按钮的位置来进行控件的位置刷新和控件当前状态的改变。

附上源码:

/**
 * 自定义控件: 滑动开关.
 *
 * @author Dch
 * @since 2015年7月29日 11:48:07
 *
 */
public class ToggleButton extends View {

    private boolean currentState = false; // 当前开关的状态, 默认为: 关闭
    private Bitmap mSwitchBackground; // 开关的背景图片(false)
    private Bitmap mSwitchBackgroundTrue; // 开关的背景图片(true)
    private Bitmap mSlideButtonBackground; // 滑动块的图片
    private int currentX; // 当前移动时x轴的值.
    private boolean isTouching = false; // 是否正在触摸滑动中, 默认为: 没有正在滑动

    private OnToggleStateChangedListener mOnToggleStateChangedListener; // 用户回调的接口

    /**
     * 当在java代码中创建此对象时, 需要使用此构造函数.
     *
     * @param context
     */
    public ToggleButton(Context context) {
        super(context);
    }

    /**
     * 当在xml代码中引用此自定义控件时, 需要使用此构造函数.
     *
     * @param context
     * @param attrs
     *            在布局文件中声明的各种属性.
     */
    public ToggleButton(Context context, AttributeSet attrs) {
        super(context, attrs);

        // 自定义的命名空间
        String namespace = "http://schemas.android.com/apk/res/com.zchz.app";

        // 取出自定义属性中背景图片
        int switchBackgroundID = attrs.getAttributeResourceValue(namespace, "switchBackgroundResource", -1);
        int switchBackgroundTrueID = attrs.getAttributeResourceValue(namespace, "switchBackgroundTrueResource", -1);
        // 取出自定义属性中滑动块图片
        int slideButtonBackgroundID = attrs.getAttributeResourceValue(namespace, "slideButtonBackgroundResource", -1);

        // 取出自定义属性中当前状态
        currentState = attrs.getAttributeBooleanValue(namespace, "currentState", false);

        setSwitchBackgroundResource(switchBackgroundID);
        setSwitchBackgroundTrueResource(switchBackgroundTrueID);
        setSlideButtonBackgroundResource(slideButtonBackgroundID);
    }

    /**
     * 设置当前开关的背景图片id, 例: R.drawable.xxx
     *
     * @param switchBackground
     */
    public void setSwitchBackgroundResource(int switchBackground) {
        mSwitchBackground = BitmapFactory.decodeResource(getResources(), switchBackground);
    }

    /**
     * 设置当前开关的背景图片id, 例: R.drawable.xxx
     *
     * @param switchBackground
     */
    public void setSwitchBackgroundTrueResource(int switchBackground) {
        mSwitchBackgroundTrue = BitmapFactory.decodeResource(getResources(), switchBackground);
    }

    /**
     * 设置滑动块的图片id, 例: R.drawable.xxx
     *
     * @param slideButtonBackground
     */
    public void setSlideButtonBackgroundResource(int slideButtonBackground) {
        mSlideButtonBackground = BitmapFactory.decodeResource(getResources(), slideButtonBackground);
    }

    /**
     * 设置当前开关的状态.
     *
     * @param b
     */
    public void setCurrentState(boolean b) {
        this.currentState = b;
    }

    public boolean getCurrentState() {
        return currentState;
    }

    /**
     * 当前控件需要测量宽和高时, 触发此方法.
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 设置当前控件的宽和高和背景图片的宽和高一样.
        if (currentState) {
            setMeasuredDimension(mSwitchBackgroundTrue.getWidth(), mSwitchBackgroundTrue.getHeight());
        } else {
            setMeasuredDimension(mSwitchBackground.getWidth(), mSwitchBackground.getHeight());
        }
    }

    /**
     * 当前控件需要绘制出来时, 调用此方法.
     *
     * @param canvas
     *            画画板, 使用canvas所画出来的东西, 都是作为当前控件, 在屏幕上显示.
     */
    @Override
    protected void onDraw(Canvas canvas) {
        // 1. 把背景图片平铺在当前控件中.
        if (currentState) {
            canvas.drawBitmap(mSwitchBackgroundTrue, 0, 0, null);
        } else {
            canvas.drawBitmap(mSwitchBackground, 0, 0, null);
        }

        if (isTouching) { // 当前正在拖动中, 应该根据currentX来处理滑动块的位置.
            // 根据当前x轴的值, 来动态的修改滑动块的位置.
            int left = currentX - mSlideButtonBackground.getWidth() / 2;
            if (left < 0) { // 超出了左边界, 应该一直设置为0
                left = 0;
            } else if (left > mSwitchBackground.getWidth() - mSlideButtonBackground.getWidth()) {
                left = mSwitchBackground.getWidth() - mSlideButtonBackground.getWidth();
            }
            canvas.drawBitmap(mSlideButtonBackground, left, 0, null);
        } else { // 当前没有触摸滑动中, 需要根据currentState来处理滑动块的位置.
            // 2. 根据当前的状态currentState来绘制滑动块的位置.
            if (currentState) {
                // 当前开关处于打开的状态, 把滑动块画在当前控件的右边.
                int left = mSwitchBackground.getWidth() - mSlideButtonBackground.getWidth();
                canvas.drawBitmap(mSlideButtonBackground, left, 0, null);
            } else {
                // 当前开关处于关闭的状态, 把滑动块画在当前控件的左边.
                canvas.drawBitmap(mSlideButtonBackground, 0, 0, null);
            }
        }
    }

    /**
     * 当前控件被触摸时触发此方法.
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            isTouching = true;
            currentX = (int) event.getX();
            break;
        case MotionEvent.ACTION_MOVE:
            currentX = (int) event.getX();
            break;
        case MotionEvent.ACTION_UP:
            isTouching = false;
            currentX = (int) event.getX();

            // 判断当前偏向于那一边

            int center = mSwitchBackground.getWidth() / 2;

            // 如果当前滑动块的中心点 > 背景图片中心点的位置时, 把当前状态置为true, 是打开的状态.
            // 如果当前滑动块的中心点 < 背景图片中心点的位置时, 把当前状态置为false, 是关闭的状态.
            boolean state = currentX > center; // 最新的状态

            // 当前是抬起, 判断当前状态是否已经改变了, 如果改变, 调用用户的回调接口把改变后的状态, 传递过去.
            if (state != currentState && mOnToggleStateChangedListener != null) {
                // 当前状态已经被修改了, 需要回调用户.
                mOnToggleStateChangedListener.onToggleStateChanged(state);
            }

            // 把最新的状态赋值给当前类的成员变量: 当前开关的状态.
            currentState = state;
            break;
        default:
            break;
        }

        // 手动触发onDraw方法的重绘.
        invalidate(); // 刷新当前控件, 会引起onDraw方法调用.
        return true; // 自己处理滑动的事件
    }

    public void setOnToggleStateChangedListener(OnToggleStateChangedListener listener) {
        this.mOnToggleStateChangedListener = listener;
    }

    /**
     * @author andong 当开关状态改变时的监听事件.
     */
    public interface OnToggleStateChangedListener {

        /**
         * 开关状态改变时, 触发此方法.
         *
         * @param currentState
         *            true 打开, false 关闭
         */
        public void onToggleStateChanged(boolean currentState);

    }

}


在代码中使用:

根布局:     xmlns:app="http://schemas.android.com/apk/res/com.zchz.app"

    <com.example.ToggleButton
            android:layout_width="50dp"
            android:layout_height="16dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="15dp"
            app:currentState="false"
            app:slideButtonBackgroundResource="@drawable/gesture_button"
            app:switchBackgroundResource="@drawable/gesture_bg1"
            app:switchBackgroundTrueResource="@drawable/gesture_bg2" />

Winform UI界面设计例程——自定义toggleButton winform c#界面设计 自定义控件 toggleButton 阅读详情

相关推荐

Android UI 组件系列(五):CheckBox、RadioButton 与 Switch 控件详解

Android开发中常用的选择控件解析 本文介绍了Android开发中三种核心选择控件的使用方法和适用场景:1) CheckBox多选按钮适用于兴趣爱好等可多选场景;2) RadioButton与RadioGroup组合实现单选功能;3) Switch和ToggleButton用于开关设置。文章详细展示了各控件的XML布局示例和Kotlin代码实现,包括获取选中状态、设置监听事件等关键操作。其中特别强调Switch控件是现代Android应用的首选开关控件,而ToggleButton则建议谨慎使用。这些控件

weixin_39339407的博客 1591

C# WPF编程-ToggleButton

在WPF中,ToggleButton是一个非常有用的控件,它允许用户在两种状态之间切换:选中(Checked)和未选中(Unchecked)。此外,还有一个中间状态叫做“不确定”(Indeterminate),但需注意的是,并不是所有的使用场景都需要或支持这个状态。下面将介绍如何使用ToggleButton,包括基本用法、样式定制以及事件处理。

若有博文对您有帮助,欢迎点赞关注,收藏评论。 1186

C#版winform中使用的ToggleButton

包含源代码,Winform中可以使用的ToggleButton,有状态切换事件,鼠标经过、点击效果。要看效果请复制该链接https://blog.youkuaiyun.com/brzee88/article/details/80426480

界面编程之基本界面组件(5)ToggleButton(状态开关按钮)

ToggleButton用于切换程序中的某种状态。 ToggleButton有三个XML属性:android:checked,设置该按钮是否被选中,对应的方法为setChecked(boolean);                                                        android:textOff,设置当按钮没有被选中时显示的文本;

liufeng93的专栏 1050

自定义个性化togglebutton

简单的风格.简单的自定义togglebutton

文献计量VOSviewer分析知网文献基本操作及实用技巧

本教程旨在为读者提供一个关于VOS viewer的初级使用指南。VOS viewer是一个强大的科学研究可视化工具,主要用于构建和可视化科学地图。它能够处理大规模的科研数据,包括文献引用、共引、共词、共作者等信息。无论你是科研人员,还是数据分析师,甚至是研究生,都能在这个教程中找到使用VOS viewer的有效方法。我们将一步步教你如何使用这个软件,以及如何利用它进行科研数据的可视化。

Jia_n的博客 8764

Android自定义View仿IOS选择控件Togglebutton实现

Android自定义View仿IOS选择控件Togglebutton实现 目前在搞自定义view这一块的东西,将自己手写的很多效果控件将全部展示在博客中,这个是模仿ios的一个控件,虽然有原生的可以直接用了,但是毕竟知道实现更有助于自己写出风格各样的自定义控件。文中会贴出代码,但如果想在实际项目中使用,还需要增加很多逻辑判断以及监听回掉。 原效果图如下: 画图分析自定义view的绘

3733

Win11 24H2共享访问被禁?深入聊聊SMB签名和‘不安全的来宾登录’那点事

本文深入解析Win11 24H2共享访问故障,探讨SMB签名的安全机制与‘不安全的来宾登录’问题。提供从注册表修改到组策略配置的多层次解决方案,特别针对家庭网络和打印机共享场景给出实用建议,帮助用户在安全与便利之间找到平衡。

weixin_42556197的博客 562

004 RadioButton,ToggleButton和Switch控件

RadioButton 单选按钮 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"

Birdlun的博客 626

基于 SquashFS 构建 Linux 可读写文件系统

嵌入式 Linux 启动过程 本文所描述的的 Linux Image 由 BootLoader、kernel、initrd、rootfs 组成,它们共同存在于一个可以启动的存储设备中(本文以 USB 为例)。组成架构如下: 图 1. 可启动 linux 镜像文件结构 各个模块的作用如下: Boot Loader:由 BIOS 加载,用于将后续的 Kernel 和 initrd 的装载到内存中 kernel:为 initrd 运行提供基础的运行环境 initrd:检测并加载各种驱动程序 ro

wzq2009的专栏 1171

【Linux】实际项目应该如何完成?--安防监控系统项目的总结

到目前为止我也做个5、6个嵌入式项目,但以往都是从零开始自己做,也就是毫无计划,想到那里做那里,有想法就会去实现,就这样导致我碰到了很多坑,也消耗了我许多时间,当然,不是说这样不好,因为在其中我也得到了一个很好的锻炼与练习,但是这不适用于在工作中去这样做。...

修成真的博客 6724

android选择人物的控件,Android 选择控件

iv=(ImageView) findViewById(R.id.imageView1);tbutton=(ToggleButton) findViewById(R.id.tbutton01);checkbox=(CheckBox) findViewById(R.id.checkbox01);radioGroup=(RadioGroup) findViewById(R.id.radiogroup0...

weixin_39793564的博客 176

kubeadm init 运行时kebelet启动失败问题

解决k8s kubeadm init时遇到的kubelet问题

ZDPZN的博客 6074

系出名门 Android(6) - 控件(View)之DatePicker, TimePicker, ToggleButton, EditText, ProgressBar, SeekBar, AutoCompleteTextView, MultiAuto

<br />介绍<br />在 Android 中使用各种控件(View)<br />DatePicker - 日期选择控件<br />TimePicker - 时间选择控件<br />ToggleButton - 双状态按钮控件<br />EditText - 可编辑文本控件<br />ProgressBar - 进度条控件<br />SeekBar - 可拖动的进度条控件<br />AutoCompleteTextView - 支持自动完成功能的可编辑文本控件<br />MultiAutoComplet

381

实战干货|.NET9 C#上位机:多PLC并发通信+数据防丢+指令精准下发(10台设备实测+踩坑实录)

摘要:本文介绍了一个基于.NET9重构汽车零部件产线10台西门子S7-1200 PLC并发通信的工业级解决方案。针对原有系统存在的同步轮询阻塞、数据丢失、指令重复等问题,采用连接池复用、异步并发控制、超时隔离等技术,实现800ms内完成10台PLC并发采集、零丢包率、100%指令精准下发。方案通过.NET9的ThreadPool调度优化和ValueTask内存管理,将CPU占用控制在15%以内,解决了多PLC通信中的并发冲突、超时扩散等核心痛点,并提供了可直接复用的工业级代码实现。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 451

[网络安全自学篇] 二.Chrome浏览器保留密码功能渗透解析及登录加密入门笔记

最近开始学习网络安全相关知识,接触了好多新术语,感觉自己要学习的东西太多,真是学无止境,也发现了好几个默默无闻写着博客、做着开源的大神。接下来系统分享一些网络安全的自学笔记,希望读者们喜欢。 上一篇文章分享了看雪Web安全总结知识和一个异或解密的示例,本篇文章着重讲解Chrome浏览器保留密码功能渗透解析及登录加密入门笔记,结合实际例子一步步实现浏览器漏洞的挖掘。非常基础的文章,希望对入门的博友们有帮助,大神请飘过,谢谢各位看官!

杨秀璋的专栏 2万+

自定义控件的一些概念

1、为什么是自定义控件: 答:在Android系统中,用系统的自带控件重新组合或者自己定义类继承View或者自定义类继承ViewGroup,实现特定的效果。 2、为什么要学习自定义控件: 答: 1.系统的某一个控件,在不同的设备效果不一样 ---当我们想让这个控件在所有的设备显示都是一样的风格的时候,就需要自定义 例如:同样的代码在不同设备运行,效果不一样 在Android2.3的B...

qq_36451275的博客 605

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Android 选择控件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <Ima...

weixin_30405421的博客 117

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Android自定义控件1--自定义控件介绍

Android控件基本介绍 Android本身提供了很多控件比如我们常用的有文本控件TextView和EditText;按钮控件Button和ImageButton状态开关按钮ToggleButton单选复选按钮RadioButton和RadioGroup单选按钮和复选按钮CheckBox图片控件ImageView时钟控件AnalogClock和DigitalClock进度条ProgressBa...

weixin_30287169的博客 79

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

系出名门Android(6) - 控件(View)之DatePicker, TimePicker, ToggleButton, EditText, Progre

系出名门Android(6) - 控件(View)之DatePicker, TimePicker, ToggleButton, EditText, ProgressBar, SeekBar, AutoCompleteTextView, MultiAutoCompleteTextView 作者:webabcd 介绍 在 Android 中使用各种控件(View) DateP

Devil不加V 1175

系出名门Android(6) - 控件(View)之DatePicker, TimePicker, ToggleButton, EditText, ProgressBar, SeekBar, AutoComplete

[源码下载]系出名门Android(6) - 控件(View)之DatePicker, TimePicker, ToggleButton, EditText, ProgressBar, SeekBar, AutoCompleteTextView, MultiAutoCompleteTextView作者:webabcd介绍在 Android 中使用各种控件(View) DatePicker 

webabcd的专栏 1557

系出名门Android(6) - 控件(View)之DatePicker, TimePicker, ToggleButton, EditText, ProgressBar

[索引页][×××] 系出名门Android(6) - 控件(View)之DatePicker, TimePicker, ToggleButton, EditText, ProgressBar, SeekBar, AutoCompleteTextView, MultiAutoCompleteTextView作者:webabcd介绍在 Android 中使用各种控件(View...

weixin_34122604的博客 69

android 常用控件一览(从底层分析,为自定义控件做下小铺垫)

Android本身提供了很多控件比如我们常用的有文本控件TextView和EditText;按钮控件Button和ImageButton状态开关按钮ToggleButton单选复选按钮RadioButton和RadioGroup单选按钮和复选按钮CheckBox和RadioButton图片控件ImageView时钟控件AnalogClock和DigitalClock进度条ProgressBar...

haierboos 199
上一篇: 这两年android开发感想
下一篇: 【简明教程】Git
MrCoderr
博客等级 码龄12年 39粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值