【5年Android从零复盘系列之六】Android自定义View(1):基础详解(图文)
发布日期:2021-06-29 18:17:35 浏览次数:2 分类:技术文章

本文共 6567 字,大约阅读时间需要 21 分钟。

1.基础一:坐标计算

1.1 Android窗口坐标系计算以屏幕左上角为原点,

向右为X轴正向,向下为Y轴正向

1.2 View坐标系

【注意获取的坐标是像素值,不是dp值】

【注意获取的坐标是像素值,不是dp值】
【注意获取的坐标是像素值,不是dp值】

//获取View内部相对的坐标值(距离)getX()、getY()//获取View相对父View的相对坐标值(距离)getLeft()、getTop()、getRight()、getBottom()//获取的是屏幕中的实际坐标值(距离)getRawX()、getRawY()

图中activity指全屏窗口,严格的讲应该是屏幕

1.3 实际开发使用场景

1.获取View的宽高【应在View绘制完成后调用

width = getRight() - getLeft();height = getBottom() - getTop();

2.获取View在父view中的左上角坐标【应在View绘制完成后调用

Point point = new Point();point.set(ivState.getLeft() ,ivState.getTop());

3.获取View在父view中心点坐标【应在View绘制完成后调用

Point point = new Point();point.set(ivState.getRight() - ivState.getLeft() ,ivState.getBottom() - ivState.getTop());

2. 自定义属性

2.1 构造函数&初始化属性

public class MDButton extends Button {
//java动态创建view时调用 public MDButton(Context context) {
super(context); initInnerView(context); } //xml布局初始化时调用 public MDButton(Context context, AttributeSet attrs) {
super(context, attrs);// initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用 initAttrs(context, attrs); } //有默认style时,在MDButton(Context context, AttributeSet attrs)中调用MDButton(context,attrs,defStyleAttr); public MDButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);// initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用 initAttrs(context, attrs); } //只有在API版本>21时才会用到 //有默认style时,在MDButton(Context context, AttributeSet attrs)中调用MDButton(context,attrs,defStyleAttr); @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public MDButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);// initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用 initAttrs(context, attrs); } //组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用 private void initInnerView(Context context) {
//... } private void initAttrs(Context context, AttributeSet attrs) {
//... }}

2.2 自定义属性

1.在module中的/res/values/attrs.xml编写属性&类型;

2.自定义View类中获取属性值,并使用

public class MDButton extends Button {
//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用 private void initInnerView(Context context) {
//... } private void initAttrs(Context context, AttributeSet attrs) {
//1.获取属性数组 TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MDButton); //2.获取属性值 Drawable bgDrawable = typedArray.getDrawable(R.styleable.MDButton_mdb_bg); int txtColor = typedArray.getInteger(R.styleable.MDButton_mdb_txt_color,Color.parseColor("#808080")); String txt = typedArray.getString(R.styleable.MDButton_mdb_txt); boolean isAutoAnim = typedArray.getBoolean(R.styleable.MDButton_mdb_auto_anim, false); float fraction = typedArray.getFraction(R.styleable.MDButton_mdb_anim_pivotX, 1, 1, 1.0f); float alpha = typedArray.getFloat(R.styleable.MDButton_mdb_auto_anim_alpha , 1.0f); float minWidth = typedArray.getDimension(R.styleable.MDButton_mdb_min_width, 32.0f); int sizeType = typedArray.getInt(R.styleable.MDButton_mdb_size, 1);//0=small 1=normal 2=big int radiusCorner = typedArray.getInt(R.styleable.MDButton_mdb_radius_corner ,0); int delay = typedArray.getInt(R.styleable.MDButton_mdb_auto_anim_delay ,0); Log.e("bgDrawable",""+bgDrawable); Log.e("txtColor",""+txtColor); Log.e("txt",""+txt); Log.e("isAutoAnim",""+isAutoAnim); Log.e("fraction",""+fraction); Log.e("alpha",""+alpha); Log.e("minWidth",""+minWidth); Log.e("sizeType",""+sizeType); Log.e("radiusCorner",""+radiusCorner); Log.e("delay",""+delay); Log.e("==============","========================================="); //3.属性值 设置到 对应属性 setText(txt); //tv.setDelay(delay); //... //4.释放 typedArray.recycle(); } //java动态创建view时调用 public MDButton(Context context) {
super(context); initInnerView(context); } //xml布局初始化时调用 public MDButton(Context context, AttributeSet attrs) {
super(context, attrs);// initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用 initAttrs(context, attrs); } //有默认style时,在MDButton(Context context, AttributeSet attrs)中调用MDButton(context,attrs,defStyleAttr); public MDButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);// initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用 initAttrs(context, attrs); } //只有在API版本>21时才会用到 //有默认style时,在MDButton(Context context, AttributeSet attrs)中调用 @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public MDButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);// initInnerView(context);//组合式自定义View(即ViewGroup)时,需初始化内部子view; 扩展式自定义View不需要调用 initAttrs(context, attrs); }}

3.在布局文件.xml中使用控件,【注意变量组设置的数据&单位】

** 附 :属性值获取正确性验证**

3.自定义View分类

3.1 组合式

顾名思义,即xml文件中根布局使用RelativeLayout(同理其他布局控件),

内部使用其他View控件,布局摆放,组合成XxxView的原始布局。
然后,Java类继承根布局标签对应的容器类,覆写构造函数,并初始化各子View的变量。
是最常用、最稳妥、不易产生过度绘制、内存泄漏等问题。

3.2 继承覆写、衍生/扩展

简而言之,即 如继承Button,修改默认background、state_press状态时按钮elevation值、取消默认最小高度56dp等。

也是最常用的、直接扩展/修改原生View功能

3.3 自绘式

强烈建议:熟悉View的绘制、Android事件传递、手势处理再入手自绘式。

方式:直接继承View ,重写绘制流程三步骤

  1. measure() 测量
  2. layout() 布局计算摆放坐标
  3. draw() 绘制

4.View的生命周期

View的生命周期,关联Activity联动时的函数调用顺序

  1. 【View】构造方法
  2. 【View】onFinishInflate()
  3. 【Activity】 onCreate()
  4. 【Activity】onStart()
  5. 【Activity】onResume()
  6. 【View】onAttachedToWindow()
  7. 【View】onMeasure() (可能调用n次)
  8. 【View】onSizeChanged() (可能调用n次)
  9. 【View】onLayout() (可能调用n次)
  10. 【View】onDraw() (可能调用n次)
  11. 【View】onWindowFocusChanged() (调用Activity.onPause()前,被调用,hasWindowFocus==false)
  12. 【Activity】onPause()
  13. 【Activity】onStop()
  14. 【Activity】onDestroy()
  15. 【View】onDetachedFromWindow

转载地址:https://cupster.blog.csdn.net/article/details/112055331 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:【5年Android从零复盘系列之七】Android自定义View(2):组合式详解(图文)
下一篇:【5年Android从零复盘系列之五】关于页面布局控件开发总结

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2024年04月20日 13时25分37秒