Android完全自定义控件并且实现监听事件

2023-05-16

本篇文章带来Android的完全自定义控件。载体是自定义一个开关的控件,并且能够响应事件,首先我们先创一个项目,名字就叫ToggleView,修改MainActivity

public class MainActivity extends Activity {

    private ToggleView toggleView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        toggleView = (ToggleView) findViewById(R.id.toggleView);
//        toggleView.setSwitchBackgroundResource(R.drawable.switch_background);
//        toggleView.setSlideButtonResource(R.drawable.slide_button);
//        toggleView.setSwitchState(true);
//        
        // 设置开关更新监听
        toggleView.setOnSwitchStateUpdateListener(new ToggleView.OnSwitchStateUpdateListener(){

            @Override
            public void onStateUpdate(boolean state) {
                Toast.makeText(getApplicationContext(), "state: " + state, Toast.LENGTH_SHORT).show();
            }

        });
    }

//  @Override
//  protected void onResume() {
//      super.onResume();
//  }
//    
}

写一个继承View的自定义控件的类ToggleView

/**
 * 自定义开关
 * @author poplar
 * 
 * Android 的界面绘制流程
 * 测量            摆放     绘制
 * measure  ->  layout  ->  draw
 *    |           |          |
 * onMeasure -> onLayout -> onDraw 重写这些方法, 实现自定义控件
 * 
 * onResume()之后执行
 * 
 * View
 * onMeasure() (在这个方法里指定自己的宽高) -> onDraw() (绘制自己的内容)
 * 
 * ViewGroup
 * onMeasure() (指定自己的宽高, 所有子View的宽高)-> onLayout() (摆放所有子View) -> onDraw() (绘制内容)
 */
public class ToggleView extends View {

    private Bitmap switchBackgroupBitmap; // 背景图片
    private Bitmap slideButtonBitmap; // 滑块图片
    private Paint paint; // 画笔
    private boolean mSwitchState = false; // 开关状态, 默认false
    private float currentX;

    /**
     * 用于代码创建控件
     * @param context
     */
    public ToggleView(Context context) {
        super(context);
        init();
    }

    /**
     * 用于在xml里使用, 可指定自定义属性
     * @param context
     * @param attrs
     */
    public ToggleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
        // 获取配置的自定义属性
        String namespace = "http://schemas.android.com/apk/res-auto";
        int switchBackgroundResource = attrs.getAttributeResourceValue(namespace , "switch_background", -1);
        int slideButtonResource = attrs.getAttributeResourceValue(namespace , "slide_button", -1);

