Android自定义View

1.View是什么?
View是屏幕上的一块矩形区域,它负责用来显示一个区域,并且响应这个区域内的事件。可以说,手机屏幕上的任意一部分看的见得地方都是View,它很常见,比如 TextView 、ImageView 、Button以及LinearLayout、RelativeLayout都是继承子View的。
对于Activity来说,我们通过setContentView(view)添加的布局到Activity上,实际上都是添加到了Activity 内部的DecorView上面,这个DecorView,其实就是一个FrameLayout,因此实际上,我们的布局实际上添加到了FrameLayout里面。
2.View 是怎么工作的?
View的工作流程分为两部分,第一部分 显示在屏幕上的过程, 第二部分 响应屏幕上的触摸事件的过程。
对于显示在屏幕上的过程:是View 从无到有,经过测量大小(Measure)、确定在屏幕中的位置(Layout)、以及最终绘制在屏幕上(Draw) 这一系列的过程。
对于响应屏幕上的触摸事件的过程:则是Touch事件的分发过程(这一部分,在这里先不涉及)。
Measure() Layout()方法是final修饰的,无法重写 ,Draw()虽然不是final的,但是也不建议重写该方法。
3.如何自定义View?
View 为我们提供了 onMeasure() onLayout() onDraw() 这样的方法,其实所谓的自定义View,也就是对onMeasure() onLayout() onDraw() 三个方法的重写的过程。
所谓的自定义View 实际上,就是仿照View的工作流程,去自己实现的过程。根据继承对象的不同自定义View又分为继承View 与ViewGroup两种。

measure():

  • EXACTLY:一般是设置了明确的值或者是MATCH_PARENT

  • AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT

  • UNSPECIFIED:表示子布局想要多大就多大,很少使用

其中AT_MOST的需要特殊处理,其他的可以自己测量

实例

@Override  
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);  int width;  int height ;  if (widthMode == MeasureSpec.EXACTLY)  {  width = widthSize;  } else  {  mPaint.setTextSize(mTitleTextSize);  mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);  float textWidth = mBounds.width();  int desired = (int) (getPaddingLeft() + textWidth + getPaddingRight());  width = desired;  }  if (heightMode == MeasureSpec.EXACTLY)  {  height = heightSize;  } else  {  mPaint.setTextSize(mTitleTextSize);  mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBounds);  float textHeight = mBounds.height();  int desired = (int) (getPaddingTop() + textHeight + getPaddingBottom());  height = desired;  }  setMeasuredDimension(width, height);  
}  

layout()

Layout() 方法如果是ViewGroup,则循环遍历所有子View,普通View则空实现,因此如果我们继承ViewGroup 我们需要遍历执行所有的child.layout()。
Layout方法中接受四个参数,是由父View提供,指定了子View在父View中的左、上、右、下的位置。父View在指定子View的位置时通常会根据子View在measure中测量的大小来决定。
子View的位置通常还受有其他属性左右,例如父View的orientation, gravity,自身的margin等等,影响布局的因素非常多。
onLayout是ViewGroup用来决定子View摆放位置的,各种布局的差异都在该方法中得到了体现。
onLayout比layout多一个参数,changed,该参数是在setFrame通过比对上次的位置得出是否发生了变化,通常该参数没有被使用的意义,因为父View位置和大小不变,并不能代表子View的位置和大小没有发生改变。

draw()

draw()的过程就是绘制View到屏幕上的过程,draw()的执行遵循如下步骤:

/* * Draw traversal performs several drawing steps which must be executed * in the appropriate order: * *      1. Draw the background(绘制背景) *      2. If necessary, save the canvas' layers to prepare for fading(保存画布的图层来准备色变) *      3. Draw view's content(绘制内容) *      4. Draw children(绘制children) *      5. If necessary, draw the fading edges and restore layers(画出褪色的边缘和恢复层) *      6. Draw decorations (scrollbars for instance)(绘制装饰 比如scollbar) */  

一般2和5 是可以跳过的。
在TextView中在该方法中绘制文字、光标和CompoundDrawable 、ImageView中相对简单,只是绘制了图片。
View 的绘制主要通过dispatchDraw()
先根据自身的padding剪裁画布,所有的子View都将在画布剪裁后的区域绘制。
遍历所有子View,调用子View的computeScroll对子View的滚动值进行计算。
根据滚动值和子View在父View中的坐标进行画布原点坐标的移动,根据子在父View中的坐标计算出子View的视图大小,然后对画布进行剪裁,请看下面的示意图。
dispatchDraw的逻辑其实比较复杂,但是幸运的是对子View流程都采用该方式,而ViewGroup已经处理好了,我们不必要重载该方法对子View进行绘制事件的派遣分发。

