题 滚动NestedScrollView后,onClick方法无法正常工作


我使用带有CoordinatorLayout的NestedScrollView来启用工具栏的滚动动画(通过app:layout_scrollFlags =“scroll | enterAlways”)。

NestedScrollView包含LinearLayout作为根子,我将2个TextViews放入LinearLayout以启用展开/折叠动画。一个是可见的 其他人已经走了。并通过LinearLayout的onClick事件切换可见性

通常,一切都按预期工作,但是当我滚动NestedScrollView时 onClick事件无法正常工作。我需要在滚动后双击以获得展开/折叠动画

有没有人和我有同样的问题?请帮帮我

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingBottom="98dp"
        android:paddingLeft="24dp"
        android:paddingRight="24dp">

        <android.support.v7.widget.AppCompatTextView
            android:id="@+id/detail_expense_reason_trim"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:singleLine="false"
            android:textColor="@color/add_new_expense_text_color" />

        <android.support.v7.widget.AppCompatTextView
            android:id="@+id/detail_expense_reason"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:singleLine="false"
            android:textColor="@color/add_new_expense_text_color"
            android:visibility="gone" />
    </LinearLayout>

</android.support.v4.widget.NestedScrollView>

<android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.Toolbar
        android:id="@+id/detail_expense_toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:layout_scrollFlags="scroll|enterAlways"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</android.support.design.widget.AppBarLayout>

 @InjectView(R.id.detail_expense_reason)
AppCompatTextView originalReason;

@InjectView(R.id.detail_expense_reason_trim)
AppCompatTextView trimReason;

@InjectView(R.id.detail_expense_container)
LinearLayout expenseContainer;

//处理事件

public void onClick() {
    if (originalReason.getVisibility() == View.VISIBLE) {
        originalReason.setVisibility(View.GONE);
        trimReason.setVisibility(View.VISIBLE);
    } else {
        originalReason.setVisibility(View.VISIBLE);
        trimReason.setVisibility(View.GONE);
    }

}

28
2017-08-05 10:31


起源


将NestedScrollView更改为ScrollView后,一切正常,但我们错过了滚动动画来显示/隐藏工具栏 - toidv
同样的问题,你找到了解决方案吗? - Gabriel Kaffka
它似乎是谷歌设计库的错误,我仍然使用ScrollView而不是NestedScrollView并丢失动画。 - toidv
报告了这个bug code.google.com/p/android/issues/detail?id=184028 - GMan


答案:


这是NestedScrollView的一个bug,可以在这里找到bug的详细信息: 问题。问题是 mScroller.isFinished() 在 onInterceptTouchEvent(MotionEvent ev) 不会回来 true 在投掷操作之后(即使停止投掷)。因此触发事件被拦截。

这个bug已经报道了一段时间,但仍未修复。所以我已经为这个问题创建了自己的bug修复版本。我实现了自己的 NestedScrollView,复制了所有代码 NestedScrollView 并通过以下修改:

public class NestedScrollView extends FrameLayout implements NestedScrollingParent, NestedScrollingChild {
    ...
    private void initScrollView() {
        ...
        // replace this line:
        // mScroller = new ScrollerCompat(getContext(), null);
        mScroller = ScrollerCompat.create(getContext(), null);
        ...
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        ...
        switch (action & MotionEventCompat.ACTION_MASK) {
            ...
            case MotionEvent.ACTION_DOWN: {
                ...
                // replace this line:
                // mIsBeingDragged = !mScroller.isFinished();
                mIsBeingDragged = false;
                ...
            }
        }
    }   
}

和这个 NestedScrollView 应该具有与原始行为相同的行为。


12
2017-09-25 13:39



工作得很完美! - Gabriel Kaffka
此解决方案效果很好。谢谢,克里斯! - Justin Pollard
这是另一个问题。如果NestedScrollView正在抛弃,我们无法点击停止投掷 - chefish


我在这个帖子上找到了同样问题的解决方案:滚动后无法立即单击RecyclerView中的项目

您可以通过添加layout_behavior来修复代码 AppBarLayout你可以在这里找到代码 修复了AppBarLayout.Behavior 只需在此项目中添加项目并修复代码:

