web-dev-qa-db-ja.com

NestedScrollView&CollapsingToolbarLayoutのスクロールを無効にする方法(たとえば、以下にコンテンツがなくなったとき)

バックグラウンド

多くのアプリに表示されているのと同じ機能を追加しようとしています。画面の上部領域は、スクロールされたコンテンツに応じて縮小および拡大します。

このために、 the CheeseSquare sample に示すように、Googleのデザインライブラリを使用します。

問題

NestedScrollViewのコンテンツの量に関係なく、コンテンツの最後のビューの下までスクロールして、アクションバーの最終的な状態を確認できます。

要するに、これは一番下までスクロールしたときに表示されるものです(CheeseSquareサンプルの変更されたコンテンツ):

enter image description here

これは私が一番下にスクロールするときに持っているものです(連絡先アプリから取得):

enter image description here

また、 ThreePhasesBottomSheet のバグを修正しようとしていますピーク状態。再現するには、水平方向にスクロールを開始し(この方法では何もしないので何もしません)、次に垂直方向にスクロールすると、ボトムシートのコンテンツのスクロールが何らかの形でトリガーされます。

したがって、「translationView()」メソッドでのスクロールを無効にする必要があります。「translation

これは、通常の使用法を使用した場合の動作です:

enter image description here

そして、これはスクロールをブロックしないというバグでどのように動作するかです:

enter image description here

私が試したこと

layout_scrollFlags 」フラグを使用して、高さをwrap_contentに変更し、clipToPaddingを削除しようとしました。およびfitsSystemWindows属性。

サンプルXMLファイルは次のとおりです。多数の代わりに1つのcardViewのみを含めるように変更しました。

<Android.support.design.widget.CoordinatorLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:id="@+id/main_content"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:fitsSystemWindows="true">

    <Android.support.design.widget.AppBarLayout
        Android:id="@+id/appbar"
        Android:layout_width="match_parent"
        Android:layout_height="@dimen/detail_backdrop_height"
        Android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        Android:fitsSystemWindows="true">

        <Android.support.design.widget.CollapsingToolbarLayout
            Android:id="@+id/collapsing_toolbar"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            Android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginStart="48dp"
            app:expandedTitleMarginEnd="64dp">

            <ImageView
                Android:id="@+id/backdrop"
                Android:layout_width="match_parent"
                Android:layout_height="match_parent"
                Android:scaleType="centerCrop"
                Android:fitsSystemWindows="true"
                app:layout_collapseMode="parallax" />

            <Android.support.v7.widget.Toolbar
                Android:id="@+id/toolbar"
                Android:layout_width="match_parent"
                Android:layout_height="?attr/actionBarSize"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:layout_collapseMode="pin" />

        </Android.support.design.widget.CollapsingToolbarLayout>

    </Android.support.design.widget.AppBarLayout>

    <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:paddingTop="24dp">

            <Android.support.v7.widget.CardView
                Android:layout_width="match_parent"
                Android:layout_height="wrap_content"
                Android:layout_margin="@dimen/card_margin">

                <LinearLayout
                    style="@style/Widget.CardContent"
                    Android:layout_width="match_parent"
                    Android:layout_height="wrap_content">

                    <TextView
                        Android:layout_width="match_parent"
                        Android:layout_height="wrap_content"
                        Android:text="Info"
                        Android:textAppearance="@style/TextAppearance.AppCompat.Title" />

                    <TextView
                        Android:layout_width="match_parent"
                        Android:layout_height="wrap_content"
                        Android:text="@string/cheese_ipsum" />

                </LinearLayout>

            </Android.support.v7.widget.CardView>

        </LinearLayout>

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

    <Android.support.design.widget.FloatingActionButton
        Android:layout_height="wrap_content"
        Android:layout_width="wrap_content"
        app:layout_anchor="@id/appbar"
        app:layout_anchorGravity="bottom|right|end"
        Android:src="@drawable/ic_discuss"
        Android:layout_margin="@dimen/fab_margin"
        Android:clickable="true"/>

</Android.support.design.widget.CoordinatorLayout>

私も次のコードを試しました:

((AppBarLayout.LayoutParams) collapsingToolbar.getLayoutParams()).setScrollFlags(0);

しかし、これは CheeseSquare の例でNestedScrollView自体のスクロールを許可し、 ThreePhasesBottomSheet サンプル.

質問

  1. 下部に表示するコンテンツがなくなったときにスクロールを停止するにはどうすればよいですか?

  2. さらに、いつでもNestedScrollViewのスクロールを無効にするために何ができますか( ThreePhasesBottomSheet サンプル)? 「setEnableScrolling(...)」のようなものですか?

    NestedScrollViewを拡張し、ScrollingViewBehaviorからも拡張しようとしましたが、スクロールを無効にするためにできることを見つけることができませんでした。

