Android动画学习(六)之View揭露效果和SurfaceView实现动画

本文深入探讨Android动画,讲解如何利用ViewAnimationUtils创建View揭露效果,以及如何使用SurfaceView实现高效动画。内容包括View揭露动画的原理、参数解析、示例代码,以及SurfaceView的绘图机制和优化策略,最后对学习内容进行了总结。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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


    <SurfaceView
        android:id="@+id/show"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center" />

效果:
这里写图片描述

总结

View动画到这篇博客已经完全学习完了。下一篇介绍转场动画。
写博客是为了帮助开发者学习使用技术,同时巩固自己所学技术。如果此篇博客有助于您的学习,那是我的荣幸!如果此篇博客有任何瑕疵,请多多指教!在此感谢您的学习和指教!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值