        mSwitchState = attrs.getAttributeBooleanValue(namespace, "switch_state", false);
        setSwitchBackgroundResource(switchBackgroundResource);
        setSlideButtonResource(slideButtonResource);
    }

    /**
     * 用于在xml里使用, 可指定自定义属性, 如果指定了样式, 则走此构造函数
     * @param context
     * @param attrs
     * @param defStyle
     */
    public ToggleView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        paint = new Paint();
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(switchBackgroupBitmap.getWidth(), switchBackgroupBitmap.getHeight());
    }

    // Canvas 画布, 画板. 在上边绘制的内容都会显示到界面上.
    @Override
    protected void onDraw(Canvas canvas) {
        // 1. 绘制背景
        canvas.drawBitmap(switchBackgroupBitmap, 0, 0, paint);

        // 2. 绘制滑块

        if(isTouchMode){
            // 根据当前用户触摸到的位置画滑块

            // 让滑块向左移动自身一半大小的位置
            float newLeft = currentX - slideButtonBitmap.getWidth() / 2.0f;

            int maxLeft = switchBackgroupBitmap.getWidth() - slideButtonBitmap.getWidth();

            // 限定滑块范围
            if(newLeft < 0){
                newLeft = 0; // 左边范围
            }else if (newLeft > maxLeft) {
                newLeft = maxLeft; // 右边范围
            }

            canvas.drawBitmap(slideButtonBitmap, newLeft, 0, paint);
        }else {
            // 根据开关状态boolean, 直接设置图片位置
            if(mSwitchState){// 开
                int newLeft = switchBackgroupBitmap.getWidth() - slideButtonBitmap.getWidth();
                canvas.drawBitmap(slideButtonBitmap, newLeft, 0, paint);
            }else {// 关
                canvas.drawBitmap(slideButtonBitmap, 0, 0, paint);
            }
        }

    }

    boolean isTouchMode = false;
    private OnSwitchStateUpdateListener onSwitchStateUpdateListener;
    // 重写触摸事件, 响应用户的触摸.
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            isTouchMode = true;
            System.out.println("event: ACTION_DOWN: " + event.getX());
            currentX = event.getX();
            break;
        case MotionEvent.ACTION_MOVE:
            System.out.println("event: ACTION_MOVE: " + event.getX());
            currentX = event.getX();
            break;
        case MotionEvent.ACTION_UP:
            isTouchMode = false;
            System.out.println("event: ACTION_UP: " + event.getX());
            currentX = event.getX();

            float center = switchBackgroupBitmap.getWidth() / 2.0f;

            // 根据当前按下的位置, 和控件中心的位置进行比较. 
            boolean state = currentX > center;

            // 如果开关状态变化了, 通知界面. 里边开关状态更新了.
            if(state != mSwitchState && onSwitchStateUpdateListener != null){
                // 把最新的boolean, 状态传出去了
                onSwitchStateUpdateListener.onStateUpdate(state);
            }

            mSwitchState = state;
            break;

        default:
            break;
        }

        // 重绘界面
        invalidate(); // 会引发onDraw()被调用, 里边的变量会重新生效.界面会更新

        return true; // 消费了用户的触摸事件, 才可以收到其他的事件.
    }

    /**
     * 设置背景图
     * @param switchBackground
     */
    public void setSwitchBackgroundResource(int switchBackground) {
        switchBackgroupBitmap = BitmapFactory.decodeResource(getResources(), switchBackground);
    }

    /**
     * 设置滑块图片资源
     * @param slideButton
     */
    public void setSlideButtonResource(int slideButton) {
        slideButtonBitmap = BitmapFactory.decodeResource(getResources(), slideButton);
    }

    /**
     * 设置开关状态
     * @param
     */
    public void setSwitchState(boolean mSwitchState) {
        this.mSwitchState = mSwitchState;
    }

    public interface OnSwitchStateUpdateListener{
        // 状态回调, 把当前状态传出去
        void onStateUpdate(boolean state);
    }

    public void setOnSwitchStateUpdateListener(
            OnSwitchStateUpdateListener onSwitchStateUpdateListener) {
                this.onSwitchStateUpdateListener = onSwitchStateUpdateListener;
    }

}

修改activity_main.xml

<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:my="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <com.mengxin.toggleview.ui.ToggleView
        android:id="@+id/toggleView"
        android:layout_centerInParent="true"
        my:switch_background="@drawable/switch_background"
        my:slide_button="@drawable/slide_button"
        my:switch_state="false"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

在value文件夹下面建一个attrs.xml

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

    <declare-styleable name="ToggleView">
        <attr name="switch_background" format="reference"/>
        <attr name="slide_button" format="reference" />
        <attr name="switch_state" format="boolean" />
    </declare-styleable>

</resources>

