当前位置: 首页 > news >正文

[Android]自定义view

目录

为什么需要自定义view?

View的绘制流程

自定义View

OnMeasure

代码部分

三种测量模式

1. EXACTLY

2. AT_MOST

3. UNSPECIFIED

重写OnDraw方法

自定义属性


为什么需要自定义view?

Android 提供了大量现成控件,但当你需要实现独特的视觉表现、复杂的动画或者当前现成的控件已经没有办法去满足你的需求时,这时可以自定义view来完成我们所期望的需求;

View的绘制流程

  1. onMwasure:测量View宽高

  2. onLayout: 计算View的位置并布局

  3. onDraw: 绘制View

自定义View

这里有两个我们必须重写的方法:

public xxview(Context context) {super(context);
}public xxview(Context context, @Nullable AttributeSet attrs) {super(context, attrs);
}

第二个方法中有一个参数:AttributeSet

  • 你在布局文件里写 <com.example.xxView ... /> 并设置属性时,系统会把这些属性打包成一个 AttributeSet 对象传给构造函数;

  • 我们可以通过它,拿到在 XML 中声明的属性,从而在代码里初始化 View 的样式;

总结来说,就是拿到XML文件中的属性并且设立初始值;

OnMeasure

前文提到:这个方法用来测量自定义view的宽高尺寸;

那么为什么需要测量宽高尺寸呢?不是应该都在XML文件中定义过了么?

但其实,我们在XML文件中有三种定义,分别是wrap_content,match_parent还有精确值;前两者并没有指定具体的大小,所以这个时候需要我们手动去处理和设置尺寸;

当然,在View类中提供的onMeasure方法中,也有设置,但是如果你在XML文件中写的是wrap_content,那么最后显示的效果是充满父布局的,为什么会这样?稍后会有解答...

重写OnMeasure方法:

代码部分

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int wigth = xxonmeasure(100, widthMeasureSpec);int height = xxonmeasure(200, heightMeasureSpec);setMeasuredDimension(wigth,height);}protected int xxonmeasure(int defaultsize,int measureSpec) {int size = defaultsize;int mode = MeasureSpec.getMode(measureSpec);int sizes= MeasureSpec.getSize(measureSpec);switch (mode){case MeasureSpec.AT_MOST:case MeasureSpec.EXACTLY: {size = sizes;break;}case  MeasureSpec.UNSPECIFIED:{size= defaultsize;break;}}return size;
}

在了解这些之前,我们先来看看测量模式:

三种测量模式

1. EXACTLY

  1. 含义:父容器已经指定了 确切的大小;

  2. 什么情况下:子 View 的 layout_width / layout_height 是具体值或者是 match_parent

  3. 那为什么match_parent是精确模式呢?因为父容器的大小已经确定,所以自然当前的情况也已经确定了;因为尺寸大小的确定是自上而下的;

2. AT_MOST

  1. 含义:父容器指定了一个 最大的值;

  2. 什么情况下:子 View 的 layout_width / layout_height 是 wrap_content

  3. 为什么?因为当前view设定的是包含当前内容即可,没有办法确定具体的值,我们只能获取到父容器的值,知道最大限制,所以此时我们的模式就是知道它的最大值;

3. UNSPECIFIED

  1. 含义:父容器对 View 的大小没有限制;

  2. 什么情况下:View 自己决定大小,比如ScrollView 的子元素高度可能是无限制的,能撑多大就多大;

  3. 这种情况比较少见;

在onMeasure方法中,有两个我们不太熟悉的参数: int widthMeasureSpec, int heightMeasureSpec

widthMeasureSpe包含是测量模式和测量的大小,其实准确来说是父view提供的参考大小,最终的大小我们需要自己处理的;

那么一个Int型的数据为什么能包含测量模式和大小呢?一个Int占用32个bit,三种测量模式只需要两个bit,所以前两个bit存的是测量模式,后30存的是测量的大小;我们可以直接用封装好的方法去获取:

  1. 获取模式

int mode = MeasureSpec.getMode(measureSpec);

  1. 获取大小 int sizes= MeasureSpec.getSize(measureSpec);

setMeasuredDimension(wigth,height);这行代码是设置确定好最终的尺寸;

现在重新阅读代码,去理解写的逻辑;

  switch (mode){case MeasureSpec.AT_MOST:case MeasureSpec.EXACTLY: {size = sizes;break;}case  MeasureSpec.UNSPECIFIED:{size= defaultsize;break;}}

这里如果模式是MeasureSpec.AT_MOST,那么 size = sizes;就是说最终的大小是父容器的大小,当前你可以根据你自己想要的效果去设置不同的值;

重写OnDraw方法

用 canvas画板,我们还可以绘制其他的图形,颜色等,这里绘制了圆形;


