自定义View —— 可删除 item 的 ListView (事件分发)

本文所用源码:https://github.com/HeXiaosa/ItemDeletableListView
本文由看这篇文章 https://blog.csdn.net/lmj623565791/article/details/22961279 以及结合 Andorid 开发艺术探索而来。

事件分发概述

Android 中触摸事件主要由 dispatchTouchEvent, onInterceptTouchEvent, onTouchEvent 来控制。

触摸屏幕时,首先会触发 ViewGroup 的 dispathTouchEvent 方法,自定义 View 时,如果它在 ACTION_DOWN 返回 false, 则表示不再继续向下执行,事件到此结束,如果返回了 true, 则下次继续执行 dispatchTouchEvent 方法,返回 super.dispatchTouchEvent(ev) 则会执行 onInterceptTouchEvent/onTouchEvent.

View 是没有 onInterceptTouchEvent 方法的,因为事件传递到 View 之后是一定交给自己处理了。ViewGroup 的 onInterceptTouchEvent 方法 返回 true 表示 要拦截事件,给自己处理,返回 false 表示不拦截,传递给子 View 处理,执行子 View 的 dispatchTouchEvent 方法。

执行到 onTouchEvent 方法,返回 true 表示不再给它的 ViewGroup 处理,自己处理完就结束,返回 false 表示自己可以做一些操作,再执行它的 ViewGroup 的 onTouchEvent 方法。

可删除 item 的 ListView 思路

理解上面的描述之后,就可以结合上面文章中的例子来自己动手实现一个

  1. 从右向左滑动时,需要我们来处理(弹出PopupWindow),其余的交由 ListView 处理
  2. PopupWindow 是弹出状态时,再次触摸,则需要消失 PopupWindow, 事件到此结束

这里贴出 dispatchTouchEvent 和 onTouchEvent 的代码:

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    Log.e("ItemDeletableListView", "dispatchTouchEvent action : " + ev.getAction() + ", handleTouchEvent:" + handleTouchEvent + ", isPopupShow:" + isPopupShow);
    Log.e("ItemDeletableListView", "dispatchTouchEvent mPwDelete.isShowing:" + mPwDelete.isShowing());
    if (!handleTouchEvent) {
        // 如果不需要处理触摸事件,那么久不做处理
        return super.dispatchTouchEvent(ev);
    }
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            if (isPopupShow) {
                // 已经展示了 popup 的话,再次触发 down 事件,则消失,并不再分发事件
                mPwDelete.dismiss();
                isPopupShow = false;
                return false;
            }
            downX = ev.getX();
            downY = ev.getY();
            downPosition = pointToPosition(((int) downX), ((int) downY));
            break;
        case MotionEvent.ACTION_MOVE:
            if (isPopupShow) {
                // 如果 move 过程中展示了 popupwindow, 那么不再分发事件
                return false;
            }
            x = ev.getX();
            y = ev.getY();
            if (downX-x > touchSlop && downX-x > Math.abs(downY-y)) {
                isSliding = true;
            } else {
                isSliding = false;
            }
            break;
        case MotionEvent.ACTION_UP:
            isSliding = false;
            break;
    }
    return super.dispatchTouchEvent(ev);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    Log.e("ItemDeletableListView", "onTouchEvent action : " + ev.getAction() + ", isSliding:" + isSliding + ", downPosition:" + downPosition);
    switch (ev.getAction()) {
        case MotionEvent.ACTION_MOVE:
            if (isSliding) {
                View child = getChildAt(downPosition);
                if (child == null) {
                    return super.onTouchEvent(ev);
                }
                isPopupShow = true;
                int x = getWidth()/2+mPwDelete.getWidth()/2;
                int y = child.getTop()+child.getHeight()/2;
                Log.e("TAG", "popup x:" + x + ", y:" + y);
                mPwDelete.showAtLocation(child, Gravity.TOP | Gravity.LEFT, x, y);
                mPwDelete.update();
                mTvDelete.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        mDeleteItemListener.deleteItem(downPosition);
                        mPwDelete.dismiss();
                        isPopupShow = false;
                    }
                });
            }
            break;
        case MotionEvent.ACTION_UP:
            break;
    }
    return super.onTouchEvent(ev);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Xamarin 中,ListView 是一个非常常见的控件,用于显示一个竖直滚动的列表。但如果我们需要实现一个横向滚动的列表,该怎么办呢?这时候,我们可以使用自定义ItemsControl 来实现这个功能。 ItemsControl 是一个用于显示一个集合的控件,它的每个元素都可以自定义显示方式。在本文中,我们会通过自定义 ItemsControl,实现一个横向滚动的列表。 首先,我们需要创建一个自定义控件,继承自 ItemsControl。在这个控件中,我们需要对 ItemContainerStyle 和 ItemsPanel 进行定义ItemContainerStyle 用于定义每个元素的样式,我们可以设置元素的大小、边距等属性。在本例中,我们设置元素宽度为 100,高度为自适应,并设置左右边距为 5。 ItemsPanel 用于定义元素的排列方式。在本例中,我们使用一个 StackPanel,设置 Orientation 为 Horizontal,这样子项就会水平排列。 下面是完整的代码实现: ```csharp using Xamarin.Forms; namespace MyNamespace { public class HorizontalItemsControl : ItemsControl { public HorizontalItemsControl() { // 设置样式 ItemContainerStyle = new Style(typeof(ViewCell)) { Setters = { new Setter { Property = ViewCell.WidthRequestProperty, Value = 100 }, new Setter { Property = ViewCell.MarginProperty, Value = new Thickness(5, 0) } } }; // 设置子项排列方式 ItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Horizontal); } } } ``` 使用起来也非常简单,只需要在 XAML 中声明这个控件即可: ```xml <local:HorizontalItemsControl ItemsSource="{Binding MyItems}"> <local:HorizontalItemsControl.ItemTemplate> <DataTemplate> <!-- 这里放置每个元素的显示内容 --> </DataTemplate> </local:HorizontalItemsControl.ItemTemplate> </local:HorizontalItemsControl> ``` 其中,MyItems 指定了要显示的数据源,ItemTemplate 指定了每个元素的显示方式。 这样,我们就实现了一个简单的横向滚动列表。当然,这只是一个简单的示例,实际使用中可能还需要进行更多的定制和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值