Android實(shí)現(xiàn)雅虎新聞?wù)虞d視差動(dòng)畫(huà)效果
基礎(chǔ)知識(shí)
繼 Android實(shí)現(xiàn)旋轉(zhuǎn)動(dòng)畫(huà)的兩種方式 我們了解了 Android實(shí)現(xiàn)旋轉(zhuǎn)的兩種基本方法之后,我們來(lái)寫(xiě)一個(gè)綜合案例
效果展示

代碼實(shí)現(xiàn)
實(shí)現(xiàn)思路
從效果中我們可以看到 可以將其分為三個(gè)動(dòng)畫(huà):
1、旋轉(zhuǎn)動(dòng)畫(huà)(Android實(shí)現(xiàn)旋轉(zhuǎn)動(dòng)畫(huà)的兩種方式)
2、聚合動(dòng)畫(huà)
3、擴(kuò)展動(dòng)畫(huà)
代碼展示
package com.wust.mydialog;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AnticipateInterpolator;
import android.view.animation.LinearInterpolator;
import androidx.annotation.Nullable;
/**
* ClassName: com.wust.mydialog.MyRotateView <br/>
* Description: <br/>
* date: 2021/8/7 12:13<br/>
*
* @author yiqi<br />
* @QQ 1820762465
* @微信 yiqiideallife
* @技術(shù)交流QQ群 928023749
*/
public class MyRotateView extends View {
//設(shè)置旋轉(zhuǎn)間隔時(shí)間
private int SPLASH_CIRCLE_ROTATE_TIME = 1000;
//設(shè)置中心圓半徑
private float CENTER_CIRCLE_RADIUS;
private float SMALL_CIRCLE_RADIUS;
private float mCurrentSingle = 0f;
private int[] mColorArray;
private Paint mCirclePaint;
private ValueAnimator va;
private Matrix mSpaceMatrix;
private LoadingState mLoadingState;
//當(dāng)前中心圓半徑
private float mCurCenterRadius;
private float mDiagonal;
private float mLineWidth;
public MyRotateView(Context context) {
super(context);
}
public MyRotateView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyRotateView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
//初始化參數(shù)
initParams(width, height);
setMeasuredDimension(width, height);
}
private void initParams(int w, int h) {
//設(shè)置中心圓半徑
CENTER_CIRCLE_RADIUS = 1 / 4.0f * w;
//設(shè)置小圓的半徑
SMALL_CIRCLE_RADIUS = 1 / 25.0f * w;
//獲取小球顏色
mColorArray = getResources().getIntArray(R.array.splash_circle_colors);
//初始化畫(huà)筆
mCirclePaint = new Paint();
mCirclePaint.setDither(true);
mCirclePaint.setAntiAlias(true);
//初始化旋轉(zhuǎn)矩陣
mSpaceMatrix = new Matrix();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mLoadingState == null) {
mLoadingState = new RotateState();
}
mLoadingState.onDraw(canvas);
}
//定義 狀態(tài) 抽象類(lèi)
private abstract class LoadingState {
public abstract void onDraw(Canvas canvas);
}
//旋轉(zhuǎn)動(dòng)畫(huà)
private class RotateState extends LoadingState {
public RotateState() {
//計(jì)算每個(gè)小球的間隔
double spaceAngle = 360.0d / mColorArray.length;
//初始化旋轉(zhuǎn)矩陣
mSpaceMatrix.reset();
mSpaceMatrix.postRotate((float) spaceAngle, getWidth() / 2, getHeight() / 2);
va = ObjectAnimator.ofFloat(0f, 360.0f);
va.setDuration(SPLASH_CIRCLE_ROTATE_TIME);
va.setRepeatCount(ValueAnimator.INFINITE);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCurrentSingle = (float) animation.getAnimatedValue();
invalidate();
}
});
va.setInterpolator(new LinearInterpolator());
va.start();
}
@Override
public void onDraw(Canvas canvas) {
//繪制背景
canvas.drawColor(Color.WHITE);
//利用旋轉(zhuǎn)畫(huà)布法
canvas.save();
canvas.rotate(mCurrentSingle, getWidth() / 2, getHeight() / 2);
for (int i = 0; i < mColorArray.length; i++) {
canvas.concat(mSpaceMatrix);
//為 每個(gè)球 畫(huà)筆 設(shè)置顏色
mCirclePaint.setColor(mColorArray[i]);
//利用旋轉(zhuǎn)畫(huà)布法
float cx = getWidth() / 2 + CENTER_CIRCLE_RADIUS;
float cy = getHeight() / 2;
canvas.drawCircle(cx, cy, SMALL_CIRCLE_RADIUS, mCirclePaint);
}
canvas.restore();
}
}
//聚合動(dòng)畫(huà)
private class ScaleState extends LoadingState {
public ScaleState() {
va = ObjectAnimator.ofFloat(CENTER_CIRCLE_RADIUS,0);
va.setDuration(SPLASH_CIRCLE_ROTATE_TIME);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mCurCenterRadius = (float) animation.getAnimatedValue();
invalidate();
}
});
va.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mLoadingState = new ExtentState();
}
});
va.setInterpolator(new AnticipateInterpolator());
va.start();
}
@Override
public void onDraw(Canvas canvas) {
//繪制背景
canvas.drawColor(Color.WHITE);
//繪制小圓
canvas.save();
//這句話也不能調(diào),要不然不連貫
canvas.rotate(mCurrentSingle,getWidth()/2,getHeight()/2);
for (int i = 0; i < mColorArray.length; i++) {
mCirclePaint.setColor(mColorArray[i]);
canvas.concat(mSpaceMatrix);
canvas.drawCircle(mCurCenterRadius+getWidth()/2,getHeight()/2,SMALL_CIRCLE_RADIUS,mCirclePaint);
}
canvas.restore();
}
}
//擴(kuò)展動(dòng)畫(huà)
public class ExtentState extends LoadingState{
public ExtentState() {
//初始化對(duì)角線
float cx = getWidth()/2.0f;
float cy = getHeight()/2.0f;
mDiagonal = (float) Math.sqrt(Math.pow(cx,2)+Math.pow(cy,2));
va = ObjectAnimator.ofFloat(mDiagonal,0);
va.setDuration(3000);
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mLineWidth = (float) animation.getAnimatedValue();
invalidate();
}
});
va.setInterpolator(new LinearInterpolator());
va.start();
}
@Override
public void onDraw(Canvas canvas) {
mCirclePaint.setColor(Color.WHITE);
mCirclePaint.setStrokeWidth(mLineWidth*2);//元的半徑只會(huì)到達(dá)線寬的中間,所以要乘2
mCirclePaint.setStyle(Paint.Style.STROKE);
canvas.drawCircle(getWidth()/2,getHeight()/2,mDiagonal,mCirclePaint);
}
}
public void dismiss() {
if (mLoadingState instanceof RotateState){
//取消旋轉(zhuǎn)值動(dòng)畫(huà)
va.cancel();
//創(chuàng)建縮放動(dòng)畫(huà)
mLoadingState = new ScaleState();
//刷新布局、可以寫(xiě)也可以不寫(xiě)
// invalidate();
}
}
}
到此這篇關(guān)于Android實(shí)現(xiàn)雅虎新聞?wù)虞d視差動(dòng)畫(huà)效果的文章就介紹到這了,更多相關(guān)android視覺(jué)動(dòng)畫(huà)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Android仿網(wǎng)易新聞圖片詳情下滑隱藏效果示例代碼
- Android開(kāi)發(fā)實(shí)現(xiàn)自定義新聞加載頁(yè)面功能實(shí)例
- Android UI設(shè)計(jì)與開(kāi)發(fā)之PopupWindow仿騰訊新聞底部彈出菜單
- Android RecyclerView仿新聞?lì)^條的頻道管理功能
- Android網(wǎng)絡(luò)編程之簡(jiǎn)易新聞客戶(hù)端
- Android模擬實(shí)現(xiàn)網(wǎng)易新聞客戶(hù)端
- Android 模擬新聞APP顯示界面滑動(dòng)優(yōu)化實(shí)例代碼
- Android實(shí)現(xiàn)基本功能的新聞應(yīng)用
相關(guān)文章
Android 手機(jī)衛(wèi)士實(shí)現(xiàn)平移動(dòng)畫(huà)示例
這篇文章主要介紹了Android 手機(jī)衛(wèi)士實(shí)現(xiàn)平移動(dòng)畫(huà)的實(shí)例代碼,本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-10-10
Android編程之簡(jiǎn)單啟動(dòng)畫(huà)面實(shí)現(xiàn)方法
這篇文章主要介紹了Android編程之簡(jiǎn)單啟動(dòng)畫(huà)面實(shí)現(xiàn)方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了開(kāi)機(jī)啟動(dòng)畫(huà)面的制作步驟及布局、Activity跳轉(zhuǎn)、權(quán)限控制等的相關(guān)操作技巧,需要的朋友可以參考下2016-11-11
android獲取附近藍(lán)牙設(shè)備并計(jì)算距離的實(shí)例代碼
下面小編就為大家分享一篇android獲取附近藍(lán)牙設(shè)備并計(jì)算距離的實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01
android實(shí)現(xiàn)系統(tǒng)信息推送
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)系統(tǒng)信息推送,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
ImageView簡(jiǎn)單加載網(wǎng)絡(luò)圖片實(shí)例代碼
使用ImageView實(shí)現(xiàn)簡(jiǎn)單加載網(wǎng)絡(luò)圖片的功能,示例代碼如下,感興趣的朋友可以參考下哈,希望對(duì)大家有所幫助2013-06-06
Android開(kāi)發(fā)Input系統(tǒng)觸摸事件分發(fā)
這篇文章主要為大家介紹了Android開(kāi)發(fā)Input系統(tǒng)觸摸事件分發(fā)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
Android PhoneWindowManager監(jiān)聽(tīng)屏幕右側(cè)向左滑動(dòng)實(shí)現(xiàn)返回功能
這篇文章主要介紹了Android PhoneWindowManager監(jiān)聽(tīng)屏幕右側(cè)向左滑動(dòng)實(shí)現(xiàn)返回功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04
Android Studio 3.3.2 正式版的安裝教程圖解
這篇文章主要介紹了Android Studio 3.3.2 正式版的安裝教程圖解,本文分步驟通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下2020-02-02

