Android动画特效之Animator属性动画实现_Angel-杭州的博客-CSDN博客

  我在百忙之中抽出宝贵时间来实现Android动画特效,也就是Android Animator动画效果,使用Animator属性动画来实现平移、缩放、透明度、旋转等动画效果,采用ValueAnimatorObjectAnimator类来满足动画特效,以及ValueAnimatorObjectAnimator类的使用。

  要实现Android动画特效,首先要掌握如何自定义View。因为不管实现Android动画特效,还是工作当中业务需求功能实现,都会经常接触到自定义View,实现自定义View也是重中之重,作为Android开发者,需要自定义View是必不可少的。

自定义view使用步骤如下:

1. 编写布局文件

2. 实现构造方法

3. 初始化UI

4. 提供对外的方法

5. 在布局当中引用该控件

6. activity中使用

因此通过示例来详解如何自定义view。

1.首先编写布局文件layout_center_view.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/rlDeviceView"><ImageViewandroid:id="@+id/ivDeviceView"android:layout_width="0dp"android:layout_height="0dp"/>
</RelativeLayout>

2. 实现构造方法

3. 初始化UI

4. 提供对外的方法

CenterView.java

// 因为我们的布局采用RelativeLayout,所以这里继承RelativeLayout
public class CenterView extends RelativeLayout {private static final String TAG = "CenterView";private ImageView ivDeviceView;private int deviceDpWith;private int devicePxWith;private Context context;public CenterView(Context context) {this(context, null);}public CenterView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public CenterView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initView(context);}// 初始化UI,可根据业务需求设置默认值private void initView(Context context) {this.context = context;View view = LayoutInflater.from(context).inflate(R.layout.layout_center_view, null, false);ivDeviceView = view.findViewById(R.id.ivDeviceView);devicePxWith = Constants.CENTER_LAYOUT_PIX_SIZE;// 先添加addView后,再获取ivDeviceView.getLayoutParams(),否则会报空refreshing();addView(view);}private void refreshing() {ivDeviceView.setImageResource(R.mipmap.wifi_icon);// 拿到的是ivDeviceView父布局的参数,也就是RelativeLayout。LayoutParams params= (LayoutParams) ivDeviceView.getLayoutParams();params.width = devicePxWith;params.height = devicePxWith;ivDeviceView.setLayoutParams(params);}public void setDeviceWith(int deviceWith) {this.deviceDpWith = deviceWith;devicePxWith = ScreenUtil.dp2px(context, deviceDpWith);refreshing();}public void setDeivceImageResource(int resId) {ivDeviceView.setImageResource(resId);}// 重写onMeasure方法进行测量@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(measureWith(widthMeasureSpec), measureHeight(heightMeasureSpec));}private int measureWith(int measureSpec) {int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);// 设置一个默认值,就是这个View的默认宽度为xxx,int result = Constants.CENTER_LAYOUT_PIX_SIZE;if (specMode == MeasureSpec.AT_MOST) { // 相当于我们设置成wrap_contentresult = specSize;} else if (specMode == MeasureSpec.EXACTLY) { // 相当于我们设置成match_content或者一个具体的值result = specSize;}return result;}private int measureHeight(int measureSpec) {int specMode = MeasureSpec.getMode(measureSpec);int specSize = MeasureSpec.getSize(measureSpec);// 设置一个默认值,就是这个View的默认宽度为xxx,int result = Constants.CENTER_LAYOUT_PIX_SIZE;if (specMode == MeasureSpec.AT_MOST) { // 相当于我们设置成wrap_contentresult = specSize;} else if (specMode == MeasureSpec.EXACTLY) { // 相当于我们设置成match_content或者一个具体的值result = specSize;}return result;}
}

上面并不难,都有注释,重要的是通过onMeasure方法需要重新测量自身的view。

  1. 在布局当中引用该控件本示例暂不引用,通过代码去引用它。

在编写一个layout_base_view.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"/>

从上面可以看出,里面没有任何子view,声明RelativeLayout即可。

BaseLayoutView.java

