IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android开发学习之控件架构与自定义控件 -> 正文阅读

[移动开发]Android开发学习之控件架构与自定义控件

(学习参考书:Android群英传)

一、Android控件架构

Android中的控件大致被分为两大类,即ViewGroup控件和View控件。ViewGroup控件作为父控件可以包含多个View控件,并对其进行管理。通过ViewGroup整个界面上的控件形成了一个树形结构即控件树,通常在activity中使用findViewById()就是在控件树中以深度优先遍历来查找对应元素的。
在这里插入图片描述

每个activity都包含一个Window对象,在Android中Window对象通常用PhoneWindow来实现。PhoneWindow将一个DecorView设置为整个应用窗口的根View。

二、View的测量

Android系统在绘制View前,也必须对View进行测量,在onMeasure()方法中进行。Android系统提供了一个设计短小精悍却功能强大的类——MeasureSpec类,通过它来帮助完成测量。MeasureSpec是一个32位int值,其中高两位为测量的模式,低30位位测量的大小。
测量模式分为:

  • EXACTLY:精确值模式,将控件长宽指定为准确数值
  • AT_MOST:最大值模式,只要控件的尺寸不超过父控件允许的最大尺寸,控件大小一般随着内容大小变化(wrap_content)
  • UNSPECIFIED:不指定大小测量模式,View想多大就多大,通常情况下在绘制自定义View时才会使用

View类默认的onMeasure()方法只支持EXACTLY,因此在自定义控件时不重写onMeasure()方法的话,也只能使用EXACTLY模式,控件可以响应match_parent属性,但如果想让控件支持wrap_content属性必须重写onMeasure()方法来指定大小。
通过MeasureSpec这一个类,我们就获取了View的测量模式和View想要绘制的大小。有了这些信息,就可以控制View最后显示的大小。
对View进行测量,需要重写View的onMeasure()方法,代码如下

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec));
}

private int measureHeight(int measureSpec) {
    int result = 0;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);

    if (specMode==MeasureSpec.EXACTLY){
        result = specSize;
    }
    else{
        result = 200;
        if (specMode==MeasureSpec.AT_MOST){
            result = Math.min(result,specSize);
        }
    }
    return result;
}

private int measureWidth(int measureSpec) {
    int result = 0;
    int specMode = MeasureSpec.getMode(measureSpec);
    int specSize = MeasureSpec.getSize(measureSpec);

    if (specMode==MeasureSpec.EXACTLY){
        result = specSize;
    }
    else{
        result = 200;
        if (specMode==MeasureSpec.AT_MOST){
            result = Math.min(result,specSize);
        }
    }
    return result;
}

对代码的解释:

  1. 在onMeasure方法中,调用自定义的measureWidth()和measureHeight()方法,分别对宽高进行重新定义,参数是宽和高的MeasureSpec对象。
  2. 在自定义方法中,从MeasureSpec对象中提取出具体的测量模式和大小
  3. 通过判断测量的模式,给出不同的测量值。当为EXACTLY时直接指定specSize即可
  4. 当为其他两种模式时,需要给一个默认的大小。
  5. 特别的如果指定为wrap_content即AT_MOST模式,需要与specSize中较小的一个来作为最后的测量值。

三、View的绘制

当测量好一个View之后,简单地重写onDraw()方法,并在Canvas对象上来绘制所需要的图形。
重写的onDraw()方法中有一个参数,也即就是Canvas对象。使用这个对象就可以绘图了;如果在其他地方创建new一个Canvas,需要传入一个bitmap对象,即装载画布。
依靠这个bitmap创建的Canvas与bitmap紧紧联系,所有的Canvas.drawXxx()方法都发生在这个bitmap上。

四、自定义View

在自定义View时,通常会去重写onDraw()方法来绘制View的显示内容。如果该View还需要wrap_content属性,那么还必须重写onMeasure()方法。另外通过自定义attrs属性,还可以指定新的属性配置值。在View中通常有以下比较重要的回调方法。

onFinishflate() //从XML加载组件后回调
onSizeChanged() //组件大小改变时回调
onMeasure() //回调该方法来进行测量
onLayout() //回调该方法来确定显示的位置
onTouchEvent() //监听到触摸事件时回调

通常情况下,不需要重写所有的方法,只需要重写特定条件的回调方法即可。一般有以下三种方法来实现自定义的控件:

(1)对现有控件进行拓展
一般来说,我们可以在onDraw()方法中对原生控件行为进行拓展。
重写onDraw()方法,程序调用super.onDraw(canvas)方法来实现原生控件的功能。但是在之前和之后都可以实现自己的逻辑,分别在系统绘制文字前后,完成自己的操作。

@Override
protected void onDraw(Canvas canvas) {
    //在回调之前实现自定义逻辑,如果对TextView来说即是绘制文本内容之前
    super.onDraw(canvas);
    //在回调之后实现自定义逻辑,如果对TextView来说即是绘制文本内容之后
}

(2)通过组合实现复合控件
创建复合控件可以很好的创建出具有重用功能的控件集合。这种方式通常都需要一个合适的ViewGroup,再给它添加指定功能的控件,从而组合成新的复合控件。具体用法如下:

  1. 定义属性:只需要在res资源目录下创建一个属性定义xml文件,然后在<declare-styleable标签下通过<attr标签指定属性。
  2. 创建Java类继承需要的ViewGroup,使用以下代码获取在XML布局文件中的自定义属性
    TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.控件名)
    并在Java代码构造方法中完成定义属性的赋值,最后获取完所有的属性值后,要调用TypedArray的recyle方法完成资源的回收
  3. 组合控件:将需要添加进复合控件布局的控件获取实例后,设置前面所获取的具体属性值,然后使用addView()模板添加到定义的复合控件模板中
  4. 如果要使用控件的点击事件,为了实现不同的功能,不能直接在UI模板中添加具体的实现逻辑,只能通过接口回调的思想,将具体的实现逻辑交给调用者
  5. 引用UI模板:在引用前,需要指定引用第三方控件的名字空间。如果使用自定义属性,就需要创建自己的命名空间;使用自定义的view需要在声明控件时指定完整的包路径。

(3)重写View来实现全新的控件
创建一个全新的自定义控件难点在于绘制控件和实现交互,通常需要继承View类,重写它的onDraw()、onMeasure()方法来实现绘制逻辑,同时通过重写onTouchEvent()等触控事件来实现交互逻辑。当然还可以像实现控件方式那样通过引入自定义属性丰富自定义View的可定制性。

五、自定义ViewGroup

ViewGroup存在的目的就是为了对其子View进行管理,为其子View添加显示、响应的规则。自定义ViewGroup需要重写onMeasure()方法来对子View进行测量,重写onLayout()方法来确定子View的位置,重写onTouchEvent()方法来增加响应时间。

六、事件拦截机制

在事件传递中,我们只关心onInterceptTouchEvent()方法,而dispatchTouchEvent()虽然是事件分发的第一步,但一般情况下,不太会改写这个方法。事件处理都是执行onTouchEvent()方法。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-05 11:07:57  更:2021-09-05 11:09:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:46:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码