手按住小球,进行滑动,小球就跟着我的手移动,当我手松开,在空白的地方滑动,小球就不在动了

本文介绍了一种自定义Android视图的方法,通过创建并覆盖View的构造方法,实现了一个可跟随手指移动的小球控件。文章详细解释了onMeasure、onDraw和onTouchEvent等关键方法的作用,并提供了一个完整的实现案例。

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

package com.bwie.ballsview;

import android.content.Context;
import android.graphics.Canvas;

import android.graphics.Color;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

/**
 * date:2018/11/1
 * author:mxy(M)
 * function:自绘式的成员之一
 * 牢记三个方法:onMeasure():测量,该方法检测View组件及他所包含的子组件的大小
 *               onLayout():layout:位置,当该组件要分配子组件所在位置时调用(基本不用)
 *               onDraw():绘制,当该组件要绘制他的内容时,回调该方法(使用频率最高,注意不要再onMeasure里做耗时操作和创建对象的操作)
 *
 *   需求:创建一个小球,手按住小球,进行滑动,小球就跟着我的手移动,当我手松开,在空白的地方滑动,小球就不在动了
 *   实现思路:
 *   1.创建一个类,继承View(就从普通类变成一个控件)
 *   2.覆写必须要覆写的三个构造方法,初始化画笔
 *   3.在onMeasure,获取屏幕和控件的宽高,让小球居于屏幕中间的位置
 *   4.在onMeasure中绘制小球
 *   5,触摸事件的监听中,根据用户手指滑动,让小球在对应的坐标重新绘制postInvalidate()
 *   有一个Bug,你会出现当你没有按住小球,在空白的地方滑动,小球依然会跟着动
 *
 *   画一个自定义控件:要有画纸(BallsView),画板(Draw),画笔()
 */
public class BallsView extends View {

    private int mHeight;
    private int mWidth;
    private int Y;
    private int X;
    private Paint mPaint;
    private boolean mOnBall;

    //这三个方法是让你做初始化的业务逻辑
    //使用控件的时候,在屏幕上显示,有两种方法,一种在XML里去定义控件,一种在Java里面使用控件
    //代码中使用自定义控件(new BallsView),自动回调此方法
    public BallsView(Context context) {
        this(context, null);

    }

    //XML布局使用此自定义控件,自动回调此方法
    public BallsView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    //XML布局中使用此自定义控件,且带有样式时,自动回调
    public BallsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        initView();
    }

    //自定义控件做个初始化的操作
    private void initView() {
        mPaint = new Paint();
    }


    //测试里

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取当前控件的宽高
        mHeight = this.getHeight();
        mWidth = this.getWidth();
        //获取屏幕正中心点
        Y = mHeight / 2;
        X = mWidth / 2;
    }

    private int mRadius = 50;


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //设置画笔颜色
        mPaint.setColor(Color.GRAY);
        //画圆
        canvas.drawCircle(X, Y, mRadius, mPaint);

    }

    //手势监听器,可以得到用户手指在屏幕上滑动的坐标
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //二者区别,getX得到的是以自定义控件左上角为原点的X轴坐标,getRawX得到的是以屏幕左上角为原点的X轴坐标
                int downX = (int) event.getX();
                int downY = (int) event.getY();
//                event.getRawX();

                //进行判断,判断用户的手指是否按在了园内
                mOnBall = isOnBall(downX, downY);

                Toast.makeText(getContext(), "用户的手指是否点到圆内了" + mOnBall, Toast.LENGTH_SHORT).show();

                break;
            case MotionEvent.ACTION_MOVE:
                //只用用户点到圆内时,我才让圆动
                if (mOnBall) {
                    X = (int) event.getX();
                    Y = (int) event.getY();
                    //回调OnDrawer方法
                    postInvalidate();
                }
                break;
            case MotionEvent.ACTION_UP:

                break;
        }
        return true;
    }

    //,判断用户的手指是否按在了圆内
    private boolean isOnBall(int downX, int downY) {
        //勾股定理的绝对值
        double sqrt = Math.sqrt((downX - X) * (downX - X) + (downY - Y) * (downY - Y));
        //判断绝对值是否小于等于半径
        if (sqrt <= mRadius) {
            return true;
        }

        return false;
    }
}