View 的几个比较重要的方法:

requestLayout:
当view确定自身已经不再适合现有的区域时,该view本身调用这个方法要求parent view(父类的视图)重新调用他的onMeasure onLayout来重新设置自己位置。特别是当view的layoutparameter发生改变,并且它的值还没能应用到view上时,这时候适合调用这个方法。

postInvalidate 与 invalidate
界面刷新 onDraw方法会执行,区别就是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。 鉴于此,如果要使用invalidate的刷新,那我们就得配合handler的使用,使异步非ui线程转到ui线程中调用,如果要在非ui线程中直接使用就调用postInvalidate方法即可,这样就省去使用handler的烦恼。

总结

自定View的那几个步骤:
1、自定义View的属性
2、在View的构造方法中获得我们自定义的属性
[ 3、重写onMesure ]
4、重写onDraw

参考链接

View的简介 - Because if I don’t write it down, I’ll forget it - 博客频道 - CSDN.NET

教你搞定Android自定义View - 简书

Android 自定义View (一) - Hongyang - 博客频道 - CSDN.NET

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/494154.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【IT笔试面试题整理】判断链表是否存在环路,并找出回路起点

【试题描述】定义一个函数,输入一个链表,判断链表是否存在环路,并找出回路起点 Circular linked list: A (corrupt) linked list in which a node’s next pointer points to an earlier node, so as to make a loop in the linked listEXAMP…

腾讯机器人实验室首曝光 攻坚“通用人工智能”

来源:新浪科技摘要:与当初的“互联网”一样,“AI”正成为各行各业的标配。在近日召开的2018 世界人工智能大会上,腾讯董事会主席兼首席执行官马化腾提出,人工智能技术是一场跨国、跨学科的科学探索工程,对于…

Android之canvas详解

