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…

【水】uva10037 过桥

给出n个人所需过桥的时间,每次最多两人过桥,过桥时间为最长的人的时间。求最快所有人全部过桥方案。 贪心。先从小到大排,易知 n1 时 ansa[1] n2,ansmax(a[1],a[2]) n3,ansa[1]a[2]a[3] 初始化F[1、2、3],记F[n](n>4&#xff0…

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

来源:智东西编辑:智东西内参摘要:随着全球电动车浪潮席卷,关于固态电池的新闻越来越多。从 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年致敬。作者:刘锋 互…

Android之自定义ViewGroup

概述 在写代码之前,我必须得问几个问题: 1、ViewGroup的职责是啥? ViewGroup相当于一个放置View的容器,并且我们在写布局xml的时候,会告诉容器(凡是以layout为开头的属性,都是为用于告诉容器…

C# 5.0 CallerMemberName CallerFilePath CallerLineNumber 在.NET4中的使用

C# 5.0 给我们带来了三个非常有用的编译器特性 CallerMemberName CallerFilePath CallerLineNumber 在C与C中由下列字符帮助我们实现调试消息的文件行号 01.#define debug_msg printf("%s[%d]:",__FILE__,__LINE__);printf 在.NET 4中与其功能相等的是 new StackTrac…

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

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

Android之ViewDragHelper

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

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

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

ListView滑动删除效果实现

通过继承ListView然后结合PopupWindow实现 首先是布局文件&#xff1a; delete_btn.xml&#xff1a;这里只需要一个Button <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/a…

直接读取硬盘扇区

Linux系统下一切都是文件&#xff0c;可以像使用普通文件一样使用设备&#xff0c;可直接操作设备扇区内容,这种方式不经过文件系统。 #include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#in…

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

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

移动传感器扫描覆盖

移动传感器扫描覆盖摘要&#xff1a;关于传感器网络中的地址覆盖问题&#xff0c;已经做过很多尝试。他们通常归为两类&#xff0c;全覆盖和栅栏覆盖&#xff0c;统称为静态覆盖。在这篇论文中&#xff0c;我们研究一种新的覆盖方案&#xff0c;扫描覆盖&#xff0c;一种不同于…

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…