请选择 进入手机版 | 继续访问电脑版

自定义视图组件流程

[复制链接]
为你演绎 发表于 2021-1-1 18:33:13 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题
一、前言

Android提供了一个复杂且强大的组件化模子,帮我我们根据布局类View和ViewGroup来构建界面。Button、TestView、EdiText,LinearLayout、FrameLayout、RelativeLayout 等,然而在开辟过程,一些系统通过的控件不能满意我们的要求,因此需要我自界说视图组件。
二、自界说视图组件的方式


  • 完全自界说视图组件,继续View或者ViewGoup来完成
  • 复合控件,团结现有的视图组件组合为满意我们需求的控件
  • 修改现有的View范例,好比继续自ImageView,TextView,EditText,根据要求重写相应的方法来完成
自界说视图组件用上面的三种方式根本满意我们要求,其中实现过程的复杂度由我们具体的功能来定,但一些根本的流程稳定,接下来通过一个绘制水杯的实例来相识自界说View的流程。
三、自界说View的流程

3.1 创建自界说视图类

  1. public class WaterView extends View {    public WaterView(Context context) {        super(context);    }    public WaterView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);    }    public WaterView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }}
复制代码
3.2 界说自界说属性

如果需要自界说属性,需要向项目中添加 资源。这些资源通常放在res/values/attrs.xml文件中。如下所示:
  1.                
复制代码
界说好属性后,接下来我们可以像内置属性一样在布局XML文件中使用他们。唯一的区别是自界说属性属于另一个命名空间。他们不属于 http://schemas.android.com/apk/res/android 命名空间,而是属于http://schemas.android.com/apk/res/[your package name]。如下所示:
  1.    
复制代码
这里为了避免反复使用冗长的命名空间URI,我们使用xmlns指令。此指令将别名app分配给命名空间http://schemas.android.com/apk/res-auto,改别名可以为任何别名,只要同一个文件不相同即可。
3.3 获取自界说属性

通过XML创建布局视图时,XML标志的所有属性都会从资源包读取,并作为AttributeSet传递到视图的构造函数。
Android资源编译器做了大量的工作,context.getTheme().obtainStyledAttributes()得到个TypeArray数组,其中包罗已解除引用并设置了样式的值。对应res目录中的各个资源,生成的R.java界说一个由属性ID组成的数组,同时界说一组常量,用于界说改数组中各属性的索引。我们可以按照下面的方法从TypeArray中读取属性值。
  1. public WaterView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.WaterView, 0, 0);    try {        color = typedArray.getColor(R.styleable.WaterView_color, DEFAULT_COLOR);    } finally {        typedArray.recycle();    }}
复制代码
Note:TypedArray 对象是共享资源,必须在使用后接纳。
3.4 处置惩罚布局巨细

为了正确绘制自界说视图,我们需要知道他有多大。View提供多种丈量方法,如果想要更精致地控制视图布局参数,需要重写onMeasure()方法,如果不需要对视图巨细举行控制,只需要重写onSizeChanged()方法。
系统会在首次为您的视图分配巨细时调用 onSizeChanged(),如果视图巨细由于任何原因而改变,系统会再次调用该方法。可在该方法中盘算位置、尺寸以及其他与视图巨细相关的任何值,而不是在每次绘制时都重新盘算。如下所示,我们可以在下面的方法中获取视图的高宽以及盘算水位的竣事Y坐标
  1. @Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);    viewWidth = w;    viewHeight = h;    waterEndYpx = viewHeight - waterPx;}
复制代码
onMeasure()可以更精致的控制布局参数。该方法参数是View.MeasureSpec值,用于告诉父视图希望子视图有多大,以及该巨细是硬性最大值照旧发起值。在实际开辟中,我们可以根据以下代码得到specMode和specSize
  1.     int specMode = MeasureSpec.getMode(measureSpec);    int specSize = MeasureSpec.getSize(measureSpec);
