目录
一、前言
自定义控件一直是Android很重要的一部分,但是大部分时间我们可能很少自己去写控件。因为现在开源的控件比较多,自定义写起来也比较麻烦。但是当我们需要的时候可能就忘了,所以菜鸟作者就买了本书打算系统的学习一遍。顺便做下笔记,防止以后忘记。
大家可以浏览一遍,复习一下巩固基础。如果要深入学习这里也推荐两位大神博客
https://www.jianshu.com/p/146e5cec4863
https://blog.csdn.net/harvic880925 启舰《Android 自定义控件开发入门与实战》
续《Android 自定义控件开发入门与实战》学习笔记(一)
二、学习笔记
第四章:属性动画进阶
一、PropertyValuesHolder
简介:PropertyValuesHolder保存了动画过程中所需要操作的属性和对应的值。
1.实例函数:
public static PropertyValuesHolder ofFloat(String propertyName,float... values)
public static PropertyValuesHolder ofInt(String propertyName,int... values)
public static PropertyValuesHolder ofObject(String propertyName,TypeEvaluator evaluator,Object... values)
public static PropertyValuesHolder ofKeyfram(String propertyName,Keyfram... values)
// propertyName:表示属性名,通过反射查找对应属性的setProperty()函数。
// values:属性所对应的参数,同样是可变长参数,可以指定多个。
2.如何使用:ObjectAnimator提供了一个设置PropertyValuesHolder实例的入口。
//target:执行动画的控件 values:PropertyValuesHolder实例 ,
传入多个PropertyValuesHolder实例,则会对控件的多个属性同时执行动画操作
public static ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder... values)
3.例:
PropertyValuesHolder holder = PropertyValuesHolder.ofFloat("Rotation",60f,-60f,40f,-40f,-20f,20f,10f)
PropertyValuesHolder holder2 = PropertyValuesHolder.ofObject("CharText",new CharEvaluator(),new Character('A'),new Character('z'));
ObjectAnimator.ofPropertyValuesHolder(mMytV,holder,holder2);
ObjectAnimator.setDuration(3000);
ObjectAnimator.setInterpolator(new AccelerateInterpolator());
ObjectAnimator.start();
二、KeyFrame
简介:提供方便地控制动画速率问题。
1.使用方式:
//第一步:生成Keyframe对象
//fraction表示当前的显示进度 value:表示动画当前所在的数值位置。
public static Keyframe ofFloat(float fraction,float value);
public static Keyframe ofInt(float fraction,int value);
public static Keyframe ofObject(float fraction,int value);
//第二步:利用PropertyValuesHolder.ofKeyframe()函数生成PropertyValuesHolder对象。
public static PropertyValuesHolder ofKeyframe(String propertyName,Keyframe... values)
//第三步:利用ObjectAnimator.ofPropertyValuesHolder()函数生成对应的Animator
public static ObjectAnimator ofPropertyValuesHolder(View view,PropertyValuesHolder holder)
2.KeyFrame常用函数:
//设置fraction参数,即KeyFrame所对应的进度
public void setFraction(float fraction)
//设置当前Keyframe所对应的值
public void setValue(Object value)
//设置插值器
public void setInterpolator(TimeInterpolator interpolator)
3.PropertyValuesHolder函数:
//设置动画的Evaluator
public void setEvaluator(TypeEvaluator evaluator)
//用于设置ofFloat()所对应的动画值列表
public void setFloatValues(float... values)
//用于设置ofInt()所对应的动画值列表
public void setIntValues(int... values)
//用于设置ofKeyframes()所对应的动画值列表
public void setKeyframes(Keyframe... values)
//用于设置ofObject()所对应的动画值列表
public void setObjectValues(Object... values)
//设置动画属性名
public void setPropertyName(String propertyName)
三、ViewPropertyAnimator
简介:Android3.1中新增ViewPropertyAnimator机制,给默认属性提供了一种更加便捷的用法。
1.例:
ObjectAnimator animator = ObjectAnimator.ofFloat(textview,"alpha",0f);
//转
textview.animate().alpha(0f);
(1)animate():整个系统从调用View的这个叫做animate()的新函数开始。这个函数会返回一个ViewPropertyAnimator对象,可以通过调用这个对象的函数来设置需要实现动画的属性。
(2)自动开始:我们没有显示调用过start()函数。在新的API中,启动动画是隐式的,在声明完成后,动画就开始了。
(3)流畅:ViewPropertyAnimator拥有一个流畅的接口,它允许将多个函数调用很自然地串在一起,并把一个多属性的动画写成一行代码。
2.常用函数:
alpha(float value) | 设置透明度 |
scaleY(float value) | 设置Y轴方向的缩放大小 |
scaleX(float value) | 设置X轴方向的缩放大小 |
translationY(float value) | 设置Y轴方向的移动值 |
translationX(float value) | 设置X轴方向的移动值 |
rotation(float value) | 设置绕Z轴旋转度数 |
rotationX(float value) | 设置绕X轴旋转度数 |
rotationY(float value) | 设置绕Y轴旋转度数 |
x(float value) | 相对于父容器的左上角座标在X轴方向的最终位置 |
y(float value) | 相对于父容器的左上角座标在Y轴方向的最终位置 |
alphaBy(float value) | 设置透明度增量 |
rotationBy(float value) | 设置绕Z轴旋转增量 |
rotationXBy(float value) | 设置绕X轴旋转增量 |
rotationYBy(float value) | 设置绕Y轴旋转增量 |
translationXBy(float value) | 设置X轴方向的移动值增量 |
translationYBy(float value) | 设置Y轴方向的移动值增量 |
scaleXBy(float value) | 设置X轴方向的缩放大小增量 |
scaleYBy(float value) | 设置Y轴方向的缩放大小增量 |
xBy(float value) | 相对于父容器的左上角座标在X轴方向的位置增量 |
yBy(float value) | 相对于父容器的左上角座标在Y轴方向的位置增量 |
setInterpolator(TimeInterpolator interpolator) | 设置插值器 |
setStarDelay(long startDelay) | 设置开始延时 |
setDuration(long startDelay) | 设置动画时长 |
3.设置监听器:
tv.animate().scaleX(2).scaleY(2).setListener(new Animator.AnimatorListener(){
......
});
4.animateLayoutChanges属性:
简介:Android为了支持ViewGroup类控件,在添加或移除其中的控件时自动添加动画。提供了一个非常简单的属性
android:animateLayoutChanges="true/false"
5.LayoutTransition
简介:因为animateLayoutChanges只能使用默认动画效果,所以LayoutTransition实现自定义动画。
使用方式:
第一步:创建实例
LayoutTransition transitioner = new LayoutTransition();
第二步:创建动画并进行设置
ObjectAnimator animOut = ObjectAnimator.ofFloat(null,"rotation",0f,90f,0f);
transitioner.setAnimator(LayoutTransition.DISAPPEARING,animOut);
第三步:将LayoutTransition设置到ViewGroup中。
linearLayout.setLayoutTransition(transitioner);
//transitionType表示当前应用动画的对象范围。
public void setAnimator(int transitionType,Animator animator)
//APPEARING:元素在容器中出现时所定义的动画
//DISAPPEARING:元素在容器中消失时所定义的动画
//CHANGE_APPEARING:由于容器中要显现一个新的元素,其他需要变化的元素所应用的动画。
//CHANGE_DISAPPEARING:当容器中某个元素消失时,其他需要变化的元素所应用的动画。
四、开源动画库NineOldAndroids
简介:Android3.0推出了全新的AnimationApi,使用起来很方便,但是不能在3.0以下版本中使用。NineOldAndroids是一个可以在任意Android版本上使用AnimationAPI,和Anidroid 3.0中的API类似。
第五章:动画进阶
1.利用PathMeasure实现路径动画
简介:AndroidSDK提供了一个非常有用的API来帮助开发者实现这样一个Path路径点的座标追踪,这个API就是PathMeasure,通过它就可以实现复杂的动画效果。
(1)初始化方法:
PathMeasure pathMeasure = new PathMeasure();
或
PathMeasure(Path path,boolean forceClosed);
(2)绑定路径:
setPath(Path path, boolean forceClosed)
(3)简单函数使用
//获取计算的路径长度
public float getLength();
//用于判断测量Path时是否计算闭合
public boolean isClosed();
//用于跳转到下一条曲线的函数
public boolean nextContour();
//用于截取整个Path中的某个片段,通过参数startD和stopD来控制截取的长度,并将截取后
//的Path保存到参数dst中。最后一个参数startWithMoveTo表示起始点是否使用moveTo将路径的
//新起始点移到结果Path的起始点,通常设置为true,以保证每次截取的Path都是正常的,完整的,
//通常和dst一起使用,因为dst中保存的Path是被不断添加的,而不是每次被覆盖的。
public boolean getSegment(float startD,float stopD,Path dst,boolean startWithMoveTo);
//用于得到路径上某一长度的位置以及该位置的正切值。
//distance:距离Path起始点的长度,取值范围为0<=distance<=getLength。
//pos:该点的座标值。 tan:该点的正切值。
public boolean getPosTan(float distance,float[] pos,float[] tan);
//用于得到路径上某一长度的位置以及该位置的正切值的矩阵
public boolean getMatrix(float distance,Matrix matrix,int flags);
例:
public void ondraw(){
Path path = new Path();
path.addRect(-50,-50,50,50,Path.Direction.CW);
path.addRect(-50,-50,50,50,Path.Direction.CW);
path.addRect(-50,-50,50,50,Path.Direction.CW);
canvas.drawPath(Path,paint);
PathMeasure measure = new PathMeasure(path,false);
do{
float len = measure.getLength();
Log.e(TAG,"len="+len);
}while(measure.nextContour());
}
2.SVG动画
简介:Goole在Android 5.0中增加了对SVG图形的支持。对于5.0以下的机型,可以通过引入com.android.support:appcompat-v7:23.4.0及以上版本进行支持。android并没有对原生的SVG图像语法进行支持,而是以一种简化的方式对SVG进行兼容,也就是通过使用它的path标签,几乎可以实现SVG中的其他所有标签。
在Android中,SVG矢量图是使用标签定义的,并存放在res/drawable/目录下
(1)例:一段简单的SVG图像代码定义如下
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http:/schemas.android.com/apk/res/android"
android:width="200dp"
android:height="100dp"
android:viewporWidth="100"
android:viewportHeight="50">
<path
android:name = "bar"
andorid:pathData = "M50,23 L100,25"
android:strokeWidth = "2"
android:strokeColor = "@android:color/darker_gray"/>
</vector>
- width与height属性:表示该SVG图形的具体大小。
- viewportWidth与viewportHeight属性:表示SVG图形划分的比例。
- path中字母M表示moveTo,字母L表示lineTo。
- vector标签指定的是画布带下,而path标签则指定的是路径内容
(2)path标签
常用属性:
- android:name:声明一个标记,类似于ID,便于对其做动画的时候顺利地找到该节点。
- android:pathData:对SVG矢量图的描述。
- android:strokeWidth:画笔的宽度。
- android:fillColor:填充颜色。
- android:fillAlpha:填充颜色的透明度。
- android:strokeColor:描边颜色。
- android:strokeWidth:描边宽度。
- android:strokeAlpha:描边透明度。
- android:strokeLineJoin:用于指定折线拐角形状,取值有miter、round、bevel。
- android:strokeLineCap:画出线条的终点形状,取值有butt/round/square
- android:strokeMiterLimit:设置斜角的上限。
- android:trimPathStart:用于指定路径从哪开始,取值为0~1,表示路径开始位置的百分比。
- android:trimPathEnd:用于指定路径的结束位置,取值为0~1,表示路径结束位置的百分比。
- android:trimPathOffset:用于指定结果路径的位移距离,取值为0~1,当取值为0时,不进行位移;当取值为1时,位移整条路径的长度。
- android:pathData:在path标签中,主要通过pathData属性来指定SVG图像的显示内容。
pathData属性除M和L指令以外,还有更多的指令:
- M = moveto(M X,Y):将画笔移动到指定的座标位置。
- L = lineto(L X,Y):画直线到指定的座标位置。
- H = horizontal lineto(H X):画水平线到指定的X座标位置。
- V = vertical lineto(V Y):画垂直线到指定的Y座标位置。
- C = curveto(C X1,Y1,X2,Y2,ENDX,ENDY):三阶贝济埃曲线。
- S = smooth curveto(S X2,Y2,ENDX,ENDY):三阶贝济埃曲线。
- Q = quadratic Belzier curve(Q X,Y,ENDX,ENDY):二阶贝济埃曲线。
- T = smooth quadratic Belzier curveto(T ENDX,ENDY):映射前面路径后的终点。
- A = elliptical Arc(A RX,RY,XROTATION,FLAG1,FLAG2,X,Y):弧线。
- Z = closepath():关闭路径。
(3)Group标签
简介:用于定义一系列路径后者将path标签分组。
group标签常用属性:
- android:name:组的名字,用于与动画相关联
- android:rotation:指定该组图像的旋转度数
- android:pivotX:定义缩放和旋转改组时的X参考点
- android:pivotY:定义缩放和旋转该组时的Y参考点
- android:scaleX:指定该组X轴缩放大小
- android:scaleY:指定该组Y轴缩放大小
- android:translateX:指定该组沿X轴平移的距离
- android:translateY:指定该组沿Y轴平移的距离
(4)制作SVG图像
1.设计软件:直接使用illustrator或在线SVG工具制作SVG图像
2.Iconfont:把你想要的矢量图标打包成一个.ttf文件,在Android中应用这个.ttf文件来方便地加载和指定各种图标。通过Iconfont公共网站可以下载到每个图标所对应的SVG文件。例:阿里巴巴矢量图库。
(5)在Android中引入SVG图像
Android不支持SVG图像解析,必须将SVG图像转换成vector标签描述:
1.在线转换
2.通过AndroidStudio引入
3.Android中使用ImageView显示SVG图像
- 1)引入兼容包:appcompat
- 2) build.gradle添加对Vector兼容性支持
- 3)使用: app:srcCompat = "@drawable/svg_line" , setImageResource(R.drawable.svg_line);
3.动态Vector
简介:实现Vector动画,首先需要Vector图像和它所对应的动画。
(1)Vector图像
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="200dp"
android:height="100dp"
android:viewportWidth="100"
android:viewportHeight="50">
<path
android:name="bar"
android:pathData="M50,23 L100,25"
android:strokeWidth="2"
android:strokeColor="@android:color/darker_gray"/>
</vector>
(2)定义Vector图像动画
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:propertyName="trimPathStart"
android:valueFrom="0"
android:valueTo="1"
android:duration="2000"/>
(3)Vector图像关联动画
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/svg_line">
<target
android:name="bar"
android:animation="@animator/anim_trim_start"/>
</animated-vector>
(4)代码使用
public void start(){
ImageView imageView = (ImageView)findViewById(R.id.iv);
AnimatedVectorDrawableCompat compat = AnimatedVectorDrawableCompat.create(this,R.drawable.line_animateed_vector);
imageView.setImageDrawable(animatedVectorDrawableCompat);
((Animatable)imageView.getDrawable()).start();
}
第六章:Paint基本使用
1.硬件加速
简介:在API11之前是没有GPU的概念的;在API11之后,在程序集中加入了对GPU加速的支持;在API14之后,硬件加速功能是默认开启的。硬件加速提高了Android系统显示和刷新的速度。
缺点:
(1)兼容性问题:由于是将绘制函数转换成OpenGL指令来绘制,所以必然会存在OpenGL并不能完全支持原始绘制函数的问题,从而造成在打开GPU加速时效果会失效的问题。
(2)内存消耗问题:由于需要OpenGL指令,所以需要把系统中与OpenGL相关的包加载到内存中来。单纯的OpenGL API调用会占用8MB内存,实际内存占用会更大。
(3)电量消耗问题:多使用一个部件,耗电相应增加。
禁用GPU:针对不同的类型,Android提供了不同的禁用方法,分Application、Activity、Window、View 4个层级。
(1)在AndroidManifest.xml文件中为application标签添加如下属性,即可为整个应用程序开启/关闭硬件加速
<application android:hardwareAccelerated = "true" ...>
(2)在activity标签下使用hardwareAccelerated属性开启或关闭硬件加速。
<activity android:hardwareAccelerated = "false"/>
(3)在Window层级上使用如下代码开启硬件加速(在View层级上不支持开启硬件加速):
getWindow().setFlages(
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
);
(4)在View层级上使用如下代码关闭硬件加速(在View层级上不支持开启硬件加速):
setLayerType(View.LAYER_TYPE_SOFTWARE,null);
2.文字
(1)canvas.DrawText()函数
//text:要绘制的文字
//x:绘制原点x座标
//y:绘制原点y座标
//paint:用来作画的画笔
public void drawText(String text,float x,float y,Paint paint)
(2)paint.setTextAlign()函数
- Paint.Align.LEFT:从原点x.y左侧开始绘制
- Paint.Align.CENTER:使原点x.y正好在所要绘制矩形的正中间
- Paint.Align.RIGHT:从原点x.y右侧开始绘制
(3)绘制四线格与FontMetrics
简介:除了基线以外,系统在绘制文字时还有4条线,分别是ascent、descent、top和bottom。基线的位置是在构造drawText()函数时由参数y来决定的。而这4条线是由FontMetrics计算出来的
- ascent:系统推荐的,在绘制单个字符时,字符应当的最高高度所在线
- descent:系统推荐的,在绘制单个字符时,字符应当的最低高度所在线
- top:可绘制的最高高度所在线
- bottom:可绘制的最低高度所在线
这4个成员变量的含义与值的计算方法分别如下:
- ascent = ascent线的y座标 - baseline线的y座标。
- descent = descent线的y座标 - baseline线的y座标。
- top = top线的y座标 - baseline线的y座标。
- bottom = bottom线的y座标 - baseline线的y座标。
//获取FontMetrics对象
Paint paint = new Paint();
Paint.FontMetrics fm = paint.getFontMetrics();
Paint.FontMetricsInt fmInt = paint.getFontMetricsInt();
字符串所占区域的高度和宽度
1)高度
Paint.FontMetricsInt fm = paint.getFontMetricsInt();
int top = baseLineY + fm.top;
int bottom = baseLineY + fm.bottom;
//所占区域的高度
int height = bottom - top;
2)宽度
Paint paint = new Paint();
paint.setTextSize(120);
//获取宽度
int width = (int)paint.measureText("XXXXXX");
3)最小矩形
//获取指定字符串所对应的最小矩形,以(0.0)点所在位置为基线
public void getTextBounds(String text,int start,int end,Rect bounds);
3.Paint常用函数
(1)基本设置函数
- reset():重置画笔
- setColor(int color):给画笔设置颜色值
- setARGB():给画笔设置颜色值
- setAlpha(int a):设置画笔透明度
- setStyle(Paint.Style style):设置画笔样式
- setStrokeWidth(float width):设置画笔宽度
- setStrokeMiter(float miter):设置画笔是否抗锯齿
- setAntiAlias(boolean aa):设置画笔的倾斜度
- setPathEffect(PathEffect effect):设置路径样式
- setStrokeCap(Paint.Cap cap):设置线帽样式
(2)字体相关函数
- setTextSize(float textSize):设置文字大小
- setFakeBoldText(boolean fakeBoldText):设置是否为粗体文字
- setStrikeThruText(boolean strikeThruText):设置带有删除线效果
- setUnderlineText(boolean underlineText):设置下划线
- setTextAlign(Paint.Align align):设置开始绘图点位置
- setTextScaleX(float scaleX):设置水平拉伸
- setTextSkewX(float skewX):设置字体水平倾斜度
- setTypeface(Typeface typeface):设置字体样式
- setLinearText(boolean linearText):设置是否打开线性文本标识
三、Demo地址
Github:https://github.com/DayorNight/BLCS
码云:https://gitee.com/blcs/BLCS
apk下载体验地址:https://www.pgyer.com/BLCS
四、内容推荐
简书:
如果你觉得写的不错或者对您有所帮助的话
不妨顶一个【微笑】,别忘了点赞、收藏、加关注哈
看在花了这么多时间整理写成文章分享给大家的份上,记得手下留情哈
您的每个举动都是对我莫大的支持