在Android中,控件大致被分为两类:ViewGroup和View。ViewGroup控件作为父控件管理其包含的View控件。例如LinearLayout下包含着一些TextView,ImageView等View控件。
自定义View
适当的使用自定义View可以丰富程序的体验效果,但是滥用View则会带来适得其反的效果。
在View中通常有以下一些比较重要的 回调方法
- onFinishInflate():从XML加载组件后回调
- onSizeChanged():组件大小改变时回调
- onMeasure():回调该方法用于测量
- onLayout():回调该方法用来确定显示的位置
- onTouchEvent():监听到触摸事件时回调
通常情况下有一下3种方法来实现自定义的控件
- 对现有控件进行扩展
- 通过组合来实现新的控件
- 重写View来实现全新的控件
原本想先看个效果图,但是图片太大,上传不了。想要查看动图可以去我的GitHub查看:自定义View
由于项目尝试使用freeline编译(freeline是一个秒级编译,可以提高编译速。,不了解的可以去搜索看看,这里就不做解释了),上传到GitHub的时候忘记忽略文件上传了。大家可以忽略这部分文件。
对现有控件进行扩展
下面就拿TextView进行扩展
实现带闪烁的效果
实现步骤
- 创建一个类继承自TextView
- 利用Paint对象的Shader渲染器,通过一个不断变化的LinearGradient
- 使用带有该属性的Paint对象来绘制要显示的文本
- 最后通过矩阵方式来不断平移渐变效果
主要重写了onSizeChanged()方法 ,对组件大小的改变进行监听。
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if (mMeasuredWidth == 0){ mMeasuredWidth = getMeasuredWidth(); if (mMeasuredWidth > 0){ mPaint = getPaint(); //获取当前绘制的TextView的Paint对象 mLinearGradient = new LinearGradient(0, 0, mMeasuredWidth, 0, new int[]{Color.BLUE, 0xffffffff, Color.BLUE}, null, Shader.TileMode.CLAMP); mPaint.setShader(mLinearGradient); //设置原生TextView没有的LinearGradent属性 mMatrix = new Matrix(); } } }
还重写了onDraw()方法,用于绘制渐变矩形。
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (mMatrix != null){ mTranslate += mMeasuredWidth / 5; if (mTranslate >2*mMeasuredWidth){ mTranslate = -mMeasuredWidth ; } mMatrix.setTranslate( mTranslate, 0 ); mLinearGradient.setLocalMatrix(mMatrix); postInvalidateDelayed(100); //无效后延时100毫秒后出现 } }
创建组合控件
组合控件可以很好的创建出具有重用功能的控件,这种方式通常需要继承一个合适的ViewGroup,再给它添加指定功能的控件,从而形成新的控件。
下面以TopBar举例
先看一下效果
大部分的程序都会有一个头布局,因此将其封装成一个组合控件,可以大大减少代码的书写。 一般的头布局会有标题,返回按钮,以及更多按钮。因此我们将其进行封装。
- 实现步骤
- 首先在res/values目录下,创建一个attrs.xml文件,在里面定义你需要的属性。
<resources>
<declare-styleable name="TopBar">
<attr name="title" format="string"/>
<attr name="titleTextSize" format="dimension"/>
<attr name="titleTextColor" format="color"/>
<attr name="leftTextColor" format="color"/>
<attr name="leftBackground" format="reference|color"/>
<attr name="leftText" format="string"/>
<attr name="rightTextColor" format="color"/>
<attr name="rightBackground" format="reference|color"/>
<attr name="rightText" format="string"/>
</declare-styleable>
</resources>
创建一个类继自一个ViewGroup,这里我选择 RelativeLayout。
将你在atts.xml中定义的declare-styleable的所有属性的值存储到TypedArray中,获取完
TypedArray
的值后,一般要调用recyle
方法来避免重新创建的时候的错误。动态创建3个控件
为创建的控件元素赋值,值就来源于我们在引用的xml文件中给对应属性的赋值
为组件元素设置相应的布局元素。也就是控件的摆放位置,是包裹内容还是铺满父布局。
为了满足更多的需求,我们一般还会给控件添加点击事件,以及控件的显示和隐藏方法。
最后在xml布局中引用,记得添加自定义的命名空间名称。
<com.dongxi.customerview.view.TopBar
android:id="@+id/topBar"
android:layout_width="match_parent"
android:layout_height="40dp"
custom:leftText="Back"
custom:leftBackground="@mipmap/ic_launcher"
custom:leftTextColor="@color/colorAccent"
custom:rightBackground="@mipmap/ic_launcher"
custom:rightTextColor="@color/colorAccent"
custom:rightText="MORE"
custom:title="自定义标题"
custom:titleTextColor="@color/colorAccent"
custom:titleTextSize="10sp"
/>
重写View来实现新的控件
实现的是音频效果图
效果
分析
- 绘制一个个随机产生高度的矩形
- 每个举行之间稍微便宜一点距离即可
- 给绘制的Paint对象添加一个LinearGradient渐变效果
自定义ViewGroup
这里实现的是具有黏性的ScrollerView
效果
分析
- 首先定义一个类继承自ViewGroup,然后获取到Activity的实际屏幕信息
- 在onMeasure方法中使用遍历对子view进行测量
- 设置子view的摆放位置,本例中是显示在手机完整的一屏。
- 在onLayout中将具体的参数传递进去即可完成静态的添加子view到viewgroup中
- 重写onTouchEvent方法,对各个操作进行控制,即可实现滑动效果。
话不多说,直接看源码。