草庐IT

android - ListView 行内的 ViewPager 阻止触发 onItemClick

coder 2023-11-28 原文

我在 ListView 的每一行中都有一个 ViewPager。它工作正常,当用户使用滑动手势时它会更改其中的 View ,但它会阻止调用 ListView 的 onItemClick 方法。我知道 ViewPager 是罪魁祸首,因为当我隐藏它时,会调用 onItemClick,所以这就是我正在尝试的:

我创建了一个 ViewGroup 作为行 (RowView)。此 ViewGroup 已覆盖 onInterceptTouchEvent 以避免 ViewPager 在我检测到点击时处理进一步的触摸事件。但是 onItemClick 回调仍然没有被调用。并且列表选择器不会在点击时显示。我希望这两个功能起作用。

这是来自 RowView 的 onInterceptTouchEvent 的样子:

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    int actionMasked = ev.getActionMasked();
    switch(actionMasked) {
        case MotionEvent.ACTION_DOWN:
            Log.d("RowView", "OnInterceptTouchEvent - Down");
            tapDetector.onTouchEvent(ev);
            return false;
        case MotionEvent.ACTION_CANCEL:
            Log.d("RowView", "OnInterceptTouchEvent - Cancel");
            tapDetector.onTouchEvent(ev);
            break;
        case MotionEvent.ACTION_UP:
            if(tapDetector.onTouchEvent(ev)) {
                Log.d("RowView", "OnInterceptTouchEvent - UP!");
                return true;
            }
            break;
    }

    return super.onInterceptTouchEvent(ev);
}

有什么解决这个问题的建议吗?

编辑:有关当 ViewPager 处于 Activity 状态时如何不调用 MainActivity 中的 onItemClick 的无效示例(Lollipop 列表选择器也未出现)

MainActivity

ListView listView = (ListView) findViewById(R.id.main_list);
listView.setAdapter(new MainListAdapter(this, 30));
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        Log.d(TAG, "onItemClick: " + position);
    }
});

List item XML:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:descendantFocusability="blocksDescendants"
    >

    <TextView
        android:id="@+id/row_num"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        />

    <android.support.v4.view.ViewPager
        android:id="@+id/row_viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible"
        />
</RelativeLayout>

List adapter:

public class MainListAdapter extends BaseAdapter {
    private Context context;
    private LayoutInflater inflater;
    private int count;

    public MainListAdapter(Context context, int count) {
        this.context = context;
        this.inflater = LayoutInflater.from(context);
        this.count = count;
    }

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