<think>我们正在解决微信小程序中按住滑动时不触发bind:touchmove事件的问题。根据引用[1]和引用[2],我们知道bind:touchmove是用于绑定滑动事件的。但是用户反映按住滑动时不触发该事件。可能的原因:1.没有正确绑定事件:确保在wxml中使用了`bindtouchmove`或`catchtouchmove`,并且对应的js中定义了事件处理函数。2.事件被阻止:可能是由于在touchstart事件中调用了`e.stopPropagation()`,阻止了事件冒泡,导致touchmove事件无法触发。3.元素没有设置移动:如果是在movable-view组件中,需要检查是否设置了方向(direction)属性,且不为'none'(引用[3])。4.元素不可移动:如果movable-view被禁用(disabled属性为true)或者超出了可移动区域(out-of-bounds)可能无法触发。5.其他事件干扰:比如在touchstart事件中返回了false,会阻止后续的touchmove事件(在微信小程序中,在touchstart中返回false并不会阻止默认事件,但可以通过其他方式阻止)。6.触摸点过多:如果同时有多个指触摸(虽然用户描述是单指,但需要注意是否有误触),可能会触发其他事件。解决方案:1.检查绑定:确保wxml中正确绑定了事件,例如:```html<viewbindtouchstart="handleTouchStart"bindtouchmove="handleTouchMove"bindtouchend="handleTouchEnd">```并且在js中定义了对应的函数。2.检查是否阻止了事件冒泡:在touchstart事件处理函数中,不要使用`e.stopPropagation()`,除非有特殊理由。3.对于movable-view组件:-确保设置了`direction`属性(例如`direction="all"`)以允许移动。-检查是否设置了`disabled`为false(默认就是false,如果设置了true则改为false)。-检查是否超出了可移动区域,可以尝试设置`out-of-bounds`为true,允许超出边界移动。4.尝试使用`catchtouchmove`代替`bindtouchmove`,因为`catch`可以阻止事件冒泡到父节点,有时候父节点的事件可能会干扰。5.在touchstart事件中,不要返回`false`(在微信小程序中,返回`false`并不会阻止事件,但为了保险,可以检查一下是否有其他操作阻止了事件)。6.检查元素样式:确保元素有足够的面积可以触摸,并且没有其他元素覆盖。7.检查是否有其他事件处理函数中断了触摸:比如在touchstart事件中设置了一个状态,而在touchmove中根据这个状态才执行,那么需要确保状态设置正确。8.使用调试工具:在微信开发者工具中,可以通过调试功能查看事件触发情况。示例代码:WXML:```html<viewclass="movable-area"><movable-viewdirection="all"bindtouchmove="onTouchMove">按住滑动</movable-view></view>```JS:```javascriptPage({onTouchMove:function(e){console.log('touchmoveevent',e);}})```如果问题仍然存在,可以尝试使用一个普通的view代替movable-view,看看是否是组件本身的问题。另外,根据引用[3],movable-view的默认定位是绝对定位,需要确保其父元素是movable-area,并且设置好宽高。如果用户的问题是在普通view上,那么检查一下是否有其他样式或逻辑问题。总结:主要从事件绑定、事件冒泡、组件配置、样式等方面进行排查。</think>### 微信小程序 bind:touchmove 事件按住滑动不触发的解决方案 #### 常见原因及排查步骤: 1. **事件绑定冲突** - 检查是否同时绑定了 `bind:touchstart` 和 `bind:touchmove` - 若 `touchstart` 事件中执行了 `e.stopPropagation()` 会阻止后续事件冒泡 - ✅ 解决方案:移除不必要的 `e.stopPropagation()` 或改用 `catch` 事件绑定 2. **组件层级问题** - 滑动区域被其他组件覆盖(如透明浮层) - 父级元素设置了 `pointer-events: none` - ✅ 解决方案: ```css /* 确保目标组件可交互 */ .target-view { pointer-events: auto; z-index: 100; } ``` 3. **movable-view 配置错误**(引用[3]) - `direction` 属性未开启移动(默认为 `none`) - `disabled` 属性被设为 `true` - ✅ 解决方案: ```html <movable-view direction="all" disabled="{{false}}" bindtouchmove="handleMove"> ``` 4. **触摸范围不足** - 触摸区域小于 20×20px(微信默认限制) - ✅ 解决方案:添加内边距扩大触摸区域 ```css .touch-area { padding: 30rpx; } ``` 5. **事件捕获阶段问题** - 父级元素使用 `capture-bind:touchmove` 截获事件 - ✅ 解决方案:改用冒泡绑定或调整捕获顺序 ```html <!-- 优先使用冒泡绑定 --> <view bindtouchmove="handleMove"></view> ``` #### 完整示例代码: ```html <!-- 正确配置 movable-view --> <movable-area style="height: 300px"> <movable-view direction="all" damping="20" bindtouchmove="handleTouchMove" style="background: #07C160; width: 100px; height: 100px"> 滑动我 </movable-view> </movable-area> ``` ```javascript Page({ handleTouchMove(e) { console.log('滑动事件触发', e.touches[0].clientX) } }) ``` #### 高级调试技巧: 1. 开启 **「显示触摸点」**:微信开发者工具 → 调试器 → WXML → 勾选「显示触摸点」 2. 监听 `touchcancel` 事件: ```html <view bindtouchcancel="handleCancel">...</view> ``` 3. 使用 `wx.createSelectorQuery()` 检查元素实际尺寸 > 若仍不触发,检查 `app.json` 是否启用 `"enablePassiveEvent": false`(微信基础库 2.12.0+)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值