复制代码
这里的specMode有三个值:

  • MeasureSpec.UNSPECIFIED:The parent has not imposed any constraint
    on the child. It can be whatever size it wants;父视图没有对子视图添加任何约束,子视图可以任意巨细。
  • MeasureSpec.EXACTLY:The parent has determined an exact size
    for the child. The child is going to be given those bounds regardless
    of how big it wants to be;父视图决定子视图简直切巨细,子视图被限定在给定的界限里,忽略自己想要的巨细。
  • MeasureSpec.AT_MOST:The child can be as large as it wants up
    to the specified size.;子最大视图可以达到指定的巨细。
我们按照下面的代码模式,分别设置WaterView以及父视图layout_width来探讨onMeasue中获取到的specMode和specSize。这里的specMode和specSize按照下面的方式归去
  1.     int specMode = MeasureSpec.getMode(measureSpec);    int specSize = MeasureSpec.getSize(measureSpec);
复制代码
  1.                
复制代码
下图只展示更改layout_width的厘革,layout_height厘革和layout_width雷同:
[tr][/tr]
父视图-layout_widthWaterView-layout_widthWaterView-specModeWaterView-specSize
wrap_contentwrap_contentMeasureSpec.AT_MOST1080px
match_parentMeasureSpec.AT_MOST1080px
100dpMeasureSpec.EXACTLY300px
match_contentwrap_contentMeasureSpec.AT_MOST1080px
match_parentMeasureSpec.EXACTLY1080px
100dpMeasureSpec.EXACTLY300px
50dpwrap_contentMeasureSpec.AT_MOST150px
match_parentMeasureSpec.EXACTLY150px
100dpMeasureSpec.EXACTLY300px
那么在实际的开辟中我们拿到specMode和specSize做什么用呢?更多是为setMeasuredDimension()使用,如果我们view的巨细高出specSize。我们就可以根据specMode和specSize来举行裁剪、滚动、换行等利用,从而盘算View的精确巨细。
3.5 控制子View位置

对子View的位置举行控制主要是针对ViewGrop视图,如果添加了多个子View,那么我就需要功能以及丈量的巨细对子View的位置举行确定。这里需要重写onLayout方法,盘算好子view的left、top、right、bottom后,调用view.layout()确定子view的位置。
3.6 自界说绘制

自界说视图最重要的部分是外观。绘制自界说视图可能很简朴,也可能横复杂,具体取决于具体的需求。
要实现自界说视图的外观效果,我们需要重写onDraw()方法,利用Canvas举行绘制。
android.graphics 框架将绘制分为两个方面:


  • 需要绘制什么,有Canvas处置惩罚。
  • 如何绘制,由Paint处置惩罚。
比方,Canvas提供了drawLine()绘制线的方法,那么就需要Paint对象设置颜色,最后绘制出一条指定颜色的线条。
如果视图非常频仍地重新绘制,那么onDraw()会不绝的执行,因此我们就不能再onDraw()内里做一些对象的创建,需要对象的创建提前到类的构造函数中,这样可以避免内存抖动带来的界面卡顿问题。我们可以按照以下方式举行对象的构建。
  1. public class WaterView extends View {    private Paint paintWater;    private RectF rectF;         public WaterView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);        init()    }    ......        private void init() {        paintWater = new Paint();        paintWater.setColor(color);        paintWater.setAntiAlias(true);        rectF = new RectF();    }}   
复制代码
最后在onDraw()中完成绘制
  1.     @Override    protected void onDraw(Canvas canvas) {        rectF.set(0,viewHeight/2,viewWidth,viewHeight);        canvas.drawRect(rectF,paintWater);    }
复制代码
参考:

官网参考文档

来源:https://blog.csdn.net/mrRuby/article/details/112047003
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

发布主题

专注素材教程免费分享
全国免费热线电话

18768367769

周一至周日9:00-23:00

反馈建议

27428564@qq.com 在线QQ咨询

扫描二维码关注我们

Powered by Discuz! X3.4© 2001-2013 Comsenz Inc.( 蜀ICP备2021001884号-1 )