変更することはおそらく非常に簡単なことですが、私は何を見つけることができません...

編集:必要に応じて、これは現在私がデザインおよびサポートライブラリに使用しているものです

compile 'com.Android.support:appcompat-v7:23.1.0'
compile 'com.Android.support:design:23.1.0'

編集:#2の場合、BottomSheetLayout.Javaファイル内から回避策を見つけました。変数「sheetViewOwnsTouch」に関連するすべてのものを、常に「false」に設定されているかのように無効にします。これにより、ボトムシートのタッチイベントを盗むことができます。ただし、これは単なる回避策であり、この場合のみです。また、他のビューで処理されるはずのタッチイベントも発生します。プログラムでスクロールをブロックする方法と、コンテンツを表示するのに十分なスペースの他の場合でも、私はまだ知りたいと思っています。

63

下部に表示するコンテンツが他にない場合、スクロールを停止するにはどうすればよいですか?

まず、以下でコメントしたように、あなたが質問で言ったスクロールはNestedScrollViewのものではありません。 CollapsingToolbarLayoutに属します。 NestedScrollViewのスクロールイベントは、CollapsingToolbarLayoutが完全に折りたたまれたときにのみ発生します。もちろん、中にコンテンツがなくなるとスクロールが停止します(下端に到達)。 CollapsingToolbarLayoutの場合、ツールバーのlayout_heightに折りたたまれます(xmlファイルのように、"?attr/actionBarSize")。次の画像は、ツールバーである赤い長方形に注意することを示しています(背景を設定します)

BNK's image

したがって、#1の解決策を得るには、NestedScrollViewの高さを計算する必要があります。それが画面の高さよりも小さい場合は、ツールバーの高さを修正します。

つまり、activity_detail.xml次のように:

<?xml version="1.0" encoding="utf-8"?>

<Android.support.design.widget.CoordinatorLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:id="@+id/main_content"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:fitsSystemWindows="true">

    <Android.support.design.widget.AppBarLayout
        Android:id="@+id/appbar"
        Android:layout_width="match_parent"
        Android:layout_height="@dimen/detail_backdrop_height"
        Android:fitsSystemWindows="true"
        Android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <Android.support.design.widget.CollapsingToolbarLayout
            Android:id="@+id/collapsing_toolbar"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            Android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                Android:id="@+id/backdrop"
                Android:layout_width="match_parent"
                Android:layout_height="match_parent"
                Android:fitsSystemWindows="false"
                Android:scaleType="centerCrop"
                app:layout_collapseMode="parallax" />

            <Android.support.v7.widget.Toolbar
                Android:id="@+id/toolbar"
                Android:layout_width="match_parent"
                Android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

        </Android.support.design.widget.CollapsingToolbarLayout>

    </Android.support.design.widget.AppBarLayout>

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

        <LinearLayout
            Android:id="@+id/linearLayout1"
            Android:layout_width="match_parent"
            Android:layout_height="match_parent"
            Android:orientation="vertical">

            <Android.support.v7.widget.CardView
                Android:layout_width="match_parent"
                Android:layout_height="wrap_content"
                Android:layout_margin="@dimen/card_margin">

                <LinearLayout
                    style="@style/Widget.CardContent"
                    Android:layout_width="match_parent"
                    Android:layout_height="wrap_content">

                    <TextView
                        Android:layout_width="match_parent"
                        Android:layout_height="wrap_content"
                        Android:text="Info"
                        Android:textAppearance="@style/TextAppearance.AppCompat.Title" />

                    <TextView
                        Android:layout_width="match_parent"
                        Android:layout_height="wrap_content"
                        Android:text="@string/cheese_ipsum" />

                </LinearLayout>

            </Android.support.v7.widget.CardView>

        </LinearLayout>

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

</Android.support.design.widget.CoordinatorLayout>

そしてCheeseDetailActivity.Java:

public class CheeseDetailActivity extends AppCompatActivity {