首先说一下canvas类: Class Overview The Canvas class holds the "draw" calls. To draw something, you need 4 basic components: A Bitmap to hold the pixels, a Canvas to host the draw calls (writing into the bitmap), a drawing primitive (e…

下一代动力电池深度报告,三大技术路线谁能笑到最后?【附下载】| 智东西内参...

来源:智东西编辑:智东西内参摘要:随着全球电动车浪潮席卷,关于固态电池的新闻越来越多。从 Fisker 宣称开发充电 1 分钟行驶 500 公里的固态电池,到宝马已与 SolidPower 进行合作开发下一代电动车用固态电池&#xff0…

Android之shape属性详解

有时候 ,为了满足一些需求,我们要用到 shape 去定义 一些背景,shape 的用法 跟图片一样 ,可以给View设置 Android:background”drawable/shape”, 定义的shape 文件,放在 res/shape 目录下 通常我们可以用shape 做 bu…

S3C6410移植u-boot-2010.3(2)基本的启动信息修改

1、启动模块修改 进入/cpu/arm1176/目录,修改start.S文件 首先找到需要修改的CONFIG_NAND_SPL汇编原码,修改如下: #ifndef CONFIG_NAND_SPL /** flush v4 I/D caches*/ mov r0, #0 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ mcr p1…

[修订版]”大脑“爆发背后是50年互联网架构重大变革

前言:面对即将到来的2019年,互联网诞生50年将是诸多纪念活动中重要的一个,经过50年的发展,互联网究竟发生什么重要的变化,通过这篇文章试图进行一次总结,也提前向互联网50年致敬。作者:刘锋 互…

智慧城市建设:科技创业的下一个浪潮

来源:资本实验室随着全球城市化进程的加速,越来越多的人涌进城市,这为城市建设带来了一系列的挑战:一方面,城市需要面对大量的越来越老化的基础设施;另一方面,需要为新涌入的城市居民提供新的&a…

Android之ViewDragHelper

在自定义ViewGroup中,很多效果都包含用户手指去拖动其内部的某个View(eg:侧滑菜单等),针对具体的需要去写好onInterceptTouchEvent和onTouchEvent这两个方法是一件很不容易的事,需要自己去处理:多手指的处理、加速度检测等等。 好…

DARPA人工智能技术研究情况一览

来源:一体化指挥调度国家工程实验室、高端装备发展研究中心摘要:20世纪60年代初,DARPA(当时为ARPA)开始介入自主技术研究,并很快成为该领域的主要研究机构。DARPA意识到,人工智能可以满足大量的…

深入“肠-脑”神经高速通道,揭开“第六感觉”面纱

来源:中国生物技术网直觉是什么?通常被描述为超感官的第六感觉,它在英文里直译就是肠道感觉。肠道作为“第二大脑”的事实已经家喻户晓了。如果你曾在重要的演讲前感到心慌恶心,或者在一顿大餐后感到头昏眼花,那就是肠…

Andoird自定义ViewGroup实现竖向引导界面

一般进入APP都有欢迎界面&#xff0c;基本都是水平滚动的&#xff0c;今天和大家分享一个垂直滚动的例子。 先来看看效果把&#xff1a; 首先是布局文件&#xff1a; <com.example.verticallinearlayout.VerticalLinearLayout xmlns:android"http://schemas.android.…

科技|全球首款飞行汽车开始量产!下月开始预售,2023年后或可实现一键打“飞车”...

来源&#xff1a; 世界科技创新论坛飞机与汽车结合的产物真的要来了。在2018全球未来出行大会上&#xff0c;吉利副总裁杨学良透露&#xff0c;由吉利控股的全资子公司、全球首家飞行汽车公司美国太力飞行汽车公司推出的“全球首款量产飞行汽车”——Transition&#xff0c;将于…

Android手势锁实现

最终效果如下 整体思路 a、自定义了一个RelativeLayout(GestureLockViewGroup)在里面会根据传入的每行的个数&#xff0c;生成多个GestureLockView&#xff08;就是上面一个个小圈圈&#xff09;&#xff0c;然后会自动进行布局&#xff0c;里面的宽度&#xff0c;间距&#x…

智能连接:5G与人工智能、物联网等技术的超级融合

来源&#xff1a;资本实验室随着新技术的成熟&#xff0c;新型的、先进的应用将来自5G、人工智能&#xff08;AI&#xff09;和物联网&#xff08;IoT&#xff09;的融合。这种融合将创造出一个智能连接的世界&#xff0c;对所有个人、行业、社会和经济产生积极影响。从现在到2…

一个绚丽的loading动效分析与实现!

最终效果如下 从效果上看&#xff0c;我们需要考虑以下几个问题&#xff1a; 1.叶子的随机产生&#xff1b; 2.叶子随着一条正余弦曲线移动&#xff1b; 3.叶子在移动的时候旋转&#xff0c;旋转方向随机&#xff0c;正时针或逆时针&#xff1b; 4.叶子遇到进度条&#xff…

20岁的谷歌,和它“最成功”的大败笔

来源&#xff1a;大数据文摘编译&#xff1a;张驰、JIN、涂世文、钱天培谷歌20岁了&#xff01;20年中&#xff0c;谷歌打造了无数或成功或流产的产品&#xff0c;其中&#xff0c;这一名为“谷歌光纤”计划的失败或许是它最“成功”的“大败笔”。2010年&#xff0c;谷歌宣布了…

自定义viewgroup实现ArcMenu

最终效果如下 实现思路 通过效果图&#xff0c;会有几个问题&#xff1a; a、动画效果如何实现 可以看出动画是从顶点外外发射的&#xff0c;可能有人说&#xff0c;那还不简单&#xff0c;默认元素都在定点位置&#xff0c;然后TraslateAnimation就好了&#xff1b;这样忽略…

也谈谈Atiyah关于黎曼猜想的证明

来源&#xff1a;潇轩社作者&#xff1a;叶扬波 著名数学家&#xff0c;美国爱荷华大学教授。作为数论学家&#xff0c;他在中国大陆出版有《迹公式与模形式》等专著。以下是他谈Atiyah关于黎曼猜想的证明的文章&#xff0c;观点专业而且独到&#xff0c;转载此文&#xff0c;…

大型Javascript应用架构的模式(译文)

附上翻译好的word文件 http://files.cnblogs.com/lizhug/Patterns_For_Large-Scale_JavaScript_Application_Architecture.zip 作者&#xff1a;Addy Osmani 技术评审&#xff1a;Andree Hansson 翻译&#xff1a;李珠刚 珠刚参上 今天我们将要探讨一系列用于大型Javascri…