15.阻止触摸窃贼

作者: Jennyni1122 | 来源:发表于2018-10-20 08:40 被阅读24次

15.1 问题

应用程序视图中设计了嵌套的触摸交互,这些交互不能很好地作用于触摸层次结构 的标准流程,在此层次结构中,较高层的容器视图通过子视图进行窃取来直接处理触摸事件。

15.2 解决方案

(API Level 1)
ViewGroup是框架中所有布局和容器的基类,它为此提供了描述性命名方法requestDisallowTouchIntercept()。在任何容器视图上设置此标志会指示框架,在当前手势持续期间,我们更希望它们不会拦截进入其子视图的事件。

15.3 实现机制

为展示此方法的实际使用,我们创建了一个示例,其中两个互相竞争的可触摸视图位于同一位置。外部包含视图是ListView,它通过滚动内容响应指示垂直拖动的触摸事件。在ListView内部是作为头部添加的ViewPager,它响应水平拖动触摸事件以在页面之间轻扫。就其本质来说,该例带来了一个问题,水平轻扫在垂直方向上远距离变化的ViewPager的尝试会为了支持ListView滚动而被取消,因为ListView会监控和拦截这些事件。人们无法在垂直或水平运动过程中进行拖动,因此这就产生了可用性问题。
为建立此例,首先需要声明一个维度资源(参见以下代码),代码清单给出了完整的Activity。
res/values/dimens.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="header_height">150dp</dimen>
</resources>

管理触摸拦截的Activity

public class DisallowActivity extends Activity implements
        ViewPager.OnPageChangeListener {
    private static final String[] ITEMS = {
            "Row One", "Row Two", "Row Three", "Row Four",
            "Row Five", "Row Six", "Row Seven", "Row Eight",
            "Row Nine", "Row Ten"
    };

    private ViewPager mViewPager;

    private ListView mListView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Create a header view of horizontal swiping items
        mViewPager = new ViewPager(this);
        // As a ListView header, ViewPager must be given a fixed height
        mViewPager.setLayoutParams(new ListView.LayoutParams(
                ListView.LayoutParams.MATCH_PARENT,
                getResources().getDimensionPixelSize(R.dimen.header_height)) );
        // Listen for paging state changes to disable parent touches
        mViewPager.setOnPageChangeListener(this);
        mViewPager.setAdapter(new HeaderAdapter(this));

        // Create a vertical scrolling list
        mListView = new ListView(this);
        // Add the pager as the list header
        mListView.addHeaderView(mViewPager);
        // Add list items
        mListView.setAdapter(new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, ITEMS));

        setContentView(mListView);
    }

    /* OnPageChangeListener Methods */
    
    @Override
    public void onPageScrolled(int position,
            float positionOffset, int positionOffsetPixels) { }

    @Override
    public void onPageSelected(int position) { }

    @Override
    public void onPageScrollStateChanged(int state) {
        // While the ViewPager is scrolling, disable the ScrollView touch
        // intercept so it cannot take over and try to vertical scroll.
        // This flag must be set for each gesture you want to override.
        boolean isScrolling = state != ViewPager.SCROLL_STATE_IDLE;
        mListView.requestDisallowInterceptTouchEvent(isScrolling);
    }

    private static class HeaderAdapter extends PagerAdapter {
        private Context mContext;

        public HeaderAdapter(Context context) {
            mContext = context;
        }

        @Override
        public int getCount() {
            return 5;
        }

        @Override
        public Object instantiateItem(ViewGroup container,
                int position) {
            // Create a new page view
            TextView tv = new TextView(mContext);
            tv.setText(String.format("Page %d", position + 1));
            tv.setBackgroundColor((position % 2 == 0) ? Color.RED
                    : Color.GREEN);
            tv.setGravity(Gravity.CENTER);
            tv.setTextColor(Color.BLACK);

            // Add as the view for this position, and return as the object for
            // this position
            container.addView(tv);
            return tv;
        }

        @Override
        public void destroyItem(ViewGroup container,
                int position, Object object) {
            View page = (View) object;
            container.removeView(page);
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return (view == object);
        }
    }
}