    public static final String EXTRA_NAME = "cheese_name";
    private final Context mContext = this;
    private int screenHeight;
    private int linearLayoutHeight;
    private int toolbarHeight_org;
    private int toolbarHeight;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);

        Intent intent = getIntent();
        final String cheeseName = intent.getStringExtra(EXTRA_NAME);

        screenHeight = getScreenHeight(this);

        TypedValue typedValue = new TypedValue();
        getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
        final int colorPrimary = typedValue.data;

        final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        AppBarLayout appbar = (AppBarLayout) findViewById(R.id.appbar);
        final CoordinatorLayout.LayoutParams appbarLayoutParams = (CoordinatorLayout.LayoutParams)appbar.getLayoutParams();

        final ViewGroup.LayoutParams toolbarLayoutParams = toolbar.getLayoutParams();
        if (toolbarLayoutParams != null) {
            toolbarHeight_org = toolbarLayoutParams.height;
            toolbarHeight = toolbarLayoutParams.height;
        }

        final CollapsingToolbarLayout collapsingToolbar =
                (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
        collapsingToolbar.setTitle(cheeseName);

        collapsingToolbar.setContentScrimColor(colorPrimary);
        collapsingToolbar.setExpandedTitleTextAppearance(R.style.ExpandedTitleTextAppearance);
        //collapsingToolbar.setCollapsedTitleTextAppearance(R.style.CollapsedTitleTextAppearance);

        final LinearLayout linearLayout = (LinearLayout) findViewById(R.id.linearLayout1);
        ViewTreeObserver observer = linearLayout.getViewTreeObserver();
        observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                linearLayoutHeight = linearLayout.getHeight();
                if (linearLayoutHeight + toolbarHeight < screenHeight) {
                    if (toolbarLayoutParams != null) {
                        toolbarLayoutParams.height = screenHeight - linearLayoutHeight - 20;
                        if (toolbarLayoutParams.height < toolbarHeight_org) {
                            toolbarLayoutParams.height = toolbarHeight_org;
                        }

                        int extended_text_size = (int) getResources().getDimension(R.dimen.expanded_text_size);

                        if (appbarLayoutParams.height - toolbarLayoutParams.height <= extended_text_size) {
                            int value = appbarLayoutParams.height - toolbarLayoutParams.height;
                            if (value < 0) {
                                appbarLayoutParams.height = toolbarLayoutParams.height - value + extended_text_size * 3;
                            } else {
                                appbarLayoutParams.height = toolbarLayoutParams.height + extended_text_size * 3;
                            }
                            if (appbarLayoutParams.height >= screenHeight) {
                                appbarLayoutParams.height = screenHeight;
                            }
                        }

                        // collapsingToolbar.setContentScrimColor(getResources().getColor(Android.R.color.transparent));
                        if (toolbarLayoutParams.height > toolbarHeight_org) {
                            collapsingToolbar.setContentScrimColor(ContextCompat.getColor(mContext, Android.R.color.transparent));
                        }
                    }
                }
                // Removes the listener if possible
                ViewTreeObserver viewTreeObserver = linearLayout.getViewTreeObserver();
                if (viewTreeObserver.isAlive()) {
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                        linearLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    } else {
                        linearLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    }
                }
            }
        });

        loadBackdrop();
        appbar.setExpanded(true);
    }

    private int getScreenHeight(Context context) {
        int measuredHeight;
        Point size = new Point();
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
            wm.getDefaultDisplay().getSize(size);
            measuredHeight = size.y;
        } else {
            Display d = wm.getDefaultDisplay();
            measuredHeight = d.getHeight();
        }

        return measuredHeight;
    }

    private void loadBackdrop() {
        final ImageView imageView = (ImageView) findViewById(R.id.backdrop);
        Glide.with(this).load(Cheeses.getRandomCheeseDrawable()).centerCrop().into(imageView);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.sample_actions, menu);
        return true;
    }
}

結果は次のとおりです。

BNK's screenshot

Cheesesquareサンプルを使用して、このプロジェクトをカスタマイズし、 My GitHub にアップロードしました。それでもまだいくつかの問題があることに同意しますが、少なくとも最初の問題の解決策になる可能性があります。

ご覧ください。それが役に立てば幸い!

12
BNK

スクロールを無効にするには、NestedScrollViewとLinearLayoutの子の高さの両方を「wrap_content」に設定するだけです。

それはあなたが望むように完全には機能しませんが、少なくともコンテンツが画面に完全に収まる場合はスクロールできません。


連絡先アプリの例について言えば、CoordinatorLayoutなどの付属物を使用していないようです。

この動作は次の方法で実行できます。

<ScrollView
    Android:id="@+id/scroll_adinfo"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <FrameLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:orientation="vertical">

        <ImageView
            Android:id="@+id/image"
            Android:layout_width="match_parent"
            Android:layout_height="@dimen/image_height"
            Android:src="@mipmap/ic_launcher"/>

        <LinearLayout
            Android:id="@+id/layout_content"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:paddingTop="@dimen/image_height">

            <!-- YOUR CONTENT HERE -->
        </LinearLayout>
    </FrameLayout>
</ScrollView>

そして、あなたのコードでは、スクロールで画像を移動します:

final ImageView image = (ImageView) findViewById(R.id.image);

((ScrollView) rootView.findViewById(R.id.scroll_adinfo)).getViewTreeObserver().addOnScrollChangedListener(
            new ViewTreeObserver.OnScrollChangedListener() {

                @Override
                public void onScrollChanged() {
                    int scrollY = ((ScrollView) rootView.findViewById(R.id.scroll_adinfo)).getScrollY();

                    image.setY(scrollY / 2);
                }
            });

私は自分のプロジェクトの1つからそれを抽出して編集したので、何かを見逃すことがあります。

0
geNia