// 因为我们的布局采用RelativeLayout,所以这里继承RelativeLayout
public class BaseLayoutView extends RelativeLayout {private static final String TAG = "BaseLayoutView";private float centerX = 0f;private float centerY = 0f;public BaseLayoutView(Context context) {this(context, null);}public BaseLayoutView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public BaseLayoutView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initView(context);}// 初始化UI,可根据业务需求设置默认值private void initView(Context context) {View view = LayoutInflater.from(context).inflate(R.layout.layout_base_view, null, false);addView(view);centerX = Constants.SCREEN_WIDTH / Constants.FLOAT_TWO;centerY = Constants.SCREEN_HEIGHT / Constants.FLOAT_TWO - ScreenUtil.getStatusBarHeight();Log.i(TAG, "initView getStatusBarHeight= " + ScreenUtil.getStatusBarHeight());Log.i(TAG, "initView centerX= " + centerX + " centerY= " + centerY);}// 返回中心X坐标public float getCenterX() {return centerX;}// 返回中心Y坐标public float getCenterY() {return centerY;}
}

BaseLayoutView是一个基础视图,初始化的时候计算下view的中心坐标,注意:需要减去状态栏的高度。这样我们就可以拿到该BaseLayoutView的中心坐标,并对外提供方法可以访问到BaseLayoutView的x、y坐标。

  这样上面的自定义View已经编好了,分别是CenterView和BaseLayoutView类。接下来我们看activity里面怎么实现呢。

在编写一个activity的activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/rl_layout"android:layout_width="match_parent"android:layout_height="match_parent"/>

上面可以看出,里面没有任何的子view,仅声明RelativeLayout和id即可。

看下Activity代码怎么写呢。

MainActivity.java

public class MainActivity extends AppCompatActivity {private RelativeLayout relativeLayout;private SolarControl solarControl;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {relativeLayout = findViewById(R.id.rl_layout);solarControl = new SolarControl(relativeLayout);}@Overrideprotected void onDestroy() {super.onDestroy();if (solarControl != null) {solarControl.release();solarControl = null;}}
}

上面可以看出,RelativeLayout实例化一个对象,拿到布局里面的id即可,将RelativeLayout对象传递给SolarControl类即可,剩下的事交给SolarControl类来处理。SolarControl类主要是负责UI显示和业务交互的地方,当前在activity的onDestroy方法内部调用SolarControl类的release()来释放资源,为什么这么做呢?

我们来看下SolarControl类里面做了什么事情。

SolarControl.java

public class SolarControl {private static final String TAG = "SolarControl";private ViewGroup parentView;private BaseLayoutView baseView;private CenterView centerView;public SolarControl(ViewGroup parent) {parentView = parent;baseView = new BaseLayoutView(parentView.getContext());initView();}private void initView() {centerView = new CenterView(baseView.getContext());float centerX = baseView.getCenterX() - Constants.CENTER_LAYOUT_PIX_SIZE / Constants.FLOAT_TWO;float centerY = baseView.getCenterY() - Constants.CENTER_LAYOUT_PIX_SIZE / Constants.FLOAT_TWO;centerView.setX(centerX);centerView.setY(centerY);Log.i(TAG, "initView centerX= " + centerX + " centerY= " + centerY);baseView.addView(centerView);parentView.addView(baseView);}public void release() {if (baseView != null) {baseView.removeView(centerView);parentView.removeView(baseView);baseView = null;parentView = null;}if (centerView != null) {centerView = null;}}
}

  首先SolarControl类的构造方法传入的是ViewGroup对象,而ViewGroup是容器,RelativeLayout、LinearLayoutConstraintLayout等等都继承ViewGroup。分别实例化CenterView和BaseLayoutView对象,并计算CenterView的x、y坐标,CenterView坐标拿到的是view左上角的坐标,因此想让view居中,需要重新计算坐标。x、y分别减去CenterView宽度的一半,计算出来的坐标就是让CenterView在整个屏幕居中显示。然后将CenterView对象通过addView方法添加到BaseLayoutView对象里面,也可以理解CenterView是BaseLayoutView的子view、子视图。同样通过addView方法添加到ViewGroup容器中,也就是需要把BaseLayoutView视图添加到activity_main.xml布局里面。声明release方法提供外部调用,方法内部就是移除view,释放引用,目的就是activity退出的时候释放内存,这就是编码过程中需要考虑到优化内存的地方。

  接下来运行一下项目,看看效果。

自定义的CenterView在整个屏幕居中了,基本功能就实现了,通过例子,我们需要掌握如何自定义View,在开发过程中,根据需求难免会需要使用自定义View来实现。上面例子已经实现了,为了后面的Android动画特效项目开发做铺垫,搜索并关注公众号“Android技术迷”关注后可文章,感谢各位关注。

