我使用NestedScrollView和CoordinatorLayout为工具栏启用滚动动画(通过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);
}
}
答案 0 :(得分:32)
我在这个帖子上找到了同样问题的解决方案:The item inside RecyclerView can't be clicked right after scrolling
您可以通过将layout_behavior添加到 AppBarLayout 来修复代码。您可以在此处找到代码Fixed AppBarLayout.Behavior 。只需在此项目中添加项目并修改代码:
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
app:layout_behavior="yourPackageName.FixAppBarLayoutBehavior"
android:layout_height="wrap_content">
答案 1 :(得分:18)
这是NestedScrollView的一个错误,可以在这里找到错误的详细信息:issue。问题是,mScroller.isFinished()
中的onInterceptTouchEvent(MotionEvent ev)
在投掷操作后不会返回true
(即使停止投掷)。因此触发事件被截获。
此错误已报告一段时间,但仍未修复。所以我已经为这个问题创建了自己的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
应与原始行为具有相同的行为。
答案 2 :(得分:8)
我在这里打开了另一个问题:https://issuetracker.google.com/issues/68103042因为它似乎仍然是Oreo中的一个问题(多个设备,包括模拟器)。
我的修复(改编自@ {whitemeter.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;
}
}
}
答案 3 :(得分:1)
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>
您可以找到更多details here。
答案 4 :(得分:0)
我也遇到了这个问题
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拦截
答案 5 :(得分:0)
最佳解决方案:
1)创建此类:
public class FixAppBarLayoutBehavior extends AppBarLayout.Behavior {
public FixAppBarLayoutBehavior() {
super();
}
public FixAppBarLayoutBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target,
int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,
dxUnconsumed, dyUnconsumed, type);
stopNestedScrollIfNeeded(dyUnconsumed, child, target, type);
}
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
View target, int dx, int dy, int[] consumed, int type) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
stopNestedScrollIfNeeded(dy, child, target, type);
}
private void stopNestedScrollIfNeeded(int dy, AppBarLayout child, View target, int type) {
if (type == ViewCompat.TYPE_NON_TOUCH) {
final int currOffset = getTopAndBottomOffset();
if ((dy < 0 && currOffset == 0)
|| (dy > 0 && currOffset == -child.getTotalScrollRange())) {
ViewCompat.stopNestedScroll(target, ViewCompat.TYPE_NON_TOUCH);
}
}
}}
2)并在xml中使用:
<android.support.design.widget.AppBarLayout
...
app:layout_behavior="yourPackageName.FixAppBarLayoutBehavior"
...>
答案 6 :(得分:0)
这是支持库中的一个问题。看到这个 https://issuetracker.google.com/u/1/issues/37070828
如果您使用的是androidX,则
'androidx.appcompat:appcompat:1.1.0-alpha04'.
这可能是解决此问题的方法,尽管这是Alpha版。