当前位置: 首页 > 后端技术 > Java

Android中的自定义View(一)

时间:2023-04-02 01:16:44 Java

PS:本文为转载文章,原文可读性会更好,文末有原文链接ps:本文基于关于AndroidAPI31的分析,文中写的demo是用AndroidStudio工具开发的。目录1.自定义View的分类2.自定义View的注意事项3.自定义View的例子1.自定义View的分类自定义View的分类目前还没有统一的标准。基于学习的积累,我将自定义View规划为以下四类。(1)直接继承View直接继承View绘制一些不规则的视图,需要通过绘制来实现,即重写View的onDraw方法;直接继承View的子类需要自己处理wrap_content(参见Android中View工作流的measure过程一文,如果自定义View直接继承View而不处理wrap_content,那么效果和match_parent一样)和padding,否则效果和我们实现的不一样。(2)该方法直接继承自ViewGroup,用于实现自定义布局,如LinearLayout、RelativeLayout等,属于系统布局。如果我们需要重新定义一个新的布局,我们可以使用这个方法来实现,比如layout的时候可以左右(可以把ViewPager想成是自定义布局)并且还会产生水波纹效果,实现起来就有点复杂了使用此方法。需要妥善处理好ViewGroup的测量和布局两个过程,同时处理好子Element的测量和布局过程。(3)直接继承自具体的View(如TextView)扩展某个View的功能,如TextView,是Button继承的,主要用于设置点击事件;直接继承自具体的View,不需要自己处理wrap_content和padding。(4)直接继承特定的ViewGroup(如FrameLayout)。如果某个效果看起来与某个ViewGroup非常相似,即当某个ViewGroup布局子元素的特性非常相似时,可以使用这种方法来实现,采用这种方法不需要处理这两个过程自己测量和布局ViewGroup。自定义View的显示效果有很多种方式。你喜欢用哪一个取决于开发者自己的喜好。好了,说说自定义View的时候应该注意的一些事情。2、自定义View注意事项(1)直接继承自View或ViewGroup,使用wrap_content值时,必须支持wrap_content;如果在onMeasure中没有对wrap_content进行特殊处理,那么当自定义View或者自定义ViewGroup放在layout中时,wrap_content就无法达到预期的效果,所以我们看到的是和match_parent一样的效果。可以看Android中View工作流的measure过程的文章,可以看到和match_parent一样的效果。(2)如果直接继承View并使用padding,如果padding没有在draw方法中处理,那么padding属性就不起作用;如果直接继承ViewGroup并使用wrap_content,则需要在onMeasure和onLayout方法中处理padding,以及子View的margin对其有影响。(3)不要在自定义View中创建Handler,因为View提供了一系列的post方法,View的一系列post方法实际上调用了Handler的一系列post方法。(4)当View变为不可见时,我们需要停止线程和动画。这种情况如果不处理,很容易造成内存泄漏;如果有线程或者动画需要停止,最好在View的onDetachedFromWindow方法中调用,因为当Activity退出或者View被删除时,View的onDetachedFromWindow方法就会执行。(5)如果View中存在滑动冲突,应妥善处理滑动冲突,否则会影响用户体验效果;滑动冲突的内容可以参考Android中View的滑动冲突一文。3、自定义View的例子这里我们写一个直接从View继续的case,我们会画一个椭圆,步骤如下;(1)写一个EllipseView,继承View;包com.xe.myapplication4;导入android.content.Context;导入android.content.res.TypedArray;导入android.graphics.Canvas;导入android.graphics.Color;导入android.graphics.Paint;导入android.graphics.Path;importandroid.graphics.RectF;importandroid.support.annotation.Nullable;importandroid.util.AttributeSet;importandroid.view.View;importandroid.view.WindowManager;/**由86188于2022/7/7创建.*/publicclassEllipseViewextendsView{Paintp;privateintcolor;publicEllipseView(Contextcontext,@NullableAttributeSetattrs){super(context,attrs);初始化(上下文,属性);}publicEllipseView(上下文上下文,@NullableAttributeSetattrs,intdefStyleAttr){init(context,attrs);}privatevoidinit(Contextcontext,@NullableAttributeSetattrs){p=newPaint();TypedArrayta=context.obtainStyledA属性(属性,R.styleable.EllipseView);//1、color=ta.getColor(R.styleable.EllipseView_ellipse_view_color,Color.GREEN);ta.recycle();}@OverrideprotectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){super.onMeasure(widthMeasureSpec,heightMeasureSpec);intwidthSpecMode=MeasureSpec.getMode(widthMeasureSpec);intwidthSpecSize=MeasureSpec.getSize(widthMeasureSpec);intheightSpecMode=MeasureSpec.getMode(heightMeasureSpec);intheightSpecSize=MeasureSpec.getSize(heightMeasureSpec);//2、if(widthSpecMode==MeasureSpec.AT_MOST&&heightSpecMode==MeasureSpec.AT_MOST){setMeasuredDimension(200,150);//3、}elseif(widthSpecMode==MeasureSpec.AT_MOST){setMeasuredDimension(200,heightSpecSize);//4、}elseif(heightSpecMode==MeasureSpec.AT_MOST){setMeasuredDimension(widthSpecSize,150);}}@OverrideprotectedvoidonDraw(画布画布){super.onDraw(画布);//5。intleftPadding=getPaddingLeft();intrightPadding=getPaddingRight();inttopPadding=getPaddingTop();intbuttomPadding=getPaddingBottom();intwidth=getMeasuredWidth();getMeasuredHeight();intwidth2=width-rightPadding;intheight2=height-buttomPadding;p.setColor(颜色);p.setAntiAlias(true);RectFrectF=newRectF();rectF.set(leftPadding,topPadding,width2,height2);canvas.drawOval(rectF,p);}}(2)在values目录下创建一个attrs.xml文件,自定义一个ellipse_view_color属性,格式为颜色类型,其值为颜色值;picture图片(3)自定义xml中View的布局;图片说明:1)见注1,是解析自定义属性的ellipse_view_color值,如果xml布局文件中没有使用该属性,则默认为绿色2)见注2、3、4、处理wrap_content模式,width为wrap_content模式时,设置width为200;当height为wrap_content模式时,设置height为150。3)见注5,获取top、bottom、left、right的padding,HandlepaddingwhendrawingcustomView。4)看Note6中的ellipse_view_color属性,有没有app前缀?这是自定义属性的flag,使用自定义属性时必须在xml布局文件中加入schemas声明:xmlns:app="http://schemas.android.com/apk/res-auto"。程序运行结果如下;图片