Android 中自定义View,实现小球往复运动

您所在的位置:网站首页 小球运动轨迹动画图片 Android 中自定义View,实现小球往复运动

Android 中自定义View,实现小球往复运动

2024-07-12 23:21| 来源: 网络整理| 查看: 265

博主前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住也分享一下给大家, 👉点击跳转到网站

一、介绍如何实现小球的往复运动,实现原理

1、View 类定义了一组 invalidate()方法,该方法有好几个版本:

public void invalidate()public void invalidate(int l, int t, int r, int b)public void invalidate(Rect dirty)

invalidate()用于重绘组件,不带参数表示重绘整个视图区域,带参数表示重绘指定的区域。 如果要去追溯该方法的源码,大概就是将重绘请求一级级往上交到 ViewRoot,调用 ViewRoot的 scheduleTraversals()方法重新发起重绘请求,scheduleTraversals()方法会发送一个异步消息,调用 performTraversals()方法执行重绘,而 performTraversals()方法最终调用 onDraw()方法。所以,简单来说,调用 View 的 invalidate()方法就相当于调用了 onDraw()方法, 而 onDraw()方法中就是我们编写的绘图代码。

如果要刷新组件或者让画面动起来,我们只需调用 invalidate()方法即可。通过改变数据来影响绘制结果,这是实现组件刷新或实现动画的基本思路。

invalidate()方法只能在 UI 线程中调用,如果是在子线程中刷新组件,View 类还定义了另一组名为 postInvalidate 的方法:

public void postInvalidate()public void postInvalidate(int left, int top, int right, int bottom)

二、接下来我们就创建自定义View实现小球的往复运动

1、首先创建自定义View类BallMoveView

/** * 球往复运动 */ public class BallMoveView extends View { //小球的水平位置 private int x; //小球的垂直位置,固定为100 private static final int Y = 100; //小球的半径 private static final int RADIUS = 30; //小球的颜色 private static final int COLOR = Color.RED; //声明画笔对象 private Paint paint; //移动的方向 private boolean direction; //该构造函数会在代码里面new的时候调用 //当不需要使用xml声明或者不需要使用inflate动态加载的时候,实现此构造函数即可 public BallMoveView(Context context) { super(context); } //在布局layout中使用时调用 //在布局文件中定义了该组件,则会调用此构造方法来创建对象 // 当需要在xml中声明此控件,则需要实现此构造函数。 // 并且在构造函数中把自定义的属性与控件的数据成员连接起来。 public BallMoveView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); //初始化画笔,参数表示抗锯齿 paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(COLOR); x = RADIUS; } //接受一个style资源 public BallMoveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //根据x,y的坐标值画一个小球 canvas.drawCircle(x, Y, RADIUS, paint); //改变 x 坐标的值,调用 invalidate()方法后, //小球将因 x 的值发生改变而产生移动的效果 int width = this.getMeasuredWidth();//获取组件的宽度 //小球的水平位置 x 值小于等于小球的半径,说明小球已到达左边边 //界 if (x = width - RADIUS) { direction = false; } x = direction ? x + 5 : x - 5; } }

2、在对应的activity_view1.xml布局文件中引用

3、在 View1Activity 中恰恰是通过定时器周期性调用了 invalidate()方法不断重绘组件,也就是不断调用 onDraw()方法,因为小球的位置由 x 来决定,onDraw()每调用一次,x 的值就会变化一次,小球绘制的位置自然也会跟着一起改变,最后形成了小球移动的效果。 具体代码如下:

public class View1Activity extends AppCompatActivity { private BallMoveView ballMoveView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_view1); ballMoveView = findViewById(R.id.ballMoveView); tv = findViewById(R.id.tv); new Timer().schedule(new TimerTask() { @Override public void run() { ballMoveView.postInvalidate(); } },0,50); //参数二表示:任务执行前的延迟毫秒数,参数三表示:连续任务执行间的时间为50毫秒 } }

注意:上面代码中,通过 Timer 类定义一个计时器,延时 0 毫秒开始计时,每隔 50 毫秒计时一次。 定时任务类 TimerTask 其实就是一个子线程,所以,不能使用只能运行在 UI 线程中的invalidate()方法而只能调用 postInvalidate()方法来重绘组件。

具体效果如下:

在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3