亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android實現(xiàn)粒子中心擴散動畫效果

 更新時間:2024年02月25日 08:37:23   作者:時光少年  
粒子動畫效果相比其他動畫來說是非常復雜了的,主要涉及三個方面,粒子初始化、粒子位移、粒子回收等問題,本篇將實現(xiàn)兩種動畫效果,代碼基本相同,只是旋轉速度不一樣,需要的朋友可以參考下

前言

粒子動畫效果相比其他動畫來說是非常復雜了的,主要涉及三個方面,粒子初始化、粒子位移、粒子回收等問題,其中特別是粒子位移是最復雜的,涉及到的數(shù)學邏輯非常多,主要是各種三角函數(shù)、物理學公式等。

本篇將實現(xiàn)兩種動畫效果,代碼基本相同,只是旋轉速度不一樣,因此,本篇其實可以看作一篇模板文章,具體效果可以通過調節(jié)參數(shù)生成各種動畫

第一種動畫

第二種動畫

實現(xiàn)步驟

其實和以往的粒子效果一樣,粒子需要被管理起來,因此我們需要有容器、也需要粒子對象

粒子對象定義

下面是創(chuàng)建粒子對象的邏輯,基本屬性在注釋中了

static class Circle {
    int maxLength;  //最大運行距離
    float speed; //外擴速度
    float rotate; // 角速度
    private float degree; //起始角度
    private int y; //y坐標
    private int x; //x坐標
    private int color; //顏色
    private float radius; //小圓半徑
    private float drawRadius; //繪制時的小圓半徑
    
   
  public Circle(int color, int maxLength, float radius, float degree) {
    this.color = color;
    this.radius = radius;
    this.maxLength = maxLength;
    this.degree = degree;
    this.x = (int) (radius * Math.cos(degree));
    this.y = (int) (radius * Math.sin(degree));
    this.rotate = 0.35f;  //觸角效果
    this.speed = 0.2f;
 }
}

粒子更新

在任何動畫中,粒子運動必須具備時間屬性,任何符合物理學的位移運動,速度和時間的關系是位移計算的方法。下面,我們繼續(xù)給Circle類添加更新方法。

這里一個重要的知識點是

  • Math.hypot(x, y) :平方根計算
  • Math.atan2(y, x): 斜率計算,注意,此角度具備方向
public boolean update(long timeline) {
    float length = (float) Math.hypot(x, y);  //計算當前移動的距離(距離中心點)
    float center = length + this.speed * timeline; //計算即將到達的距離
    float ratio = center / maxLength;  //計算與最遠距離的比值

    this.drawRadius = (1f - ratio) * radius;  //距離越遠,圓的半徑越小

    double degree = Math.atan2(y, x) + rotate;  //即將旋轉的角度

    this.x = (int) (center * Math.cos(degree)); //新的x
    this.y = (int) (center * Math.sin(degree)); //新的y

    if (drawRadius <= 0) {
        return false; //如果半徑為0時,意味著圓看不見了,因此要坐下標記
    }
    return true;
}

粒子繪制方法

繪制自身其實很簡單,只需要簡單的調用Canvas相關邏輯即可

public void draw(Canvas canvas, TextPaint paint) {
    paint.setColor(color);
    canvas.drawCircle(x, y, drawRadius, paint);
}

粒子回收

為了減少內存申請頻率,我們對跑出邊界的粒子進行重置

public void reset() {
    this.x = (int) (radius * Math.cos(degree));
    this.y = (int) (radius * Math.sin(degree));
}

View邏輯

以上是完整的粒子對象邏輯,接下來我們實現(xiàn)一個View,用來管理和繪制粒子。

int maxCircleRadius = 20;  //粒子初始半徑
List<Circle> circleList = new ArrayList<>(); //容器
int maxCircleNum = 300; //最大數(shù)量

繪制邏輯

首先是初始化,我們這里設置了3種粒子,因此間隔角度是120度,而我們每次增加三種,防止出現(xiàn)混亂的問題。

   final float rotateDegree = (float) Math.toRadians(120f); //間隔角度
    if (circleList.size() < maxCircleNum) {
    //每次增加三種
        circleList.add(new Circle(Color.RED, (int) maxRadius, maxCircleRadius, 0 * rotateDegree));
        circleList.add(new Circle(Color.GREEN, (int) maxRadius, maxCircleRadius, 1 * rotateDegree));
        circleList.add(new Circle(Color.CYAN, (int) maxRadius, maxCircleRadius, 2 * rotateDegree));
    }