具体实现参考源码

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android完全自定义控件并且实现监听事件 的相关文章

  • HTML5初体验——蛮神奇的

    记得去年在一个公司实习的时候 xff0c 听当时的领导说起过HTML5 xff0c 当时就大体了解了一下 知道了是新的下一代HTML的新标准 xff0c 去掉了HTML4中的一些标签 xff0c 扩展了一些标签内容 其他的就没有继续深入的去
  • Aruco码估计相机位姿初步

    Abstract xff1a 利用aruco库中的相关函数实现在摄像头下aruco码的识别和在指定地方插入视频 Criticize xff1a 一 xff1a OpenCV实现USB摄像头的打开 并且实现USB摄像头参数调节 我们调用ope
  • 【笔记】Protues仿真STM32的实现过程

    测试环境 xff1a protues8 6 问题 xff1a 搭建好基本电路 xff0c 在仿真时候出错 xff0c 提示没VSS和VDD未连接 xff0c 如下如图 提示错误 解决办法 xff1a 选择 Design gt Configu
  • 年度回忆录(2013.01----2013.12)

    看了一下上次的年度总结是从 2013 年 2 月份开始的 xff0c 按照以往的习惯 xff0c 年度回忆录是半年一写的 xff0c 这次居然破例了 xff01 由于工作的原因吧 xff08 这是找借口的节奏么 xff09 xff0c 没有
  • 使用JMF实现音乐播放(java多媒体编程)

    JMF实际上是Java的一个类包 JMF 2 1 1技术提供了先进的媒体处理能力 xff0c 从而扩展了 Java平台 的功能 这些功能包括 xff1a 媒体捕获 压缩 流转 回放 xff0c 以及对各种主要媒体形式和编码的支 持 xff0
  • Pygame下载和安装

    Pygame 的下载非常简单 xff0c 可分为两种方式 xff1a 一是通过 Python 的包管理器 pip 来安装 xff1b 二是下载二进制安装包进行安装 其中使用 pip 包管理器安装是最简单 最轻量级的方法 xff0c 下面以
  • 物联网毕业设计 stm32四轴飞行器设计与实现

    1 简介 Hi xff0c 大家好 xff0c 今天向大家介绍一个学长做的单片机项目 基于stm32的四轴飞行器设计 大家可用于 课程设计 或 毕业设计 这次尝试制作一个四旋翼飞控的过程 这个飞控是基于STM32 xff0c 整合了MPU6
  • 机器学习(周志华)学习笔记八:集成学习(上)

    一 AdaBoost思想 三个臭皮匠 xff0c 顶个诸葛亮 xff0c 这也正是集成学习的目的 为了达到上述目的 xff0c AdaBoost算法有两个核心思想 1 更加关注之前基学习器做错的样本 xff1b 2 降低错误率较高的基学习器
  • opencv在编译报错的汇总

    Q1 xuy 64 xuy 桌面 opencv test make usr bin cmake home xuy anaconda2 lib libcurl so 4 no version information available req
  • 至简设计系列_闹钟

    作者 xff1a 小黑同学 本文为明德扬原创及录用文章 xff0c 转载请注明出处 xff01 1 1 1 概述 数字时钟是采用数字电路技术实现时 分 秒计时显示的装置 xff0c 可以用数字同时显示时 xff0c 分 xff0c 秒的精确
  • 遥控器对码与飞控解锁

    今天开始DIY 四旋翼 xff0c 购买了 mwc 飞控和天地飞六代遥控器 xff0c 装好电机电调后 xff0c 想试一下遥控控制电机 首先是遥控发射器与接收器的对码 将电调连上电机后 xff0c 单独把电调的杜邦线插口查到接收器油门插槽
  • Git保存论文

    多图预警 多图预警 多图预警 多图预警 操作步骤 下载git for windows客户端安装TortoiseGit使用Git删除文件夹再试一遍 下载git for windows客户端 下载地址 http msysgit github i
  • Git小乌龟分支操作

    分支的创建 选择创建分支 这里填上分支名字 切换到新分支可点可不点 选中的话直接就切换到新分支 不点的话进行下一步选择切换 检出 选择要切换的分支 分支就创建完成 接下来是分支的合并 分支的合并 首先 确认当前的分支为发起合并方 个人理解
  • 零星PCB打板|开源广场|每月2张|等你来撸|保姆级教程:嘉立创免费PCB打样获取攻略

    目录 缘由 软件 xff1a 嘉立创EDA专业版 xff08 视情况下载 xff0c 非必需 xff09 软件 xff1a 嘉立创PC端下单助手 xff08 领优惠券 xff09 优惠券在这里 xff1a 嘉立创PCB免费打样新规则解读 6
  • Linux下利用GDB调试快速找到Bug

    调试程序最让人头疼的就是层出不断的Bug xff0c 而且有些Bug不容易定位 xff0c 下面介绍一种很强大的调试工具 xff1a GDB 虽然之前听过GDB调试 xff0c 但是自己调试时一直没使用过 今天在调试highmac程序时 x
  • 无状态会话bean(1)---定义

    无状态会话bean 用于完成在单个方法的生命周期内的操作 无状态bean 可以实现许多业务操作 xff0c 但是每个方法都不能假定任何其他的方法会在它之前调用 后半句的意思是现在的你可能不是刚才的你 xff0c 明天的你可也能不是今天的你
  • 树莓派(Raspberry Pi),如何在命令行下配置查看WIFI无线网络

    通常 xff0c 我们的wifi路由器都是开启了DHCP自动分配 ip地址的功能的 xff0c 本文是以这个为前提 xff0c 如果你的WIFI路由器没有开启DHCP xff0c 则在本文的基础上 xff0c 还需要给WLAN0口配置静态I
  • ubuntu虚拟机网络配置同时连接WIFI上外网和连接以太网与ARM开发板通信

    在学习ARM嵌入式开发过程中 xff0c 需要在ubuntu虚拟机下进行程序开发和编译 xff0c 一般需要使用网线直连ARM开发板 xff0c 或挂载NFS网络文件系统 xff0c 或 通过SSH TFTP等网络协议传输在PC端编译完的二
  • Systemd 服务管理教程

    Systemd 概述 Systemd 简介 Systemd 是一系列工具的集合 xff0c 其作用也远远不仅是启动操作系统 xff0c 它还接管了后台服务 结束 状态查询 xff0c 以及日志归档 设备管理 电源管理 定时任务等许多职责 x
  • 高版本Matlab运行时//在当前文件夹或MATLAB路径中未找到文件//函数或变量 ‘xx‘ 无法识别//解决方法

    当你用2019以上版本Matlab时 xff0c 可能会发现这样一个问题 xff1a 当你默默选择 更改文件夹 或者 添加到路径 后 xff0c Matlab又会输出 函数或变量 xx 无法识别 类似这样 xff1a 总之不会乖乖出现运行结