    @Override
    public Object getItem(int position) {
        return position;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;

        if(convertView == null) {
            holder = new ViewHolder();
            convertView = createRow(parent, holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        holder.textView.setText(Integer.toString(position));
        int randomPages = (int) (new Random().nextDouble()*5+2);
        holder.viewPager.setAdapter(new NumAdapter(context, randomPages));

        return convertView;
    }

    private View createRow(ViewGroup parent, ViewHolder holder) {
        View view = inflater.inflate(R.layout.row_main_listview, parent, false);
        holder.textView = (TextView) view.findViewById(R.id.row_num);
        holder.viewPager = (ViewPager) view.findViewById(R.id.row_viewpager);
        view.setTag(holder);

        return view;
    }

    private static class ViewHolder {
        public TextView textView;
        public ViewPager viewPager;
    }
}

ViewPager's Adapter:

public class NumAdapter extends PagerAdapter {
    private LayoutInflater inflater;
    private int count;

    public NumAdapter(Context context, int count) {
        this.inflater = LayoutInflater.from(context);
        this.count = count;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        TextView textView = (TextView) inflater.inflate(R.layout.page_viewpager, container, false);
        textView.setText("Page " + position);
        container.addView(textView);
        return textView;
    }

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

    @Override
    public boolean isViewFromObject(View arg0, Object arg1) {
        return arg0 == arg1;
    }

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

最佳答案

我认为重写 listview onintercepter 比重写 viewgroup 更好。

简单的 TouchEvent 流程:

Acitivity触摸事件->viewgroup.dispatchtouchevent->viewgroup.intercepter..->view.dispatchtouch...->.....

在本例中是 list.dispatch 调用。将事件抛给 ViewPager.dispatch。但在 ViewPager.dispatchtouchevent 之前,调用 ListView.intercepterTouchEvent

如果 dispatchTouchEvent 返回 false 调用父 ViewTouchEvent 但返回 true 调用流程下降。

如果 intercepterTouchEvent 返回 true 不调用子 dispatchTouchEvent 但返回 false 调用子 dispatchTouchEvent 。 所以 listview.intercepterTouchEvent 返回 true,调用 onItemClick

因此,如果 listView.intercepterTouchEvent 返回 true,则不会滑动 viewPager 项。

您可以通过 2 种方式了解用户的 Action 滑动或点击。 TouchEventguesturedetector..

在 ListView 的 IntercepterTouchEvent(Event ev);

VelocityTracker mVelocityTracker;
PointF mLastPoint;
public mListView(Context context) {
    super(context);
    init();
}

public mListView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
}

public mListView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
}

private void init(){
    mLastPoint = new PointF();
}


@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {

    if(mVelocityTracker == null)
        mVelocityTracker = VelocityTracker.obtain();
    mVelocityTracker.addMovement(ev);

    switch (ev.getAction()){
        case MotionEvent.ACTION_MOVE:
            mVelocityTracker.computeCurrentVelocity(100);
            int x = (int)Math.abs(mVelocityTracker.getXVelocity());
            int move_x = (int)Math.abs(ev.getX() - mLastPoint.x);
            Log.d("ListView","speed : " + x +" move_x : " + move_x);
            //here x is drag speed. (pixel/s)
            // change value left right both value you want speed and move amount
            if(move_x < 100 || x <100) {
                mLastPoint.set(ev.getX(), ev.getY());
                return true;
            }
            break;
        case MotionEvent.ACTION_DOWN:
            mLastPoint.set(ev.getX(), ev.getY());
            break;
        case MotionEvent.ACTION_UP:

            mVelocityTracker.recycle();mVelocityTracker = null;

            break;
    }
    return super.onInterceptTouchEvent(ev);
}

您可以滑动速度大约 100 或移动量 100 像素。如果不执行点击事件。

希望这篇文字能帮到你......

并添加编辑一些代码。

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {

    if(mVelocityTracker == null)
        mVelocityTracker = VelocityTracker.obtain();
    mVelocityTracker.addMovement(ev);

    switch (ev.getAction()){
        case MotionEvent.ACTION_MOVE:
            mVelocityTracker.computeCurrentVelocity(10);
            int x = (int)Math.abs(mVelocityTracker.getXVelocity());
            int move_x = (int)Math.abs(ev.getX() - mLastPoint.x);
            int move_y = (int)Math.abs(ev.getY() - mLastPoint.y);
            Log.d("ListView","speed : " + x +" move_x : " + move_x + " move_y : "+ move_y);
            if(move_x < move_y || x < 10) {
                mLastPoint.set(ev.getX(), ev.getY());
                return true;
            }else if(move_x > move_y){
                return false;
            }
            break;
        case MotionEvent.ACTION_DOWN:
            mLastPoint.set(ev.getX(), ev.getY());
            break;
        case MotionEvent.ACTION_UP:
            break;
    }
    return super.onInterceptTouchEvent(ev);
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    Log.d("ListView", "dispatch");
    switch (ev.getAction()){
        case MotionEvent.ACTION_MOVE:
            break;
        case MotionEvent.ACTION_DOWN:
            break;
        case MotionEvent.ACTION_UP:
            if(mVelocityTracker != null){mVelocityTracker.recycle();mVelocityTracker = null;}
            break;
    }
    return super.dispatchTouchEvent(ev);;
}

关于android - ListView 行内的 ViewPager 阻止触发 onItemClick,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29622098/

有关android - ListView 行内的 ViewPager 阻止触发 onItemClick的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. ruby - 触发器 ruby​​ 中 3 点范围运算符和 2 点范围运算符的区别 - 2

