在Android中,熟悉的布局和控件都是从基类视图继承的。
有几种自定义视图实现方式:
① 自定义组合控件:多个控件组合成为一个新的控件,方便多处复用② 继承系统View控件:继承自TextView等系统控件,在系统控件的基础功能上进行扩展③ 继承View:不复用系统控件逻辑,继承View进行功能定义④ 继承系统ViewGroup:继承自LinearLayout等系统控件,在系统控件的基础功能上进行扩展⑤ 继承ViewGroup:不复用系统控件逻辑,继承ViewGroup进行功能定义
一、视图的绘制过程
视图的绘制基本上由三个函数完成:measure()、layout()和draw():
measure:测量View的宽高,主要是View中的:measure(),setMeasuredDimension(),onMeasure()方法。layout:计算当前View以及子View的位置,主要是View中的:layout(),onLayout(),setFrame()方法。draw:视图的绘制工作,主要是View中的:draw(),onDraw()方法。
二。Android屏幕坐标系
在安卓坐标系中,以屏幕左上角为原点,向右为X轴正轴,向下为Y轴正轴。
根据上述坐标,结合视图基类的相关API,涉及到视图的一些坐标方法,如:
getTop:View到其父布局顶边的距离getLeft:View到其父布局左边的距离getBottom:View到其父布局顶边的距离getRight:View到其父布局左边的距离
结合上面的API,可以计算出视图的宽度和高度,计算方法如下:
width = getRight – getLeft;height = getBottom – getTop
三。自定义视图开发的步骤
这里我们介绍最复杂的一种,自定义视图。
3.1构造函数
无论是继承系统视图还是直接继承视图,都需要重写构造函数。有许多构造函数,其中至少有一个必须重写。
public class CustomView extends View{ /** * 代码中New实例化时 调用该方法 */ public CustomView(Context context){ super(context); } /** * 在xml布局文件中使用时会自动调用该方法 */ public CustomView(Context context, AttributeSet attrs){ super(context, attrs); } ... //更多参数的构造函数}
3.2自定义属性
安卓的控件都是从安卓开始的,都是系统本身的属性。为了方便配置自定义视图的属性,我们还可以自定义属性值。Android自定义属性可以分为以下几个步骤:
1、自定义一个View2、编写values/attrs.xml,在其中编写styleable和item等标签元素3、在布局文件中View使用自定义的属性(注意namespace)4、在View的构造方法中通过TypedArray获取
attrs.xml文件的示例如下:
<?xml version="1.0" encoding="utf-8"?><resources><declare-styleable name="test"><attr name="text" for***t="string" /><attr name="testAttr" for***t="integer" /></declare-styleable></resources>
代码实现示例如下:
public class MyTextView extends View { private static final String TAG = MyTextView.class.getSimpleName(); //在View的构造方法中通过TypedArray获取 public MyTextView(Context context, AttributeSet attrs) { super(context, attrs); TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.test); String text = ta.getString(R.styleable.test_testAttr); int textAttr = ta.getInteger(R.styleable.test_text, -1); Log.e(TAG, "text = " + text + " , textAttr = " + textAttr); ta.recycle(); }}
文件使用的示例如下:
<RelativeLayout xmlns:android="http://sche***s.android.com/apk/res/android" xmlns:tools="http://sche***s.android.com/tools" xmlns:app="http://sche***s.android.com/apk/res/com.example.test" android:layout_width="***tch_parent" android:layout_height="***tch_parent" ><com.example.test.MyTextView android:layout_width="100dp" android:layout_height="200dp" app:testAttr="520" app:text="helloworld" /></RelativeLayout>
四。Measure()
MeasureSpec
MeasureSpec是View的内部类,封装了视图的大小。在onMeasure()中,视图的宽度和高度将根据这个MeasureSpec的值来确定。MeasureSpec的值保存在一个int值中。int值有32位,前两位表示模式mode,后30位表示大小size。即MeasureSpec = mode+size。
MeasureSpec中有三种模式:
UNSPECIFIED:无限制,View对尺寸没有任何限制,View设置为多大就应当为多大。EXACTLY :精准模式,View需要一个精确值,这个值即为MeasureSpec当中的Size。对应的是***tch_parent。AT_MOST:最大模式,View的尺寸有一个最大值,View不可以超过MeasureSpec当中的Size值。对应的是wrap_content。
的常见用法如下:
// 获取测量模式(Mode)int specMode = MeasureSpec.getMode(measureSpec)// 获取测量大小(Size)int specSize = MeasureSpec.getSize(measureSpec)// 通过Mode 和 Size 生成新的SpecModeint measureSpec=MeasureSpec.***keMeasureSpec(size, mode);
onMeasure
整个测量过程的入口位于视图的measure方法中,在初始化一些参数后调用onMeasure方法。这里我们主要分析一下对策。OnMeasure源代码如下:
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}
setMeasuredDimension(int measuredWidth, int measuredHeight)
:该方法用来设置View的宽高,在我们自定义View时也会经常用到。
getDefaultSize(int size, int measureSpec)
:该方法用来获取View默认的宽高。
getSuggestedMinimumWidth()
:getHeight和该方法原理是一样的
V. Layout()
layout()过程用于为视图计算视图的位置参数。对于ViewGroup来说,除了测量自己的位置,还需要测量子视图的位置。layout()方法是整个Layout()过程的入口,在Layout方法中调用onLayout方法,主要是计算子视图。
六。Draw()
绘制过程是将视图绘制到屏幕上的过程。整个过程的入口在View的draw()方法里,源代码注释写的很清楚。整个过程可以分为六个步骤:
绘制背景有过有必要,保存当前canvas绘制View的内容绘制子View根据需要,绘制边缘、阴影等效果绘制装饰,如滚动条等等
七。摘要
视图在Android的开发中还是很重要的,因为只有系统提供的控件和组件,无论是美观性、可用性还是新特性,都无法满足特定的业务场景。所以经常使用自定义视图,需要在自己的项目中独立开发特殊控件。自定义控件也是开发过程中的重点和难点,要多花时间学习和研究。要点如下:
控件属性的定义、设置和使用交互处理:事件交互和处理属于重中之重,常常要和事件分发结合在一起研究。Canvas和Paint:在进行自定义View开发时,往往会通过画布自己使用画笔进行绘制,这就要求要对Paint、Path、Canvas要做着重的掌握。
本文来自别舍不得旧情人投稿,不代表舒华文档立场,如若转载,请注明出处:https://www.chinashuhua.cn/24/627495.html