NestedScrollViewとCoordinatorLayoutを使用して、ツールバーのスクロールアニメーションを有効にしました(app:layout_scrollFlags = "scroll | enterAlways"による)。
NestedScrollViewには、ルートの子としてLinearLayoutが含まれています。2つのTextViewをLinearLayoutに配置して、展開/折りたたみアニメーションを有効にします。 1つはVisibleに設定され、もう1つはGoneに設定されました。 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);
}
}
これはNestedScrollViewのバグです。バグの詳細は、ここで見つけることができます: issue 。問題は、mScroller.isFinished()
のonInterceptTouchEvent(MotionEvent ev)
が、フリング操作後に(フリングが停止していても)true
を返さないことです。したがって、タッチイベントはインターセプトされます。
このバグはしばらく報告されていますが、まだ修正されていません。そのため、この問題に対する独自のバージョンのバグ修正を作成しました。独自の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
は元のものと同じ振る舞いを持つべきです。
このスレッドで同じ問題の解決策を見つけました: RecyclerView内のアイテムはスクロール直後にクリックできません
コードを修正するには、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">
私はここで別の問題を開きました: https://issuetracker.google.com/issues/68103042 それは私たちにとってはまだOreoの問題のようです(エミュレータを含む複数のデバイス)。
私の修正(ta .. @ graymeter.comの https://issuetracker.google.com/issues/3705172 の提案から適応)は、リフレクションを使用するため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;
}
}
}
Google #issues 194398
でBug
に言及しています。
NestedScrollView
のようなWorkaroundNestedScrollView.Java
クラスを使用するだけで、
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>
また、さらに多くの 詳細はこちら を見つけることもできます。
最適なソリューション:
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"
...>
これはサポートライブラリの問題でした。こちらをご覧ください https://issuetracker.google.com/u/1/issues/37070828
AndroidXを使用している場合
'androidx.appcompat:appcompat:1.1.0-alpha04'.
これはおそらくアルファビルドですが、おそらくこの問題を修正します。
私もこの問題に出会いました
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によってインターセプトされません。