Android动画特效之自定义View相关推荐

  1. Android动画特效之Animator属性动画实现

    Android动画特效之自定义view: Android动画特效之自定义view_Angel-杭州的博客-CSDN博客_android view 设置动画 由于上期Android动画特效之自定义Vie ...

  2. Android动画效果之自定义ViewGroup添加布局动画

    Android动画效果之自定义ViewGroup添加布局动画 前言: 前面几篇文章介绍了补间动画.逐帧动画.属性动画,大部分都是针对View来实现的动画,那么该如何为了一个ViewGroup添加动画呢 ...

  3. android炫酷的自定义view,Android自定义View实现炫酷进度条

    本文实例为大家分享了Android实现炫酷进度条的具体代码,供大家参考,具体内容如下 下面我们来实现如下效果: 第一步:创建attrs文件夹,自定义属性: 第二步:自定义View: /** * Cre ...

  4. Android动画特效第二弹——QQ聊天彩蛋蹦蹦哒

    效果 在比较新的版本的手机QQ中,有许多的隐藏彩蛋.当我们发送一些特定关键字的时候,屏幕上回掉下一些到处乱蹦表情,比如输入么么哒.节日快乐这些字的时候,都会有不同的表情掉落,看上去灰常酷炫.  那么我 ...

  5. HenCoder Android 开发进阶:自定义 View 1-5 绘制顺序

    这期是 HenCoder 自定义绘制的第 1-5 期:绘制顺序 之前的内容在这里:  HenCoder Android 开发进阶 自定义 View 1-1 绘制基础  HenCoder Android ...

  6. android动画介绍之 自定义Animation动画实现qq抖一抖效果

    昨天我们介绍了Animation的基本用法.小伙伴们了解的怎么样了?如果还没有了解过Animation的小伙伴可以看看这篇博客 android动画介绍--Animation 实现loading动画效果 ...

  7. Android自定义控件面试题,自定义View面试总结

    本着针对面试,不负责任的态度,写下<面试总结>系列.本系列记录面试过程中各个知识点,而不是入门系列,如果有不懂的自行学习. 自定义View三种方式,组合现有控件,继承现有控件,继承View ...

  8. Android Paint应用之自定义View实现进度条控件

    在上一篇文章<Android神笔之Paint>学习了Paint的基本用法,但是具体的应用我们还没有实践过.从标题中可知,本文是带领读者使用Paint,自定义一个进度条控件. 上图就是本文要 ...

  9. 【Android 应用开发】自定义View 和 ViewGroup

    一. 自定义View介绍 自定义View时, 继承View基类, 并实现其中的一些方法. (1) ~ (2) 方法与构造相关 (3) ~ (5) 方法与组件大小位置相关 (6) ~ (9) 方法与触摸 ...

最新文章

  1. 小作文十大必背范文:五星级真题
  2. 微信小程序开发的完整流程介绍,新手必读
  3. 得到app文稿导出_再见了扫描仪!微信打开这个功能,一键将纸质文稿扫描成电子档...
  4. 初识linux之给我一个家
  5. 设计模式中的观察者模式
  6. java 解密后为空_java RSA加密解密
  7. Centos7 安装gitlab 8.7.5
  8. linux就业技术指导,学linux前景怎么样
  9. 20 Valid Parentheses
  10. CountDownLacth详解
  11. python爬虫网页pdf_爬虫实战【3】Python-如何将html转化为pdf(PdfKit)
  12. C#:泛型Range助手
  13. call和apply的作用和不同
  14. php 拉丁文转中文,拉丁文在线翻译_拉丁语在线翻译
  15. 骇客(Hacker)用语
  16. php写poc,0day Poc编写指南(实战篇)
  17. 台式计算机睡眠状态功率,电脑选择待机休眠的时候大约耗电功率是多少W?
  18. 深拷⻉和浅拷⻉区别是什么?
  19. 安卓开发用什么语言?一次违反常规的安卓大厂面试经历,含BATJM大厂
  20. ArkID 一账通:企业级开源IDaaS/IAM平台系统

热门文章

  1. [C++实现 设计模式(6)] : 代理模式
  2. 社交+汽车保养+电商
  3. 投递简历用什么邮箱好?TOM163.net邮箱助你轻松搞定Offer
  4. 半监督主题模型Correlation Explanation
  5. 【技术史】人类历史上的历次重大技术变革的背后的核心驱动力是什么?
  6. EditText 获取不到焦点
  7. 索尼a5100_索尼微单家族全家福性能、价格大对比,看看哪款最适合你
  8. 求求各位大佬指点下,已经一天了
  9. CentOS7环境下MySQL定时备份
  10. 芝麻开门---打开测试心结