在此Activity中,作为根视图的ListView包含一个基本适配器,用于显示字符串条目的静态列表。同样在onCreate()方法中,创建ViewPager实例并作为头部视图添加到列表中。我们将在本章后面更详细地讨论ViewPager的工作方式,此处只需要知道我们正在创建一个带有自定义PagerAdapter的简单ViewPager,它显示了一些彩色视图作为其页面,以供用户在这些页面直接轻扫。
创建ViewPager之后,构造并应用一组ListView.LayoutParams来控制ViewPager如何作为头部显示。必须执行该操作,因为ViewPager自身没有内在的内容大小,并且列表不能很好地作用于没有明确高度的视图。通过维度资源应用固定的高度,从而可以轻松获得适当缩放的dp值,该值与设备无关。这比完全通过Java代码全面构造dp值要简单很多。
此例的关键之处在于Activity实现的onPageChangeListener(该回调在后面会用于与ViewPager)。当用户与ViewPager交互并左右轻扫时,就会触发此回调。在onPageScrollStateChanged()方法内部,我们传递一个指示ViewPager是否空闲、
Activity正在滚动或在滚动后停到某个页面的值。这是控制父ListView的触摸拦截行为的最佳位置。当ViewPager的滚动状态不是空闲时,我们不希望ListView窃取Viewager正在使用的触摸事件,因此在requestDisallowTouchIntercept()中设置相应的标志。
连续触发该值还要另一个原因。在原始解决方案中提及,该标志对当前手势有效。这意味着每次新的ACTION_DOWN事件发生时,我们需要再次设置该标志。没有添加触摸侦听器来查找特定的事件,我们基于子视图的滚动行为连续设置该标志,这就获得了相同的效果。

相关文章

  • 15.阻止触摸窃贼

    15.1 问题 应用程序视图中设计了嵌套的触摸交互,这些交互不能很好地作用于触摸层次结构 的标准流程,在此层次结构...

  • 移动端常见的触摸相关事件

    Touch触摸事件 阻止默认事件preventDefault(); touchstart:手指触摸到屏幕会触发 t...

  • 杀人事件

    (一) 有两个窃贼,我们姑且称之为窃贼甲和窃贼乙。这么称呼他们,也并非他们没有自己...

  • 未来属于自己

    命运,瞬息万变 我伸出这已被荆棘刺伤的双手 试图将它触摸 却无法阻止 阻止这命运的变幻 被压迫的灵魂 在此刻,跳动...

  • 窃贼

    窃贼 文|飞 我仍旧是个浪子 在深夜里 依然不能入睡 我被窗外肆意的风声撕扯 随着它的踪迹游荡着 久久不能平静 那...

  • 窃贼

    人总是在经历某些事情后变得异常清醒,然后变得麻木无情。之后情商也变得特别低,人来人往打招呼过过场,聊得来变我...

  • 窃贼

    不要把时光当做窃贼 偷窃你时光的,是你自己 懒惰,贪婪,欲望太多 你偷走了自己的梦 还说时光匆匆留不住 你知道么?...

  • 窃贼

    女孩猫着腰,鬼鬼祟祟的把手伸进站在前面男人的口袋,熟练的夹出两枚金币。转身便走。 突然,一把长剑抵住她的喉咙,持剑...

  • 窃贼

    一个编辑——我是说时空特警——为修补时空错误来到我们这,并要求我帮忙寻找一名偷渡客,据他说,那个家伙已经偷了我不少...

  • 窃贼

    一扇木头门 和一支狗尾巴草 谁能更早料知你的离开 曲折的土路 有你煽情的走过 笔挺和从容 原来才是你真正的秘密 炉...

网友评论

    本文标题:15.阻止触摸窃贼

    本文链接:https://www.haomeiwen.com/subject/ymkgwftx.html