随机推荐

  • 美团技术十年:让我们感动的那些人那些事

    时光荏苒 xff0c 美团十岁了 xff0c 美团技术团队也走过了十个春秋 2010年3月4日美团网上线的时候 xff0c 整个公司总共十来人 xff0c 在一套三居室的民房里起步 其中技术团队只有5个人 xff0c 现在有4位还在美团 今
  • 如何在Windows上轻松安全的将数据从HDD迁移到SSD?

    当你打算升级硬盘时 xff0c 如何将数据从HDD迁移到SSD xff1f 你可以使用一款免费的软件将所有数据从一个硬盘克隆到另一个硬盘 为什么要将数据从HDD迁移到SSD xff1f HDD xff08 机械硬盘 xff09 和SSD x
  • Ubuntu 16.04安装Python3.8

    bin sh install software properties common sudo apt install software properties common install PPA sudo add apt repositor
  • error LNK2038: 检测到“_ITERATOR_DEBUG_LEVEL”的不匹配项: 值“0”不匹配值“2” 解决方法

    错误原因 xff0c Debug工程引用了Release版本的库文件 解决方法
  • 关于wince OS开发面试问题的总结系列之Bootloader

    参考资料 xff1a 1 Windows CE 工程事件完全解析 by xff1a 李大为 2 Windos CE 实用开发技术 by xff1a 张冬泉 等 3 Windows Embedded CE 6 0 Fundamentals 4
  • Jacobian矩阵和Hessian矩阵

    1 Jacobian 转载自 xff1a http jacoxu com p 61 146 在向量分析中 雅可比矩阵是一阶偏导数以一定方式排列成的矩阵 其行列式称为雅可比行列式 还有 在代数几何中 代数曲线的雅可比量表示雅可比簇 xff1a
  • 打工与乘公交

    去一个公司打工就如同上了一辆公交车 在上车之前 xff0c 你应该清楚自己打算去哪里 xff0c 打算在哪里下车 有的公交车很豪华 xff0c 有的很破烂 xff0c 但是这并不是重点 xff0c 所有能开到目的地的车都是好车 上了车之后
  • 卡尔曼滤波器(从vchelp的算法论坛上看到的)

    卡尔曼滤波器 Kalman Filter 1 xff0e 什么是卡尔曼滤波器 xff08 What is the Kalman Filter xff09 在学习卡尔曼滤波器之前 xff0c 首先看看为什么叫 卡尔曼 跟其他著名的理论 xff
  • 第4篇 FreeRTOS是如何工作的---基本原理3(上下文切换)

    上下文切换Context Switching 任务执行时 xff0c 它使用处理器 微控制器的寄存器并访问RAM和ROM xff0c 就像任何其他程序一样 这些资源 处理器寄存器 堆栈等 组成了任务执行上下文 任务是一段连续的代码 xff0
  • MissionPlanner-开发历程-1

    1 Mission Planner 简介 Mission Planner是使用C 开发的开源飞控地面站软件 xff0c 使用MavLink通信协议 xff0c 浏览官方网站 Mission Planner是ArduPilot开源自动驾驶项目
  • 关于SpringSecurity配置中的一些问题解决(登录页面不跳转,报错302)

    1 为何在自定义的登录页面中登录完页面不跳转 xff1f 主要是SpringSecurity在校验csrf跨域时候 xff0c 会传一个csrf相关的随机token值 xff01 在SpringSecurity 4 之后 xff0c 其cs
  • DAY2. jetson nx gpio

    更新 扩展接口说明 xff0c 官方说明文档 xff1a Jetson Xavier NX DevKit Carrier Board Specification v1 0 pdf 分割线 参照这个文档 xff1a https www jet
  • 使用kinect2进行目标跟踪-ROS平台

    之前闲得无聊 xff0c 在ROS平台上调用Kinect摄像头进行目标跟踪检测 首先 xff0c 要在ubuntu下安装好Kinect2和ROS的接口 xff0c 参考http www mamicode com info detail 15
  • 在ROS中使用opencv-灰度处理

    没什么好说的 xff0c 直接看代码理解吧 xff1a include lt ros ros h gt ros标准库头文件 include lt iostream gt C 43 43 标准输入输出库 cv bridge中包含CvBridg
  • GCC的编译流程分为了四个步骤:

    GCC的编译流程分为了四个步骤 1 预处理 xff0c 生成预编译文件 xff08 文件 xff09 xff1a Gcc E hello c o hello i 2 编译 xff0c 生成汇编代码 xff08 s文件 xff09 xff1a
  • Android自定义控件基础

    采用自定义控件解决重复编写代码的问题 总共分三步 1 写好一个自定义模板布局 title XML span class hljs pi lt xml version 61 34 1 0 34 encoding 61 34 utf 8 34
  • String,StringBuffer,StringBuilder的区别(优缺点)

    最近学习到StringBuffer xff0c 心中有好些疑问 xff0c 搜索了一些关于String xff0c StringBuffer xff0c StringBuilder的东西 xff0c 现在整理一下 关于这三个类在字符串处理中
  • nginx+tomcat重复请求

    好久不写技术文章了 xff0c 越发的觉得单纯的讲技术没啥意思 怪不得知乎越来越火 xff0c 因为大家都喜欢看故事 xff0c 不喜欢硬生生的技术文章 笔者今天就来就给大家讲故事 最近网站压力突然增大 xff0c 把带宽都占满了 xff0
  • Android真机获得root权限修改文件权限

    好久没有更新博客了 xff0c 最近因为重装了系统导致所有的配置都不存在了 xff0c 当要修改Android权限去查看数据库文件的时候 xff0c 发现又忘记了怎么去获得修改权限 xff08 其实第一次弄这个内容的时候就费了很大的劲 xf
  • Android完全自定义控件并且实现监听事件

    本篇文章带来Android的完全自定义控件 载体是自定义一个开关的控件 xff0c 并且能够响应事件 xff0c 首先我们先创一个项目 xff0c 名字就叫ToggleView xff0c 修改MainActivity span class