Android動畫學習(六)之View揭露效果和SurfaceView實現動畫

Android動畫學習(六)之View揭露效果和SurfaceView實現動畫

View揭露效果

當顯示或隱藏一組 UI 元素時,揭露動畫可為用戶提供視覺連續性。ViewAnimationUtils.createCircularReveal() 方法讓您能夠為裁剪區域添加動畫以揭露或隱藏視圖。這是Android5.0推出的新的動畫框架,可以給View做一個揭露效果。 使用非常簡單。

如果要使用此效果揭露之前不可見的視圖:

// previously invisible view
View myView = findViewById(R.id.my_view);

// get the center for the clipping circle
int cx = (myView.getLeft() + myView.getRight()) / 2;
int cy = (myView.getTop() + myView.getBottom()) / 2;

// get the final radius for the clipping circle
int finalRadius = Math.max(myView.getWidth(), myView.getHeight());

// create the animator for this view (the start radius is zero)
Animator anim =
    ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);

// make the view visible and start the animation
myView.setVisibility(View.VISIBLE);
anim.start();

如果要使用此效果隱藏之前可見的視圖:

// previously visible view
final View myView = findViewById(R.id.my_view);

// get the center for the clipping circle
int cx = (myView.getLeft() + myView.getRight()) / 2;
int cy = (myView.getTop() + myView.getBottom()) / 2;

// get the initial radius for the clipping circle
int initialRadius = myView.getWidth();

// create the animation (the final radius is zero)
Animator anim =
    ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0);

// make the view invisible when the animation is done
anim.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
        myView.setVisibility(View.INVISIBLE);
    }
});

// start the animation
anim.start();

源碼解析:

  public static Animator createCircularReveal(View view,
            int centerX,  int centerY, float startRadius, float endRadius) 

參數說明:
view:控件
centerX和centerY :中心點坐標
startRadius:開始半徑
endRadius:結束半徑
示例代碼:

/**
 * Android5.0推出的新的動畫框架,可以給View做一個揭露效果
 *
 * @author ZD
 *         created at 2017/7/14 10:17
 *         description:
 */

public class CircularReveralActivity extends AppCompatActivity {
    private ImageView imageView;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_circularepeveral);
        imageView = (ImageView) findViewById(R.id.iv_CircularReveral);
    }

    /**
     * 五個參數分別是View,中心點坐標,開始半徑,結束半徑。通過這五個參數的配合,我們可以做出很多不同的效果。
     * @param v
     */
    public void CircularReveral(View v) {

        Animator anim = ViewAnimationUtils.createCircularReveal(imageView, imageView.getWidth() / 2, imageView.getHeight() / 2, imageView.getWidth(), 0);
        anim.setDuration(2000);
        anim.start();



    }
}

示例效果:
這裡寫圖片描述

SurfaceView實現動畫

概述:
SurfaceView是視圖(View)的繼承類,這個視圖裡內嵌瞭一個專門用於繪制的Surface。你可以控制這個Surface的格式和尺寸。Surfaceview控制這個Surface的繪制位置.

Vew 的繪圖機制存在如下缺陷:

View 缺乏雙緩沖機制。 當程序需要更新 View 上的圖片時,程序必須重繪 View 上顯示的整張圖片。 新線程無法直接更新 View 組件。

SurfaceView 與普通 View 還有一個重要的區別: View 的繪圖必須在當前 UI 線程中進行——這也是前面程序需要更新 View 組件時總要采用 Handler 處理的原因;但 SurfaceView 就不會存在這個問題,因此 SurfaceView 的繪圖是由 SurfaceHolder 來完成的。對於 View 組件,如果程序需要花較長的時間來更新繪圖,那麼主 UI 線程將會被阻塞,無法響應用戶的任何動作;而 SurfaceHolder 則會啟用新的線程去更新 SurfaceView 的繪制,因
此不會阻塞主 UI 線程。 、
一般來說,如果程序或遊戲界面的動畫元素較多,而且很多動畫元素的移動都需要通定時器來控制,就可以考慮使用 SurfaceView ,而不是 View 。

SurfaceView繪圖機制:
Surface View —般會與SurfaceHolder結合使用,SurfaceHolder用於向與之關聯的SurfaceView上繪圖,調用Surface View的getHolder()方法即可獲取SurfaceView關聯的SurfaceHolder。
SurfaceHolder提供瞭如下方法來獲取Canvas對象。

Canvas l〇ckCanvas():鎖定整個 SurfaceView 對象,獲取該 SurfaceView 上的 Canvas。

