Android炫酷应用300例读书笔记五_1
第5章动画
121.使用ObjectAnimator创建上下振动动画
这里的知识点是PropertyValuesHolder 和 ObjectAnimator 的使用,最后实际的效果不是上下震动,而是组合震动。
public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
private ImageView mImageView;
private ObjectAnimator mObjectAnimator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.imageView);
//使用PropertyValuesHolder创建y坐标方向上的540到550的动画
PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofFloat("y",540,550);
//使用PropertyValuesHolder创建围绕y轴从0°旋转到到25°的动画
PropertyValuesHolder propertyValuesHolder2 = PropertyValuesHolder.ofFloat("rotationY",0,25);
//使用PropertyValuesHolder创建围绕x轴从0°旋转到到15°的动画
PropertyValuesHolder propertyValuesHolder3 = PropertyValuesHolder.ofFloat("rotationX",0,15);
//调用ofPropertyValuesHolder组合动画,同时执行这3种动画效果。
mObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(mImageView,propertyValuesHolder1,propertyValuesHolder2,propertyValuesHolder3);
//设置重复次 无限
mObjectAnimator.setRepeatCount(ObjectAnimator.INFINITE);
//设置重复类型 倒序播放 倒序就是例如定义的动画是从左到右的,实际播放是从右到左
mObjectAnimator.setRepeatMode(ObjectAnimator.REVERSE);
//执行一次动画的时间
mObjectAnimator.setDuration(90);
//开始执行动画
mObjectAnimator.start();
}
}
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/imageView"
android:layout_width="253dp"
android:layout_height="321dp"
app:srcCompat="@mipmap/flower"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="16dp"
android:layout_marginLeft="55dp"
app:layout_constraintLeft_toLeftOf="parent"/>
</android.support.constraint.ConstraintLayout>
参考链接:
Android 三种动画详解
122.使用ObjectAnimator实现沿弧线路径平移
这里的知识点是PathInterpolator。
public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
private ImageView mImageView;
private Button mButton;
private ObjectAnimator mObjectAnimator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.imageView);
mButton = (Button) findViewById(R.id.button);
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Path path = new Path();
RectF rectF = new RectF(50,50,700,700);
path.arcTo(rectF,600,600);//创建圆弧路径
mObjectAnimator = ObjectAnimator.ofFloat(mImageView,View.X,View.Y,path);
Path pathInterpolator = new Path();
pathInterpolator.lineTo(0.6f,0.9f);
pathInterpolator.lineTo(0.75f,0.2f);
pathInterpolator.lineTo(1f,1f);
mObjectAnimator.setInterpolator(new PathInterpolator(pathInterpolator));
mObjectAnimator.setDuration(5000);
mObjectAnimator.start();
}
});
}
}
xml
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/imageView"
android:layout_width="79dp"
android:layout_height="75dp"
app:srcCompat="@mipmap/home"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="109dp"
android:layout_marginLeft="213dp"
app:layout_constraintLeft_toLeftOf="parent"/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始动画"
android:layout_marginLeft="125dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="16dp"/>
</android.support.constraint.ConstraintLayout>
延伸:
再谈属性动画——介绍以及自定义Interpolator插值器
https://www.jianshu.com/p/9f65c163906c
Android动画插值器之PathInterpolator浅析
https://blog.csdn.net/u013279866/article/details/70142976
123.使用ObjectAnimator滚动显示多幅图像
这里的知识点是
ObjectAnimator ofInt(Object target, String propertyName, int... values)
target是要操作的控件,propertyName是控件的属性,int... values是可变长参数,指属性值从A变成B。
public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
private LinearLayout mLinearLayout;
private ObjectAnimator mObjectAnimator;
private Handler mHandler = new Handler();
private int[] mImages = {R.mipmap.image1,R.mipmap.image2,R.mipmap.image3};
private int mCurrentIndex;
private int mWidth;
private int mHeight;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
HorizontalScrollView horizontalScrollView = (HorizontalScrollView) findViewById(R.id.scrollView);
mLinearLayout = (LinearLayout) findViewById(R.id.linear_layout);
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
mWidth = dm.widthPixels;
mHeight = dm.heightPixels;
for (int i = 0; i < mImages.length ;i++){
ImageView imageView = new ImageView(MainActivity.this);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setImageResource(mImages[i]);
imageView.setLayoutParams(new RelativeLayout.LayoutParams(mWidth,mHeight));
mLinearLayout.addView(imageView);
}
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
if (mCurrentIndex >= mImages.length){
mCurrentIndex = 0;
}
//将mLinearLayout的scrollX属性值 在指定时间内 从mLinearLayout.getScrollX() 变成 mWidth * mCurrentIndex++,即每次向左移动一个屏幕宽度
mObjectAnimator = ObjectAnimator.ofInt(mLinearLayout,"scrollX",mLinearLayout.getScrollX(),
mWidth * mCurrentIndex++);
mObjectAnimator.setStartDelay(1000);
mObjectAnimator.setDuration(1000);
mObjectAnimator.start();
mHandler.postDelayed(this,2000);
}
},1000);
}
}
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<HorizontalScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:id="@+id/linear_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"/>
</HorizontalScrollView>
</LinearLayout>
124.使用ObjectAnimator实现图形数字形变
这里的知识点是android 矢量动画。
参考链接:
这个例子稍微简单点
SVG矢量动画机制
https://www.jianshu.com/p/c6d7f03980a1
这个例子稍微深入
Android高级动画(2)
https://cloud.tencent.com/developer/article/1329569
125.使用ObjectAnimator改变图像的色相值
知识点是ColorMatrix的使用。
https://developer.android.google.cn/reference/android/graphics/ColorMatrix?hl=en
public void setRotate (int axis, float degrees)
Set the rotation on a color axis by the specified values.
axis=0 correspond to a rotation around the RED color axis=1 correspond to a rotation around the GREEN color axis=2 correspond to a rotation around the BLUE color
首先,自定义一个view。
public class AnimImageView extends android.support.v7.widget.AppCompatImageView {
private float mDegree;
private ColorMatrix mColorMatrix;
public AnimImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mColorMatrix = new ColorMatrix();
}
public float getDegree() {
return mDegree;
}
public void setDegree(float degree) {
mDegree = degree;
}
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
mColorMatrix.setRotate(0,mDegree);//旋转R通道的色相值
mColorMatrix.setRotate(1,mDegree);//旋转G通道的色相值
mColorMatrix.setRotate(2,mDegree);//旋转B通道的色相值
//在图像中应用ColorMatrix对象
setColorFilter(new ColorMatrixColorFilter(mColorMatrix));
}
}
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<com.cc.uisample.AnimImageView
android:id="@+id/image_view"
android:src="@drawable/test"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="105dp"
/>
<Button
android:id="@+id/button_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始"
android:layout_marginLeft="66dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="16dp"/>
<Button
android:id="@+id/button_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="暂停"
android:layout_marginRight="65dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="16dp"/>
</android.support.constraint.ConstraintLayout>
public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
private ObjectAnimator mObjectAnimator;
private Button mButtonStart;
private Button mButtonPause;
private AnimImageView mAnimImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButtonStart = (Button) findViewById(R.id.button_start);
mButtonStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mObjectAnimator.isPaused()){
mObjectAnimator.resume();
}else {
mObjectAnimator.start();
}
}
});
mButtonPause = (Button) findViewById(R.id.button_pause);
mButtonPause.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mObjectAnimator.isStarted()){
mObjectAnimator.pause();
}
}
});
mAnimImageView = (AnimImageView) findViewById(R.id.image_view);
//这里ofFloat会判断是否存在函数setDegree(set+propertyName) ,所以这里propertyName填Degree
mObjectAnimator = ObjectAnimator.ofFloat(mAnimImageView,"Degree",0f,360f);
mObjectAnimator.setDuration(5000).setRepeatCount(ValueAnimator.INFINITE);
}
}
126.使用AnimatorSet组合多个ObjectAnimator
public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
private ObjectAnimator mObjectAnimator1;
private ObjectAnimator mObjectAnimator2;
private ObjectAnimator mObjectAnimator3;
private ObjectAnimator mObjectAnimator4;
private AnimatorSet mAnimatorSet;
private Button mButtonStart;
private Button mButtonStop;
private ImageView mImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButtonStart = (Button) findViewById(R.id.button_start);
mButtonStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mAnimatorSet.start();
}
});
mButtonStop = (Button) findViewById(R.id.button_stop);
mButtonStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mAnimatorSet.cancel();
}
});
mImageView = (ImageView) findViewById(R.id.image_view);
//透明度动画
mObjectAnimator1 = ObjectAnimator.ofFloat(mImageView,"alpha",1f,0f);
//旋转动画
mObjectAnimator2 = ObjectAnimator.ofFloat(mImageView,"rotation",1f,180f);
//水平缩放动画
mObjectAnimator3 = ObjectAnimator.ofFloat(mImageView,"scaleX",1.0f,0f);
//垂直缩放动画
mObjectAnimator4 = ObjectAnimator.ofFloat(mImageView,"scaleY",1.0f,0f);
mAnimatorSet = new AnimatorSet();
mAnimatorSet.play(mObjectAnimator1).with(mObjectAnimator2).
with(mObjectAnimator3).with(mObjectAnimator4);
mAnimatorSet.setDuration(9000);
}
}
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/image_view"
android:src="@drawable/test"
android:layout_width="300dp"
android:layout_height="300dp"
android:layout_marginRight="8dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="8dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="105dp"
/>
<Button
android:id="@+id/button_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开始"
android:layout_marginLeft="66dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="16dp"/>
<Button
android:id="@+id/button_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="停止"
android:layout_marginRight="65dp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="16dp"/>
</android.support.constraint.ConstraintLayout>
127.使用TypeEvaluator实现颜色过渡动画
知识点是使用ObjectAnimator创建颜色动画,并自定义TypeEvaluator,实现白色到绿色的效果。
其实这里是用到了ArgbEvaluator。原理可以看下面的链接。
参考链接:
自定义控件三部曲之动画篇(五)——ValueAnimator高级进阶(一)
https://blog.csdn.net/harvic880925/article/details/50546884
自定义控件三部曲之动画篇(七)——ObjectAnimator基本使用
https://blog.csdn.net/harvic880925/article/details/50598322
161_界面颜色亮度属性变化
https://blog.csdn.net/qq_33781658/article/details/51511385
0x00ffffff 和 0xff008000 是十六进制格式的ARGB数据。
在A中,00表示完全不可见,ff表示完全可见。
颜色可以通过android studio自带取色器去查看。
可以随便在控件中写一个颜色