下面是每個粒子的繪制邏輯

for (int i = 0; i < circleList.size(); i++) {
    Circle circle = circleList.get(i);
    circle.draw(canvas, mPaint); //繪制方法
}

更新粒子

下面有個重要的邏輯,其實前面也提到過,就是重置跑出邊界的粒子

for (int i = 0; i < circleList.size(); i++) {
    Circle circle = circleList.get(i);
    if(!circle.update(16)){
        circle.reset(); //如果不能更新,則進行重置
    }
}
postInvalidate(); //刷新繪制邏輯

以上就是整體核心邏輯

效果調節(jié)

我們開頭的兩種效果其實是同一個View實現(xiàn)的,這其中一個重要的點就是速度調整,文章開頭是調整出的兩種效果,當然染還可以調整出其他效果 第一種

this.rotate = 0.2f;
this.speed = 0.2f; //外擴效果

第二種

 this.rotate = 0.35f;  //觸角效果
 this.speed = 0.2f;

第三種

this.rotate = 0.8f;
this.speed = 0.1f;

當然,還有更多,篇幅原因就不深入了。

總結

本篇到這里就結束了,其實我們的核心代碼并不多,但是簡單的邏輯就能衍生出很多動畫效果。其實,學習粒子動畫是非常有意思的事,很多時候,你在實現(xiàn)某些效果的途中,就能突然開發(fā)出一種新的動畫效果。

本篇代碼

下面是本篇內容的完整邏輯,基本就在100行左右。

public class CircleParticleView extends View {
    private TextPaint mPaint;
    private DisplayMetrics mDM;

    public CircleParticleView(Context context) {
        this(context, null);
    }
    public CircleParticleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDM = getResources().getDisplayMetrics();
        initPaint();
    }

    private void initPaint() {
        //否則提供給外部紋理繪制
        mPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        PaintCompat.setBlendMode(mPaint, BlendModeCompat.PLUS);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        if (widthMode != MeasureSpec.EXACTLY) {
            widthSize = mDM.widthPixels / 2;
        }
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (heightMode != MeasureSpec.EXACTLY) {
            heightSize = widthSize / 2;
        }
        setMeasuredDimension(widthSize, heightSize);

    }

    int maxCircleRadius = 20;
    List<Circle> circleList = new ArrayList<>();
    int maxCircleNum = 300;
    long time = 0;

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        int width = getWidth();
        int height = getHeight();
        float maxRadius = Math.min(width, height) / 2f;


        int save = canvas.save();
        canvas.translate(width / 2f, height / 2f);

        final float rotateDegree = (float) Math.toRadians(120f);
        if (circleList.size() < maxCircleNum) {
            circleList.add(new Circle(Color.RED, (int) maxRadius, maxCircleRadius, 0 * rotateDegree));
            circleList.add(new Circle(Color.GREEN, (int) maxRadius, maxCircleRadius, 1 * rotateDegree));
            circleList.add(new Circle(Color.CYAN, (int) maxRadius, maxCircleRadius, 2 * rotateDegree));
        }

        mPaint.setStyle(Paint.Style.FILL);
        for (int i = 0; i < circleList.size(); i++) {
            Circle circle = circleList.get(i);
            circle.draw(canvas, mPaint);
        }
        canvas.restoreToCount(save);

        for (int i = 0; i < circleList.size(); i++) {
            Circle circle = circleList.get(i);
            if (!circle.update(16)) {
                circle.reset();
            }
        }

        postInvalidate();
        time += 16;
    }

    static class Circle {
        int maxLength;  //最大運行距離
        float speed; //外擴速度
        float rotate; // 角速度
        private float degree; //起始角度
        private int y; //y坐標
        private int x; //x坐標
        private int color; //顏色
        private float radius; //小圓半徑
        private float drawRadius; //繪制時的小圓半徑

        public Circle(int color, int maxLength, float radius, float degree) {
            this.color = color;
            this.radius = radius;
            this.maxLength = maxLength;
            this.degree = degree;
            this.x = (int) (radius * Math.cos(degree));
            this.y = (int) (radius * Math.sin(degree));
            this.rotate = 0.35f;  //觸角效果
            this.speed = 0.2f;
        }


        public boolean update(long timeline) {
            float length = (float) Math.hypot(x, y);
            float center = length + this.speed * timeline; //距離增加
            float ratio = center / maxLength;

            this.drawRadius = (1f - ratio) * radius;

            double degree = Math.atan2(y, x) + rotate;  //角度增加

            this.x = (int) (center * Math.cos(degree));
            this.y = (int) (center * Math.sin(degree));

            if (drawRadius <= 0) {
                return false;
            }
            return true;
        }

        public void draw(Canvas canvas, TextPaint paint) {
            paint.setColor(color);
            canvas.drawCircle(x, y, drawRadius, paint);
        }
        public void reset() {
            this.x = (int) (radius * Math.cos(degree));
            this.y = (int) (radius * Math.sin(degree));
        }
    }

}