Canvas lockCanvas(Rect dirty) : 鎖 定 SurfaceView 上 Rect 劃分的區域,獲取該
SurfaceView 上的 Canvas。

當對同一個SurfaceView調用上面兩個方法時,兩個方法所返回的是同一個Canvas對象。但當程序調用第二個方法獲取指定區域的Canvas時,SurfaceView將隻對Rect所“圈”出來的區域進行更新,通過這種方式可以提高畫面的更新速度。當通過lockCanvas()獲取瞭指定SurfaceView上的Canvas之後,接下來程序就可以調用
Canvas進行繪圖瞭,Canvas繪圖完成後通過如下方法來釋放繪圖、提交所繪制的圖形。

unlockCanvasAndPost(canvas)

需要指出的是,當調用SurfaceHolder的unlockCanvasAndPost()方法之後,該方法之前所繪制的圖形還處於緩沖區中,下一次lockCanvasO方法鎖定的區域可能會“遮擋”它。

SurfaceView繪圖示例——示波器代碼:
java代碼:

public class SurfaceViewActivity extends AppCompatActivity {
    private SurfaceHolder holder;
    private Paint paint;
    final int HEIGHT = 320;
    final int WIDTH = 768;
    final int X_OFFSET = 5;
    private int cx = X_OFFSET;
    // 實際的Y軸的位置
    int centerY = HEIGHT / 2;
    Timer timer = new Timer();
    TimerTask task = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_surface_view);
        TextView textView = (TextView) findViewById(R.id.tv_title);
        //設置標題
        textView.setText("SurfaceView示波器");

        final SurfaceView surface = (SurfaceView)
                findViewById(R.id.show);
        // 初始化SurfaceHolder對象
        holder = surface.getHolder();
        paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStrokeWidth(5);
        Button sin = (Button)findViewById(R.id.sin);
        Button cos = (Button)findViewById(R.id.cos);
        OnClickListener listener = (new OnClickListener()
        {
            @Override
            public void onClick(final View source)
            {
                drawBack(holder);
                cx = X_OFFSET;
                if(task != null)
                {
                    task.cancel();
                }
                task = new TimerTask()
                {
                    public void run()
                    {
                        int cy = source.getId() == R.id.sin ? centerY
                                - (int)(100 * Math.sin((cx - 5) * 2
                                * Math.PI / 150))
                                : centerY - (int)(100 * Math.cos ((cx - 5)
                                * 2 * Math.PI / 150));
                        Canvas canvas = holder.lockCanvas(new Rect(cx ,
                                cy - 2  , cx + 2, cy + 2));
                        canvas.drawPoint(cx , cy , paint);
                        cx ++;
                        if (cx > WIDTH)
                        {
                            task.cancel();
                            task = null;
                        }
                        holder.unlockCanvasAndPost(canvas);
                    }
                };
                timer.schedule(task , 0 , 30);
            }
        });
        sin.setOnClickListener(listener);
        cos.setOnClickListener(listener);
        holder.addCallback(new SurfaceHolder.Callback()
        {
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format,
                                       int width, int height)
            {
                drawBack(holder);
            }
            @Override
            public void surfaceCreated(final SurfaceHolder myHolder){ }
            @Override
            public void surfaceDestroyed(SurfaceHolder holder)
            {
                timer.cancel();
            }
        });
    }
    private void drawBack(SurfaceHolder holder)
    {
        Canvas canvas = holder.lockCanvas();
        // 繪制白色背景
        canvas.drawColor(Color.WHITE);
        Paint p = new Paint();
        p.setColor(Color.BLACK);
        p.setStrokeWidth(2);
        // 繪制坐標軸
        canvas.drawLine(X_OFFSET , centerY , WIDTH , centerY , p);
        canvas.drawLine(X_OFFSET , 40 , X_OFFSET , HEIGHT , p);
        holder.unlockCanvasAndPost(canvas);
        holder.lockCanvas(new Rect(0 , 0 , 0 , 0));
        holder.unlockCanvasAndPost(canvas);
    }

}

Xml中引用SurfaceView

    

效果:
這裡寫圖片描述

總結

View動畫到這篇博客已經完全學習完瞭。下一篇介紹轉場動畫。
寫博客是為瞭幫助開發者學習使用技術,同時鞏固自己所學技術。如果此篇博客有助於您的學習,那是我的榮幸!如果此篇博客有任何瑕疵,請多多指教!在此感謝您的學習和指教!

You May Also Like