博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android:绘制自定义视图
阅读量:4044 次
发布时间:2019-05-24

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

介绍

每天我们使用各种应用程序,尽管他们的不同意图,大多数是非常相似,甚至相似的设计。这就是为什么很多客户要求特定的,自定义的布局和外观,没有其他应用程序还没有体现,以使Android应用程序的独特性和与其他人的对比。
如果一个特定的功能需要一个非常定制的功能,不能创建android内置视图? - ?然后来自定义视图绘制。在大多数情况下,这意味着需要很长时间才能完成它。但它的确意味着我们不应该这样做,此外,它是非常令人兴奋和有趣的实施。
我最近遇到了类似的情况:我的任务是为Android ViewPager创建一个页面指示器。不像iOS,Android不提供这样的视图,所以我不得不实现它作为一个自定义。
我花了相当多的时间试图实现它。幸运的是,视图在现在的项目中是可重复使用的,所以为了节省个人时间和其他开发人员的时间,我决定根据该视图创建一个公共库。如果你有类似的功能,没有时间自己实现它,然后在github repo找到它。

使用PageIndicatorView的示例

画!

好吧,由于大多数自定义视图比常规视图更耗时,您应该只有在没有更简单的方法来实现特定功能或您有以下问题,自定义视图可以解决:
性能。如果在布局中有很多视图,并且想要通过绘制单个自定义视图以使其更轻,进行优化。
大视图层次结构,操作和支持复杂。
需要手动绘制的完整自定义视图。
如果你没有尝试制定一个自定义视图,那么这篇文章是一个很好的机会,以更接近绘制自己的平面自定义视图。它将显示整体视图结构,如何实现具体的事情,如何避免常见的错误,甚至如何动画你的观点!
我们需要做的第一件事是跳转到View生命周期。由于某种原因,Google没有提供视图生命周期的官方图表,因此开发人员之间相当普遍的误解,导致意想不到的错误和问题,因此我们关注它!

构造函数

每个视图开始它的生命从构造函数。它给了我们,是一个很好的机会来准备一个初始绘图,进行各种计算,设置默认值或任何我们需要的。
但是为了使我们的视图易于使用和设置,有一些有用的AttributeSet接口。它很容易实现,绝对值得花时间,因为它将帮助您(和您的团队)在更多的屏幕上使用一些静态参数设置您的视图。
首先,创建一个新文件并将其命名为attrs.xml。在该文件中可以是不同自定义视图的所有属性。正如你可以看到在这个例子中,我们有一个视图称为PageIndicatorView和单一属性piv_count。
自定义属性示例
在你的View构造函数中,你需要获取属性并使用它,如下所示。
public PageIndicatorView(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.PageIndicatorView);
    int count = typedArray.getInt(R.styleable.PageIndicatorView_piv_count,0);
    typedArray.recycle();
}

自定义视图检索属性

注意:
创建自定义属性时会创建一个简单的前缀,以避免具有类似属性名称的其他视图之间的名称冲突。主要是视图名称的缩写,就像我们有piv_。

如果你使用Android Studio,Lint会建议你调用recycle()方法,只要你完成你的属性。原因是为了摆脱无效的绑定数据,不会再次使用。

onAttachedToWindow

父视图调用addView(View)后,该视图将附加到一个窗口。在这个阶段,我们的观点将知道其它观点被它包围。如果你的视图使用位于同一layout.xml中的用户的其他视图,它是通过id(你可以通过属性设置)和保存为全局引用(如果需要)找到它们的好地方。

onMeasure

意味着我们的自定义视图是在舞台上,以找出它自己的大小。这是非常重要的方法,因为在大多数情况下,您将需要您的视图具有适合您的布局的特定大小。
在覆盖此方法时,您需要执行此操作是设置setMeasuredDimension(int width,int height)。
在设置自定义视图的大小时,您应该处理大小写,该视图可以具有特定大小,用户将在layout.xml中或以编程方式设置。要正确计算,需要完成几个步骤。
计算您的视图内容所需的大小(宽度和高度)。
获取您的视图MeasureSpec(宽度和高度)的大小和模式。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    }
自定义视图MeasureSpec
3.检查MeasureSpec模式,用户设置和调整视图的大小(宽度和高度)。
int width;
if (widthMode == MeasureSpec.EXACTLY) {
  width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
  width = Math.min(desiredWidth, widthSize);
} else {
  width = desiredWidth;

}