<android.support.design.widget.AppBarLayout android:layout_width="match_parent" app:layout_behavior="yourPackageName.FixAppBarLayoutBehavior" android:layout_height="wrap_content">


25
2017-11-07 15:32



我试了很多。这是最好的解决方案 - Emre Tekin
真的很好的解决方案 - Mladen Rakonjac
它可以解决拖拽后的触摸问题,但是正常的ACTION_MOVE在NestedScrollView中的水平RecyclerView上不起作用。谢谢你的解决方案!! - Sjd
非常感谢... - W00di
很多人都非常感谢 - ahmed_khan_89


我在这里开了另一个问题: https://issuetracker.google.com/issues/68103042 因为它似乎仍然是我们奥利奥的问题(多种设备,包括模拟器)。

我的修复(改编自ta .. @ graymeter.com的建议在 https://issuetracker.google.com/issues/37051723)不需要修改AOSP代码,因为它使用反射:

public class MyNestedScrollView extends NestedScrollView {

    private static final Logger sLogger = LogFactory.getLogger(MyNestedScrollView.class);

    private OverScroller mScroller;
    public boolean isFling = false;

    public MyNestedScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mScroller = getOverScroller();
    }

    @Override
    public void fling(int velocityY) {
        super.fling(velocityY);

        // here we effectively extend the super class functionality for backwards compatibility and just call invalidateOnAnimation()
        if (getChildCount() > 0) {
            ViewCompat.postInvalidateOnAnimation(this);

            // Initializing isFling to true to track fling action in onScrollChanged() method
            isFling = true;
        }
    }

    @Override
    protected void onScrollChanged(int l, final int t, final int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);

        if (isFling) {
            if (Math.abs(t - oldt) <= 3 || t == 0 || t == (getChildAt(0).getMeasuredHeight() - getMeasuredHeight())) {
                isFling = false;

                // This forces the mFinish variable in scroller to true (as explained the
                //    mentioned link above) and does the trick
                if (mScroller != null) {
                    mScroller.abortAnimation();
                }
            }
        }
    }

    private OverScroller getOverScroller() {
        Field fs = null;
        try {
            fs = this.getClass().getSuperclass().getDeclaredField("mScroller");
            fs.setAccessible(true);
            return (OverScroller) fs.get(this);
        } catch (Throwable t) {
            return null;
        }
    }
}

4
2017-10-22 16:08



这很有用。为我工作。 - Sujit Yadav


它是一个 Bug 提到 Google #issues 194398

只需要使用它 WorkaroundNestedScrollView.java 扩展的类 NestedScrollView 喜欢,

WorkaroundNestedScrollView.java

public class WorkaroundNestedScrollView extends NestedScrollView {

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

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    if (ev.getAction() == MotionEvent.ACTION_DOWN) {
        // Explicitly call computeScroll() to make the Scroller compute itself
        computeScroll();
    }
    return super.onInterceptTouchEvent(ev);
}
}

在你的布局中使用它,这样,

layout.xml

<com.yourpackagename.whatever.WorkaroundNestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">
...
...

</com.yourpackagename.whatever.WorkaroundNestedScrollView>

你可以找到更多 详情请点击


2
2017-12-31 13:32





我也遇到了这个问题

    public class NestedScrollView extends FrameLayout implements NestedScrollingParent,
    NestedScrollingChild, ScrollingView {
       @Override
        public boolean onTouchEvent(MotionEvent ev) {
          switch (actionMasked) {
            case MotionEvent.ACTION_DOWN: {
                if (getChildCount() == 0) {
                    return false;
                }
                //add this line
                if (!inChild((int) ev.getX(), (int) ev.getY())) {
                    return false;
                }
                if ((mIsBeingDragged = !mScroller.isFinished())) {
                        final ViewParent parent = getParent();
                    if (parent != null) {
                        parent.requestDisallowInterceptTouchEvent(true);
                    }
                }
           }
      }

并且我更改了我的xml文件,将paddingTop更改为margin_top,然后我的顶级浮动视图的OnClick事件将不会被NestedScrollView拦截


0
2017-10-25 02:31