以上就是Android實現(xiàn)粒子中心擴散動畫效果的詳細內容,更多關于Android粒子中心擴散的資料請關注腳本之家其它相關文章!

相關文章

  • Unity同步/異步調用Android的方法實例

    Unity同步/異步調用Android的方法實例

    unity在Android端開發(fā)的時候,免不了要調用Java,下面這篇文章主要給大家介紹了關于Unity同步/異步調用Android的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2021-08-08
  • Android RecyclerView item選中放大被遮擋問題詳解

    Android RecyclerView item選中放大被遮擋問題詳解

    這篇文章主要介紹了Android RecyclerView item選中放大被遮擋問題詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • Android ViewPager實現(xiàn)選項卡切換

    Android ViewPager實現(xiàn)選項卡切換

    這篇文章主要介紹了Android ViewPager實現(xiàn)選項卡切換,詳細分析了ViewPager實現(xiàn)選項卡切換功能,感興趣的小伙伴們可以參考一下
    2016-02-02
  • 簡單實現(xiàn)Android放大鏡效果

    簡單實現(xiàn)Android放大鏡效果

    這篇文章主要教大家簡單實現(xiàn)Android放大鏡效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Android Studio中引入Lambda表達式的方法

    Android Studio中引入Lambda表達式的方法

    這篇文章主要給大家介紹了在Android Studio中引入Lambda表達式的方法,文中通過圖文介紹的非常詳細,對大家具有一定的參考價值,需要的朋友們下面來一起看看吧。
    2017-03-03
  • RecyclerView實現(xiàn)常見的列表菜單

    RecyclerView實現(xiàn)常見的列表菜單

    這篇文章主要為大家詳細介紹了用RecyclerView實現(xiàn)移動應用中常見的列表菜單,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Android實現(xiàn)從底部彈出的Dialog的實例代碼

    Android實現(xiàn)從底部彈出的Dialog的實例代碼

    這篇文章主要介紹了Android實現(xiàn)從底部彈出的Dialog的實例代碼,非常不錯,具有參考借鑒價值 ,需要的朋友可以參考下
    2018-04-04
  • 詳解Android 利用Iptables實現(xiàn)網(wǎng)絡黑白名單(防火墻)

    詳解Android 利用Iptables實現(xiàn)網(wǎng)絡黑白名單(防火墻)

    這篇文章主要介紹了詳解Android 利用Iptables實現(xiàn)網(wǎng)絡黑白名單(防火墻),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08
  • Android APP與媒體存儲服務的交互

    Android APP與媒體存儲服務的交互

    本文介紹如何在 Android 中,開發(fā)者的 APP 如何使用媒體存儲服務(包含MediaScanner、MediaProvider以及媒體信息解析等部分),包括如何把 APP 新增或修改的文件更新到媒體數(shù)據(jù)庫、如何在多媒體應用中隱藏 APP 產生的文件、如何監(jiān)聽媒體數(shù)據(jù)庫的變化等等。
    2013-10-10
  • 懸浮對話框Android代碼實現(xiàn)

    懸浮對話框Android代碼實現(xiàn)

    這篇文章主要為大家詳細介紹了懸浮對話框Android代碼實現(xiàn),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-08-08

最新評論