Android:绘制自定义视图

翻译 2017年01月03日 15:39:50

介绍

每天我们使用各种应用程序,尽管他们的不同意图,大多数是非常相似,甚至相似的设计。这就是为什么很多客户要求特定的,自定义的布局和外观,没有其他应用程序还没有体现,以使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的动画示例


Android开发之自定义View(视图)

作者:李响                View类是Android的一个超类,这个类几乎包含了所有的屏幕类型。每一个View都有一个用于绘图的画布,这个画布可以进行任意扩展。在游戏开发中往往需要...
  • pku_android
  • pku_android
  • 2012年03月18日 14:26
  • 4679

使用自定义视图的AlertDialog

自定义AlertDialog 本文部分内容参考自:http://blog.csdn.net/fofu33/article/details/40622599 使用自定义视图的AlertDialog主要分...
  • piglite
  • piglite
  • 2016年01月04日 01:21
  • 1064

Android中自定义视图View

标签: 前言 好长时间没写blog了,心里感觉有点空荡荡的,今天有时间就来写一个关于自定义视图的的blog吧。关于这篇blog,网上已经有很多案例了,其实没什么难度的。但是我们在开发的过程中有时候会...
  • HTYBAY
  • HTYBAY
  • 2016年05月18日 15:49
  • 1159

自定义视图的绘制

自定义视图最重要的部分是它的外观.你可以根据应用的需求简单或复杂的实现它. 这个教程包含了最常见的操作. 重写onDraw() 绘制自定义视图里最重要的一步是重写onDraw()方法. o...
  • qeqeqe236
  • qeqeqe236
  • 2014年05月20日 16:59
  • 439

Android-自定义视图

折腾了一天,终于弄清楚了一个简单的自定义的视图,在这里做个笔记。
  • wjr2012
  • wjr2012
  • 2010年08月31日 16:34
  • 3833

Android 自定义View——自定义ProgressBar

Android中给我们提供了多个样式的ProgressBar,SeekingBar,RatingBaar等进度条,但是我们这些样式都满足不了我们的要求,这时我们就可以使用自定义View来定义我们自己想...
  • To_be_Designer
  • To_be_Designer
  • 2015年09月16日 22:21
  • 1885

springmvc学习笔记(15)——自定义视图

什么时候用到自定义视图通常我们所用到的视图就是jsp等网页,有些时候,我们会根据我们的需求自定义视图。比如我们要提交一个表单,然后把表单的内容导出为Excel,这时候我们就可以定义一个导出Excel的...
  • u010837612
  • u010837612
  • 2015年04月24日 15:36
  • 1977

Android圆形头像的绘制(二)之自定义视图

一般在项目中,我们用到的圆形头像都是采用自定义视图的方式,这种圆形头像一般分为普通的圆形头像、带边框的圆形图像、随机背景头像,在上一篇Android圆形图像的绘制(一)中,提到了圆形头像绘制的基本方法...
  • DylanZhuang
  • DylanZhuang
  • 2016年07月02日 17:24
  • 530

自定义View(一)——画线、矩形、圆形、图像

一、最简单的自定义View,什么都不显示,但是有View的特性 com.cctvjiatao.customview.MainActivity package com.cctvjiatao.custom...
  • lvyoujt
  • lvyoujt
  • 2016年03月12日 13:29
  • 4669

Android-下拉刷新(一)自定义刷新视图

前言入职接近半个多月,有几天空闲,所以想着能不能自己实现一个库来练练手,因为之前一直想要实现下拉刷新的功能,因此就有了这样一个自制的下拉刷新库——RefreshWidgetLib.关于下拉刷新下拉刷新...
  • z82367825
  • z82367825
  • 2016年07月23日 21:16
  • 1180
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android:绘制自定义视图
举报原因:
原因补充:

(最多只允许输入30个字)