安卓开发可随手指移动的触摸球项目

实现效果

能够实现触摸球随手指移动而移动,点击正向回放按钮和反向回放按钮可以实现上一段轨迹的重放,输入毫秒,可以控制轨迹回放的速度(通过延迟时长实现)

设计思路

界面设计

比较简单,用到Button、TextView、EditText组件,用线性布局LinearLayout,把几个组件位置固定。设定一个FrameLayout,来表示触摸有效区域,通过设置它的height、width来划出区域

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <FrameLayout
        android:id="@+id/frameLayout"
        android:layout_width="match_parent"
        android:layout_height="300dip">

        <TextView
            android:id="@+id/touch_area"
            android:layout_width="fill_parent"
            android:layout_height="300dip"
            android:background="#0FF"
            android:text="触摸事件测试区域"
            android:textColor="#FFFFFF"></TextView>

        <TextView
            android:id="@+id/trackballTextView"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginTop="16dp"
            android:gravity="center"
            android:text="触摸球"
            android:textColor="#000"
            android:textSize="10sp" />


    </FrameLayout>

    <EditText
        android:id="@+id/speedEditText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_gravity="center"
        android:hint="输入回放速度(毫秒)"
        android:inputType="number"
        android:minHeight="48dp" />

    <Button
        android:id="@+id/replayButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/speedEditText"
        android:layout_gravity="center"
        android:layout_marginTop="10dp"
        android:text="正向回放" />

    <Button
        android:id="@+id/replayReverseButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:layout_below="@id/replayButton"
        android:layout_centerHorizontal="true"
        android:layout_gravity="center"
        android:layout_marginTop="16dp"
        android:text="反向回放" />
</LinearLayout>

业务逻辑

回放轨迹记录:

使用触摸监听器,监听当前触摸点的坐标(x,y),每一次按压(DOWN)清空以前的列表,记录该点,存入列表中,在手指触摸移动(MOVE)过程中,不断向列表中add坐标点,在手指松开(UP)后,本次轨迹记录结束。

switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        // 显示轨迹球并记录起点
                        trackPointsX.clear();
                        trackPointsY.clear();
                        trackPointsX.add(x);
                        trackPointsY.add(y);
                        trackballTextView.setX(x);
                        trackballTextView.setY(y);
                        trackballTextView.setVisibility(View.VISIBLE);
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        // 记录移动过程中的点
                        trackPointsX.add(x);
                        trackPointsY.add(y);
                        // 实时更新轨迹
                        trackballTextView.setX(x);
                        trackballTextView.setY(y);
                        return true;
                    case MotionEvent.ACTION_UP:
                        // 隐藏轨迹球
                        trackballTextView.setVisibility(View.INVISIBLE);
                        // 开始回放
                        if (!trackPointsX.isEmpty() && !trackPointsY.isEmpty()) {
                            replayTrajectory();
                        }
                        return true;
                }

回放轨迹实现:

利用Handler来实现延迟一段时间后执行指定的任务,利用Runnable()来创建一个匿名内部类对象,该匿名内部类实现了Runnable接口,因此必须实现run()方法,run方法是该线程操作的主方法。

在run方法中实现方法用于控制轨迹球的移动,并在一定条件下递归调用handler方法,实现了轨迹球的连续移动效果。也就是handler每隔设定的时间间隔,在列表中查询是否有未取的点,从而一直回放轨迹,当没有点位可取时,就结束本次任务。

handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (currentIndex[0] < totalFrames) {
                    float x = trackPointsX.get(indices[currentIndex[0]]);
                    float y = trackPointsY.get(indices[currentIndex[0]]);
                    trackballTextView.setX(x);
                    trackballTextView.setY(y);
                    trackballTextView.setVisibility(View.VISIBLE); // 设置轨迹球可见
                    currentIndex[0]++;
                    handler.postDelayed(this, replaySpeed);
                } else {

                    // 回放结束,重置状态
                    isReplaying = false;
                }
            }
        }, replaySpeed);

主体代码

public class MainActivity extends Activity {

    private FrameLayout frameLayout;
    private TextView trackballTextView;
    private Button replayButton;
    private TextView speedEditText;
    private List<Float> trackPointsX = new ArrayList<>();
    private List<Float> trackPointsY = new ArrayList<>();
    private boolean isReplaying = false;
    private int replaySpeed = 50; // 默认回放速度为每50毫秒移动一次
    private Handler handler = new Handler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        frameLayout = findViewById(R.id.frameLayout);
        trackballTextView = findViewById(R.id.trackballTextView);
        replayButton = findViewById(R.id.replayButton);
        speedEditText = findViewById(R.id.speedEditText);

        // 隐藏轨迹球
        trackballTextView.setVisibility(View.INVISIBLE);

        // 设置轨迹球的触摸监听器
        frameLayout.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                float x = event.getX();
                float y = event.getY();

                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        // 显示轨迹球并记录起点
                        trackPointsX.clear();
                        trackPointsY.clear();
                        trackPointsX.add(x);
                        trackPointsY.add(y);
                        trackballTextView.setX(x);
                        trackballTextView.setY(y);
                        trackballTextView.setVisibility(View.VISIBLE);
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        // 记录移动过程中的点
                        trackPointsX.add(x);
                        trackPointsY.add(y);
                        // 实时更新轨迹
                        trackballTextView.setX(x);
                        trackballTextView.setY(y);
                        return true;
                    case MotionEvent.ACTION_UP:
                        // 隐藏轨迹球
                        trackballTextView.setVisibility(View.INVISIBLE);
                        // 开始回放
                        if (!trackPointsX.isEmpty() && !trackPointsY.isEmpty()) {
                            replayTrajectory();
                        }
                        return true;
                }
                return false;
            }
        });

        // 设置回放按钮的点击监听器
        replayButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!isReplaying) {
                    // 获取用户输入的回放速度
                    String speedText = speedEditText.getText().toString();
                    if (!speedText.isEmpty()) {
                        replaySpeed = Integer.parseInt(speedText);
                    }
                    replayTrajectory();
                }
            }
        });
    }

    // 回放轨迹方法
    private void replayTrajectory() {
        if (trackPointsX.isEmpty() || trackPointsY.isEmpty()) return;

        // 设置回放状态为true
        isReplaying = true;

        // 重置回放索引
        int totalFrames = trackPointsX.size();
        final int[] reversedIndices = new int[totalFrames];
        for (int i = 0; i < totalFrames; i++) {
            reversedIndices[i] = totalFrames - 1 - i;
        }

        // 开始逐帧移动
        final int[] currentIndex = {0};
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (currentIndex[0] < totalFrames) {
                    float x = trackPointsX.get(reversedIndices[currentIndex[0]]);
                    float y = trackPointsY.get(reversedIndices[currentIndex[0]]);
                    trackballTextView.setX(x);
                    trackballTextView.setY(y);
                    trackballTextView.setVisibility(View.VISIBLE); // 设置轨迹球可见
                    currentIndex[0]++;
                    handler.postDelayed(this, replaySpeed);
                } else {
                    // 回放结束,重置状态
                    isReplaying = false;
                }
            }
        }, replaySpeed); // 延迟开始回放
    }
}

  • 22
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值