自定义视图onMeasure - 获取正确的大小

注意:
看看MeasureSpec值:
MeasureSpec.EXACTLY表示用户硬编码大小的值,所以
 不管你的视图大小,你应该设置指定的宽度或高度。
MeasureSpec.AT_MOST用于使您的视图大到它想要达到指定的大小。
MeasureSpec.UNSPECIFIED实际上是一个视图的包裹大小。所以用
 此参数可以使用上面计算的所需大小。

在将最终值设置为setMeasuredDimension之前,请检查这些值是否为负值。这将避免布局预览中的问题。

onLayout

这种方法包括给每个孩子分配大小和位置。因此,我们正在寻找一个平面自定义视图(扩展一个简单的视图),没有任何孩子,所以没有理由重写此方法。

onDraw

这就是魔法发生的地方。拥有Canvas和Paint对象将允许你绘制任何你需要的东西。
Canvas实例来自onDraw参数,它基本上响应绘制不同的形状,而Paint对象定义了形状将获得的颜色。简单地说,Canvas响应绘制一个对象,而Paint则是对它进行造型。它几乎在任何地方使用,无论它将是一个线,圆或矩形。
onDraw()方法示例
在做自定义视图时,始终记住onDraw调用大量的时间,像真的很多。虽然有一些更改,滚动,刷卡将重绘。所以这就是为什么即使Android Studio建议在onDraw操作期间避免对象分配,而是创建一次并进一步重用。
onDraw() -绘制对象重新创建
onDraw() -绘制对象重用
注意:
在执行绘制时,始终记住重用对象,而不是创建新对象。不要依赖你的IDE来突出一个潜在的问题,但自己做,因为如果你在onDraw调用的方法中创建对象,IDE看不到它。

不要在绘制时硬编码视图大小。处理其他开发人员可能具有相同视图但大小不同的情况,因此绘制视图取决于它有什么大小。

查看更新

从视图生命周期图中,您可能会注意到有两种方法导致视图重绘本身。 invalidate()和requestLayout()方法将帮助您创建交互式自定义视图,这可能会改变其在运行时的外观。但为什么有两个?
invalidate()方法用于简单重绘视图。虽然您的视图例如更新其文本,颜色或触摸交互性。这意味着视图将仅再次调用onDraw()方法来更新其状态。
requestLayout()方法,你可以看到将产生视图更新通过其生命周期只是从onMeasure()方法。这意味着你需要它,而在视图更新后,它改变了它的大小,你需要再次测量它来绘制它取决于新的大小。

动画

自定义视图中的动画是逐帧过程。这意味着,如果你想让一个圆半径动画从小到大,你需要逐个增加它,并在每一步之后调用invalidate()来绘制它。
你最好的朋友在自定义视图动画是ValueAnimator。这个类将帮助你动画任何值从开始到结束甚至Interpolator支持(如果你需要)。
ValueAnimator animator = ValueAnimator.ofInt(0, 100);
animator.setDuration(1000);
animator.setInterpolator(new DecelerateInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
  public void onAnimationUpdate(ValueAnimator animation) {
    int newRadius = (int) animation.getAnimatedValue();
  }
});
animator.start();

自定义视图ValueAnimator样本

注意:
不要忘记调用invalidate()每次新的动画值出来。
通过ValueAnimator的动画示例

转载地址:http://yeedi.baihongyu.com/

你可能感兴趣的文章
python_time模块
查看>>
python_configparser(解析ini)
查看>>
selenium学习资料
查看>>
<转>文档视图指针互获
查看>>
从mysql中 导出/导入表及数据
查看>>
HQL语句大全(转)
查看>>
几个常用的Javascript字符串处理函数 spilt(),join(),substring()和indexof()
查看>>
javascript传参字符串 与引号的嵌套调用
查看>>
swiper插件的的使用
查看>>
layui插件的使用
查看>>
JS牛客网编译环境的使用
查看>>
9、VUE面经
查看>>
关于进制转换的具体实现代码
查看>>
Golang 数据可视化利器 go-echarts ,实际使用
查看>>
mysql 跨机器查询,使用dblink
查看>>
mysql5.6.34 升级到mysql5.7.32
查看>>
dba 常用查询
查看>>
Oracle 异机恢复
查看>>
Oracle 12C DG 搭建(RAC-RAC/RAC-单机)
查看>>
Truncate 表之恢复
查看>>