然后点击颜色,打开取色器。

public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
private ObjectAnimator mObjectAnimator;
private LinearLayout mLinearLayout;
private Button mButtonStart;
private Button mButtonStop;
private ImageView mImageView;
private int mStartColor = 0x00ffffff;
private int mEndColor = 0xff008000;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLinearLayout = (LinearLayout) findViewById(R.id.linear_layout);
mButtonStart = (Button) findViewById(R.id.button_start);
mButtonStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mObjectAnimator.start();
}
});
mButtonStop = (Button) findViewById(R.id.button_stop);
mButtonStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mObjectAnimator.cancel();
}
});
mImageView = (ImageView) findViewById(R.id.image_view);
mObjectAnimator = ObjectAnimator.ofObject(mLinearLayout, "backgroundColor", new TypeEvaluator() {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
int startInt = (Integer) startValue;
int startA = (startInt >> 24) & 0xff;
int startR = (startInt >> 16) & 0xff;
int startG = (startInt >> 8) & 0xff;
int startB = startInt & 0xff;
int endInt = (Integer) endValue;
int endA = (endInt >> 24)& 0xff;
int endR = (endInt >> 16) & 0xff;
int endG = (endInt >> 8) & 0xff;
int endB = endInt & 0xff;
return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
(int)((startR + (int)(fraction * (endR - startR))) << 16) |
(int)((startG + (int)(fraction * (endG - startG))) << 8) |
(int)((startB + (int)(fraction * (endB - startB))));
}
}, mStartColor, mEndColor);
mObjectAnimator.setDuration(5000);
}
}
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/button_start"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="开始"/>
<Button
android:id="@+id/button_stop"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="停止"
/>
<LinearLayout
android:id="@+id/linear_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/image_view"
android:layout_width="match_parent"
android:layout_height="300dp"
android:src="@drawable/test"/>
</LinearLayout>
</LinearLayout>
128.通过trimPathEnd实现动态生成手指图形
知识点是矢量图形动画。关键点是矢量图形的。跳过。
129.使用ValueAnimator动态改变扇形转角
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.cc.uisample.AnimImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
public class AnimImageView extends View {
private float mDegrees;
private Paint mPaint;
private ValueAnimator mValueAnimator;
public AnimImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mPaint= new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
float startDegrees = 0f;
float endDegrees = 315f;
mValueAnimator = ValueAnimator.ofFloat(startDegrees,endDegrees);
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
mDegrees = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
mValueAnimator.setRepeatMode(ValueAnimator.REVERSE);
mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
mValueAnimator.setDuration(5000);
mValueAnimator.start();
}
@Override
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
int width = getWidth();
int height = getHeight();
//根据变化的角度绘制扇形
canvas.drawArc(new RectF(0,0,width,height),0f,mDegrees,true,mPaint);
}
}
public class MainActivity extends AppCompatActivity{
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}