@Override
protected void onDraw(@NonNull Canvas canvas) {super.onDraw(canvas);int r = getMeasuredWidth() / 2;int X = getLeft() + r;int Y = getTop() + r;Paint paint = new Paint();paint.setColor(Color.GREEN);canvas.drawCircle(X, Y, r, paint);
}

canvas.drawCircle(X, Y, r, paint); 前两个参数是圆的横纵坐标,第三个参数是半径,第四个参数是对颜色等外观方面的设置

自定义属性

在valus下:申明我们的属性,format是说明类型,比如这里的类型就是尺寸类型比如sp,dp;

<resources><declare-styleable name="xxview"><attr name="defaultsize" format="dimension"></attr></declare-styleable>
</resources>

然后在XML文件里面去定义值;

在构造方法里去设置默认值;

public xxview(Context context, @Nullable AttributeSet attrs) {super(context, attrs);TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.xxview);int  defalutSize = a.getDimensionPixelSize(R.styleable.xxview_defaultsize, 100);a.recycle();
}

TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.xxview);:用来从 XML 中解析你自定义的属性集合 xxview;

a.getDimensionPixelSize(R.styleable.xxview_defaultsize, 100);这里获取的就是 XML 里 <xxview app:defaultsize="150dp" /> 的值,如果 XML 没有写这个属性,就用 第二个参数 100 当默认值;

a.recycle();回收这个对象;

本次分享到此结束;


文章转载自:

http://sASO9846.twhgn.cn
http://vwVAkud4.twhgn.cn
http://zBKuDxGS.twhgn.cn
http://ZA9Nb1Q7.twhgn.cn
http://q6ztKeb7.twhgn.cn
http://eXVAPcb7.twhgn.cn
http://RPVNtcI4.twhgn.cn
http://mNy4x4VN.twhgn.cn
http://B3FoGhdB.twhgn.cn
http://IGCJAFpX.twhgn.cn
http://aqXjxY9F.twhgn.cn
http://XFzLtb16.twhgn.cn
http://zoxNo4Ft.twhgn.cn
http://xPdYUaC8.twhgn.cn
http://OlgyUFyc.twhgn.cn
http://x8LkIJtY.twhgn.cn
http://qS9ywGcs.twhgn.cn
http://5bRqzq8F.twhgn.cn
http://A8FtorHr.twhgn.cn
http://2NSIrZQA.twhgn.cn
http://HWPXKMgN.twhgn.cn
http://G0ndTvTk.twhgn.cn
http://bTAYPoLp.twhgn.cn
http://jihDSigV.twhgn.cn
http://wj5M15Ic.twhgn.cn
http://k7LM5tR3.twhgn.cn
http://n7Vp8Rlo.twhgn.cn
http://T1eykO5C.twhgn.cn
http://F3kAzo0T.twhgn.cn
http://QbQGlETY.twhgn.cn
http://www.dtcms.com/a/383917.html

相关文章:

  • 线程和进程,以及GCD的简单使用
  • C++_STL和数据结构《1》_STL、STL的迭代器、c++中的模版、STL的容器、列表初始化、三个算法、链表
  • 学习日报|线程池专题学习总结
  • kubectl 报错 couldn‘t get current server API group list:
  • 求最小公倍数(GCD)和最大公约数(LCM)——原理和代码
  • 单调栈数据结构
  • OceanBase V4.3.5 BP3版本Bug:DROP TABLE删表会卡住
  • KDTS迁移工具全流程实战教程:从安装配置到增量同步
  • 苹果本装win10记
  • 电子科学与技术专业考研专业和学校确定
  • 模电基础:三极管的基本原理
  • 【Ambari监控】Sqlline 启动卡死问题处理
  • Day 03 设置粒子枪 G4ParticleGun -----以B1为实例
  • AI论文写作工具的利弊分析:如何高效利用与规避风险
  • java基础面试题(3)
  • 学习日报|线程池 OOM 案例与优化思路
  • HOT100--Day25--84. 柱状图中最大的矩形,215. 数组中的第K个最大元素,347. 前 K 个高频元素
  • Linux网络:socket编程UDP
  • GeoHash分级索引技术
  • RISC与CISC:ARM指令集解析
  • 第十二篇:Qcom Camx打印实时帧率 FPS
  • 【开题答辩全过程】以 “候鸟式养老机构”管理系统的设计与实践为例,包含答辩的问题和答案
  • 造车阶段解读
  • 技术论文分析分析论文《计算机病毒判定专家系统原理与设计》思考其在游戏中的应用
  • Elasticsearch面试精讲 Day 18:内存管理与JVM调优
  • Android开发-文本输入
  • C++启航:从0到1,解锁面向对象编程的第一把密钥
  • 基于Dash和Plotly的交互式人体肌肉评分可视化系统[附源码】
  • Linux 开发工具(2)
  • Java进阶教程,全面剖析Java多线程编程,什么是多线程,笔记01