专栏名称: 安卓开发精选
伯乐在线旗下账号,分享安卓应用相关内容,包括:安卓应用开发、设计和动态等。
目录
相关文章推荐
51好读  ›  专栏  ›  安卓开发精选

Android: 自定义View

安卓开发精选  · 公众号  · android  · 2016-12-23 20:45

正文

(点击 上方公众号 ,可快速关注)

英文:medium.com

来源: adison

链接: http://www.jianshu.com/p/29bb35a4860e


原文链接

  • https://medium.com/@romandanylyk96/android-draw-a-custom-view-ef79fe2ff54b#.hl4rzavps


部分译文是按自己的理解翻译的,如有错漏,还请指正


简介


每天我们都会使用很多的应用程序,尽管他们有不同的约定,但大多数应用的设计是非常相似的。这就是为什么许多客户要求使用一些其他应用程序没有的设计,使得应用程序显得独特和不同。


如果功能布局要求非常定制化,已经不能由Android内置的View创建 —这时候就需要使用自定义View了。而这意味着在大多数情况下,我们将需要相当长的时间来完成它。但这并不意味着我们不应该这样做,因为实现它是非常令人兴奋和有趣的。


我最近面临了类似的情况:我的任务是使用ViewPager实现Android应用引导页。不同于iOS,Android并没有提供这样的View,所以我不得不编写一个自定义View来实现它。


我花了一些时间来实现它。幸运的是,时下很多开源项目都有类似可复用的View,这节省了我和其他开发者的时间。我决定基于这种View创建一个公共库。如果你有类似的功能需求并且缺乏时间实现它,可以在github repo发现它。


Sample of using PageIndicatorView


绘制!


因为编写自定义View比起普通的View更耗时,你应该只在为了实现特定的功能但没有更简单的方法情况下使用自定义View,或者你希望通过自定义View解决以下问题:


  1. 性能。如果你布局里面有很多View,你想通自定义View优化它,使其更轻量。

  2. 视图层次结构复杂。

  3. 一个完全自定义的View,需要手动绘制才能实现。



如果你还没有尝试过编写自定义View,这篇文章将教会你绘制扁平的自定义View的一些技巧。我将会告诉你整体的视图结构,如何实现具体的功能,不要重犯常见的错误,以及实现动画效果!


我们需要知道的第一件事 –View的生命周期。不知出于某种原因,谷歌并没有提供View生命周期的图表,由于开发者普遍对其有误解,导致了一些意想不到的错误和问题,所以我们要认清这过程。


构造函数


每个View的生命都是从构造函数开始。而且这是一个绘制初始化,进行各种计算,设定默认值或做任何我们需要的事情很好的地方。


但是,为了使我们的View更易于使用和配置,Android提供了很有用的AttributeSet接口。它很容易实现,而且绝对值得花时间去了解和实现它,因为它会帮助你(和你的团队)通过静态参数来设置View,对于以后新特性加入或者新屏幕拓展性支持也更好。


首先,创建一个新的文件attrs.xml。所有不同的自定义View属性都可以放在该文件中。正如你看到的这个例子,我们有一个PageIndicatorView和它的唯一属性piv_count。


Custom Attributes sample


紧接着在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 ();

}


注意:


  • 在创建自定义属性使用一个简单的前缀,以避免与其它View类似的属性名称冲突。一般我们使用View名称缩写,就像例子中的piv_。

  • 如果你使用的是Android Studio,一旦你使用完属性,lint会建议你调用recycle()方法 。The reason is just to get rid of inefficiently bound data that’s not gonna be used again。[译者注:翻译有点拗口,其实就是回收TypedArray,以便后面重用]


onAttachedToWindow


父View调用addView(View)后,这个View将被依附到一个窗口。在这个阶段,我们的View会知道它被包围的其他view。如果你的View和其他View在相同的layout.xml,这是通过id找到他们的好地方(你可以通过属性进行设置),同时可以保存为全局(如果需要)的引用。


onMeasure


这意味着我们的自定义View到了处理自己的大小的时候。这是非常重要的方法,因为在大多数情况下,你的View需要有特定的大小以适应你的布局。


当你重写此方法,需要记得的是,最终要设置setMeasuredDimension(int width, int height) 。


onMeasure


当处理自定义View的大小时候,使用者可能通过layout.xml或者动态设置了具体的大小。要正确地计算它,我们需要做几件事情。


1.计算你的View内容所需的大小(宽度和高度)。

2.获取你的View 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 );







请到「今天看啥」查看全文