    请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是

  3. ruby-on-rails - Rails - 乐观锁定总是触发 StaleObjectError 异常 - 2

    我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd

  4. ruby-on-rails - 如何在 Rails Controller Action 上触发 Facebook 像素 - 2

    我有一个ruby​​onrails应用程序。我按照facebook的说明添加了一个像素。但是,要跟踪转化,Facebook要求您将页面置于达到预期结果时出现的转化中。即,如果我想显示客户已注册,我会将您注册后转到的页面作为成功对象进行跟踪。我的问题是,当客户注册时,在我的应用程序中没有登陆页面。该应用程序将用户带回主页。它在主页上显示了一条消息,所以我想看看是否有一种方法可以跟踪来自Controller操作而不是实际页面的转化。我需要计数的Action没有页面,它们是ControllerAction。是否有任何人都知道的关于如何执行此操作的gem、文档或最佳实践?这是进入布局文件的像素

  5. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  6. ruby - Faye WebSocket,关闭处理程序被触发后重新连接到套接字 - 2

    我有一个super简单的脚本,它几乎包含了FayeWebSocketGitHub页面上用于处理关闭连接的内容:ws=Faye::WebSocket::Client.new(url,nil,:headers=>headers)ws.on:opendo|event|p[:open]#sendpingcommand#sendtestcommand#ws.send({command:'test'}.to_json)endws.on:messagedo|event|#hereistheentrypointfordatacomingfromtheserver.pJSON.parse(event.d

  7. ruby-on-rails - Ruby method_added 回调不触发包括模块 - 2

    我想写一点“Deprecate-It”库并经常使用“method_added”回调。但是现在我注意到在包含模块时不会触发此回调。是否有任何回调或变通方法,以便在某些内容包含到自身时通知类“Foobar”?用于演示的小Demo:#IncludingModulswon'ttriggermethod_addedcallbackmoduleInvisibleMethoddefinvisible"Youwon'tgetacallbackfromme"endendclassFoobardefself.method_added(m)puts"InstanceMethod:'#{m}'addedto'

  8. javascript - jQuery 的 jquery-1.10.2.min.map 正在触发 404(未找到) - 2

    我看到有关未找到文件min.map的错误消息:GETjQuery'sjquery-1.10.2.min.mapistriggeringa404(NotFound)截图这是从哪里来的? 最佳答案 如果ChromeDevTools报告.map文件的404(可能是jquery-1.10.2.min.map、jquery.min.map或jquery-2.0.3.min.map,但任何事情都可能发生)首先要知道的是,这仅在使用DevTools时才会请求。您的用户不会遇到此404。现在您可以修复此问题或禁用sourcemap功能。修复:获取文

  9. ruby - 在描述之外使用 RSpec 的 "expect"等...它会阻止 - 2

    我正在构建一个网络应用程序自动化框架,旨在允许:当然是自动化任务轻松构建测试场景我正在使用Capybara与浏览器通信,我有一个组件库,其中包含许多辅助函数(login_to_the_back_office、create_customer等)。现在我希望我的组件可以独立使用,也可以在RSpec测试中使用。这意味着我的组件(包含在库中)没有环绕describe...it...默认情况下会阻塞,但在测试使用它们时它们会在某个时候出现,因此它们应该使用expect和friend尽可能多。我关注了rspec's.shouldfails(outsidedescribe/itblock)inRub

  10. ruby - 为什么触发器运算符包含第二个条件? - 2

    以下代码使用了触发器运算符。(1..10).each{|x|print"#{x},"ifx==3..x==5}为什么结果是3,4,5?我觉得应该是3,4。如教程中所述,此表达式在x==3时为真,并一直为真,直到x==5。如果“5”的计算结果为false,如何打印它?谁能为我澄清一下? 最佳答案 来自“TheRubyProgrammingLanguage”的重要链接是:4.6.9.1Booleanflip-flopsWhenthe..and...operatorsareusedinaconditional,suchasanifstat

随机推荐