美文网首页安卓Android面试题Android 开发经验集程序员
Android面试一天一题(Day 30:老外的自定义View面

Android面试一天一题(Day 30:老外的自定义View面

作者: goeasyway | 来源:发表于2016-11-07 11:47 被阅读7715次

    之前买过一本专门讲Android Launcher开发的书,有点可惜,关建的地方都没有讲深入,用太多基础的知识点来占篇幅了(并不是说基础知识不重要,只些这些基础知识我可以从很多地方得到资料,不需要一本专讲Launcher开发的书来过多的介绍),这样的讲解我认为很难让一个开发学习到Launcher的精髓。我认为开发Launcher应用有三个关键的地方:

    • 自定义View
    • 数据结构(显示在Launcher的应用,包括AppWidget)
    • 性能优化

    其实从这三点,大家也可以看出Launcher是一个很关键的应用,能同时做好这三点的开发可以说是相当不错的。所以,你也可以检验一个面试者所做过的应用或者项目,看他是否有能力独立做好这三点。

    这一章,就说一下自定义View。

    面试题:如何实现自定义View?

    回忆一下,你去面试时常被问到的自定义View方面的问题是那些。有没有:

    invalidate和postInvalidate方法的区别?
    自定义View的绘制流程?
    View的Touch事件分发流程?

    因为在实际的工作中并不是每个人都会涉及UI的实现,所以有些人没有做过自定义View并不能否决这个人在Android开发上的能力,包括会问你这方面问题的面试官也可能并没有自定义View的经验。所以很多面试中,一般也就是问问如上面的那些机制方面的问题,看面试者是否有一个正确的认识。但如果一个人说他精通自定义View的话,不妨从细节上检验一下他。

    在说我怎么检验面试者的自定义View水平之前,先来一道老外的面试题,大家不妨先自己试着敲一下代码看能不能实现。

    效果界面如下:

    这一道题其实把我们刚刚提到的面试常被问到的那些机制问题都涉及到了,你很容易就能查找和了解并可以很好的回答上那几个基础问题,但是你能做出这个自定义View吗?

    这就是机制和现实的差距!你有必要了解机制(基础),但了解并不等于会了,会的过程需要一定的积累,只有融会贯通了才能轻而易举地完成这个老外的面试题。

    我们简单剖析一下,这个可左右滑动的View中是一组子View组成的,每个子View(圆盘carousel)可以自定界面,但背景的样式是相似(每组背景只是颜色不一样),有点ListView中的Adapter味道,对滑动的过渡是有要求的,这个其实是更真实操作Touch的样例(没有人想看生硬的滑动效果)。那么我们要能实现上面的效果,需要注意以下几个点:

    ViewGroup的布局(计算一行能显示的圆盘数量和大小)
    圆盘View的效果(背景和半透明过渡)
    左右列表和BaseAdapter
    圆盘View的滑动(需要自动回弹,保证滑动后要有一个圆盘处于中间位置)

    这个章节讲的是怎么准备自定义View的面试,所以我并不打算把这个问题的具体实现过程写出来(如果大家觉得有必要,可以反馈一下,人数较多的话可以就此题的实现写一篇文章),大家可以自去偿试实现,下一节再给一个我的实现链接,大家可以对比一下。

    View & ViewGroup

    自定义View(有时我们也可以叫自定义UI或者自定义UI组件),从实现或者分类上我觉得可以分为三类:

    1. 直接继承View
    2. 继承自ViewGroup
    3. 对现有组件的扩展(如继承自TextView)

    第3种方式是比较容易的,因为父组件常常帮我处理了绘制、分发和Touch等事件,我们只需要加入一些特别的功能就行。比如继承自ImageView实现图片圆角显示。

    第1和第2种方式,需要我们对前面提到的那些机制问题有一定的了解,也要搞清楚View和ViewGroup在哪些方面有什么区别。

    ViewGroup继承自View,是一种特殊的View,可以理解成一种View的容器,它可以装其他的View或其他的ViewGroup。
    ViewGroup需要控制子View如何布局,所以必须实现onLayout(在ViewGroup中是抽像方法)。
    ViewGroup可以通过onInterceptTouchEvent拦截当前事件,再决定是否分发给子View处理。
    ViewGroup默认是不会调用onDraw方法的,如果需要重绘容器的背景需要在构造函数调用setWillNotDraw(false)。

    除此之外,要熟悉一些概念(或者类):Canvas, Paint, Matrix,Path & PathMeasure,贝塞尔曲线,SufaceView & OpenGL等等。是不是觉得概念太多了,是的,没有实际做过,你一定会这样想。让你为了面试去准备这么多东西,貌似也起不到多大的作用,面试官不一定会问(除非指明了招专门做自定义UI的开发)。而且就算面试官问了一个你准备好的主题,但他换一种说法问你,如果你只是准备过但并没有掌握的话,也不一定能答得上来。就拿PathMaesure来说,做为面试官一般不会直接问你:“这个PathMeasure有什么方法或者主要是做什么用的啊?”

    而往往会用实例来看你的实现思路,例:“如何实现下图的这个箭头图标(png图片)围绕园周运动的自定义View”。如果你的做法不是使用PathMeasure,那么我也会很有兴趣想听听你的思路和实现方法。

    灵活使用PathMeasure的常见的两个方法可以轻松的实现很多神奇的效果。
    getSegment:截取整个Path的片段;
    getPosTan:获取路径上的坐标点和对应点的切线坐标。

    使用PathMeasure实现的核心代码:

        path = new Path();
        path.addCircle(0, 0, 200, Path.Direction.CW); //添加一个圆的path
        pathMeasure = new PathMeasure(path, false);
    
        float[] pos = new float[2];
        float[] tan = new float[2];
        pathMeasure.getPosTan(pathMeasure.getLength() * value, pos, tan);
    
        float degress = (float) (Math.atan2(tan[1], tan[0]) * 180.0 / Math.PI); // 计算箭头图片的旋转角度
    

    如果面试者不了解PathMeasure的话,也可以问一下图片圆角(或称矩形圆角)或者圆形头像的实现方式,这个也是一个很常见的功能,效果如下图:

    �除了把原图直接做成圆角外,常见有三种方式实现:
    使用Xfermode混合图层;
    使用BitmapShader;
    通过裁剪画布区域实现指定形状的图形(ClipPath)

    小结

    对于应用开发来说,自定义View是一项很常见的工作,很多时候都需要把UI交互设计师的动画和草图通过自定义View实现出来。如果对自定义View不太了解的话,有可能会引入很多不必要的代码(因为你总想着先找别人实现好的库),而且可能很简单的实现会被你写得很复杂(如上面举的PathMeasure的例子),无形中增加维护的难度。

    遇到过很多面试者,当你问他们比较善长Android开发的哪个方面的话,他们脱口而出“UI”,但当你问他自定义View的一些经验时,得到的回答却只是知道如何使用别人的库而已。

    当我写之篇文章时,也觉得很难用一篇文章把自定义View的知识要点全部讲清楚,这里也只能是从面试的角度给讲几个例子,希望对你有帮助。最后,准备自定义View方面的面试最简单的方法:

    1. 就是自己动手实现几个View(由简单到复杂);
    1. 分析一些热门App中的自定义View的效果是怎么实现的;

    相关文章

      网友评论

      • afcc0fb1eeda:思考了一会,还是不知道如何画出箭头bitmap,用矩阵旋转以后效果与博主的完全不同.博主如何实现的阿
      • 小鱼打酱油:图片绕着旋转的 第一感觉是seekbar:smile:底下圆环图片固定 上面seekbar 把平时原点的图片 换成箭头图片 感觉调一调应该能出来啊
      • 2bd4198d1a5d:楼主写的很不错:+1:
      • 残霜丶:进阶必会啊
      • 06aff8f89281:求实现 大神
      • 懒猫来:博主方便告知文首提到的书名吗?想学习一下
        goeasyway:@_Zeno 京东搜一下“android launcher”就出来了。
      • D13954:我觉得,先去把机制那一块了解了,然后自己尝试写,这样写的时候,才会舒服,不然这个类不会,那个方法不知道。瞬间就让你觉得很那。
      • wipen:第一次读作者的文章,文字简练,能给人一些引导。之后顺着作者指出的方向自己探索,尝试。适合作为自学的指导,如果是一步步教的傻瓜式教程反而容易失去兴趣。
        goeasyway:@wipen thanks
      • 菩提丶:想到了一个,用post和postdelayed,间隔时间短点小角度的旋转重绘,会不会性能太差
        goeasyway:@MiBoy 看情况,如果不去滑动你并不一定能感觉到卡。有些手机30fps效果都挺好了。
        MiBoy:@goeasyway 楼主的意思 低于60fps 是不是肉眼就能感觉到卡顿了
        goeasyway:@菩提丶 16.7毫秒重绘一次 所以应该不会
      • 啸天AskSky:感谢楼主分享,感觉楼主很厉害,我是一名初级Android开发,实际上就连自定义View的基础都不是很懂,很多方法,执行顺序都模模糊糊的,希望楼主能够写一遍自定义View实现原理相关的文章。在网上找了好多文章,都感觉不是很好
        goeasyway:@啸天AskSky 好提议。不过自己view的概念太多,带我慢慢理顺。
      • 菲利柯斯:好像习惯了抄袭,自己去写的话感觉无从下手,哎!
        c7cd0a3d27ca:同感 读了楼主的文章后开始从新重视这些基本的实现而不是先开始找库……
      • 寒涵:求实现
      • 薄炳鑫:学习学习...
      • 丛蛋白:公众号过来的,求下一篇实现。。毫无思路。。最好还有那个图片绕圆形动的。。谢谢,辛苦,希望下一期能看到。好像学学自定义view
        goeasyway:@丛蛋白 呵呵 稍等

      本文标题:Android面试一天一题(Day 30:老外的自定义View面

      本文链接:https://www.haomeiwen.com/subject/zwtpyttx.html