Android CollapsingToolbarLayout折りたたみリスナー


106

およびCollapsingToolBarLayoutと一緒に使用していますが、それらはすべてFineで動作しています。上にスクロールしたときに修正されるように設定しました。ツールバーが折りたたまれているときに、ツールバーのタイトルテキストを変更する方法があるかどうかを知りたいです。AppBarLayoutCoordinatorLayoutToolbarCollapsingToolBarLayout

まとめると、スクロールしたときと展開したときの2つの異なるタイトルが必要です。

よろしくお願いします

回答:


150

@Frodio Begginsと@Nifhelコードに基づいて、完全な実装を共有します。

public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener {

    public enum State {
        EXPANDED,
        COLLAPSED,
        IDLE
    }

    private State mCurrentState = State.IDLE;

    @Override
    public final void onOffsetChanged(AppBarLayout appBarLayout, int i) {
        if (i == 0) {
            if (mCurrentState != State.EXPANDED) {
                onStateChanged(appBarLayout, State.EXPANDED);
            }
            mCurrentState = State.EXPANDED;
        } else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) {
            if (mCurrentState != State.COLLAPSED) {
                onStateChanged(appBarLayout, State.COLLAPSED);
            }
            mCurrentState = State.COLLAPSED;
        } else {
            if (mCurrentState != State.IDLE) {
                onStateChanged(appBarLayout, State.IDLE);
            }
            mCurrentState = State.IDLE;
        }
    }

    public abstract void onStateChanged(AppBarLayout appBarLayout, State state);
}

そして、あなたはそれを使うことができます:

appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() {
    @Override
    public void onStateChanged(AppBarLayout appBarLayout, State state) {
        Log.d("STATE", state.name());
    }
});

21
そのとおりです。ただし、列挙型が整数値に変換されるProguardを使用しないでください。
rciovati 2016年

1
知らなかった。それは素晴らしいことです!
tim687 2016年

2
また、列挙型はタイプセーフを保証する非常に優れた方法です。State.IMPLODEDは存在しないので(コンパイラーは文句を言うでしょう)持つことはできませんが、整数定数を使用すると、コンパイラーが誤っていると考えている値を使用できます。シングルトンとしても良いですが、それは別の話です。
droppin_science

@droppin_science for android enumsはIntDefをチェックしてください
David

1
@DavidDarias個人的には、オーバーヘッドがある場合でも列挙型がはるかにクリーンなアプローチであることがわかります(ここで引数を開始します... :-)
droppin_science

95

このソリューションは、AppBarLayout折りたたみまたは拡張を検出するために完全に機能します。

appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {

            if (Math.abs(verticalOffset)-appBarLayout.getTotalScrollRange() == 0)
            {
                //  Collapsed


            }
            else
            {
                //Expanded


            }
        }
    });

で使用さaddOnOffsetChangedListenerれますAppBarLayout


36

にフックOnOffsetChangedListenerしますAppBarLayoutverticalOffsetが0 に達するか、Toolbar高さ未満になると、CollapsingToolbarLayoutが折りたたまれたことを意味します。それ以外の場合は、折りたたまれています。

mAppBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                if(verticalOffset == 0 || verticalOffset <= mToolbar.getHeight() && !mToolbar.getTitle().equals(mCollapsedTitle)){
                    mCollapsingToolbar.setTitle(mCollapsedTitle);
                }else if(!mToolbar.getTitle().equals(mExpandedTitle)){
                    mCollapsingToolbar.setTitle(mExpandedTitle);
                }

            }
        });

1
それは私のために働いていません。OnCollapseでホームボタンを有効にし、Expandでホームボタンを非表示にしたい
Maheshwar Ligade

9
ツールバーが完全に展開されている場合、verticalOffsetの値はゼロのようで、折りたたむと負になります。ツールバーが折りたたまれている場合、verticalOffsetは、ツールバーの高さ(-mToolbar.getHeight())に等しくなります。したがって、ツールバーは部分的に展開されます "if(verticalOffset> -mToolbar.getHeight())"
Mike

appBarLayout.getVerticalOffset()メソッドがどこにあるのか疑問に思われる場合appBarLayout.getY()は、コールバックして、コールバックで使用されているのと同じ値を取得できます。
Jarett Millard

残念ながら、ジャレット・ミラードは正しくありません。fitsSystemWindowの構成とStatusBarの構成(透明)によっては、appBarLayout.getY()それがそうである可能性がありますverticalOffset = appBarLayout.getY() + statusBarHeight
Capricorn

1
実際にappbarと対話していなくても、mAppBarLayout.addOnOffsetChangedListener(listener)が繰り返し呼び出されていることに気付いた人はいますか?または、この動作を観察しているレイアウト/アプリのバグです。助けて!
Rahul Shukla

16

このコードは私のために働きました

mAppBarLayout.addOnOffsetChangedListener(new   AppBarLayout.OnOffsetChangedListener() {
        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
            if (verticalOffset == -mCollapsingToolbarLayout.getHeight() + mToolbar.getHeight()) {
                //toolbar is collapsed here
                //write your code here
            }
        }
    });

Nikola Despotoskiよりも良い回答
Vignesh Bala

信頼できるソリューションではないようです。私はそれをテストし、私のデバイス上の値は次のとおりです。mCollapsingToolbarLayout.getHeight()= 1013、mToolbar.getHeight()= 224折りたたまれた状態で、ソリューションverticalOffsetによるのでは-789でなければならない、しかし、それは-693に等しいです
レオドロイドコーダー

16
private enum State {
    EXPANDED,
    COLLAPSED,
    IDLE
}

private void initViews() {
    final String TAG = "AppBarTest";
    final AppBarLayout mAppBarLayout = findViewById(R.id.appbar);
    mAppBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
        private State state;

        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
            if (verticalOffset == 0) {
                if (state != State.EXPANDED) {
                    Log.d(TAG,"Expanded");
                }
                state = State.EXPANDED;
            } else if (Math.abs(verticalOffset) >= appBarLayout.getTotalScrollRange()) {
                if (state != State.COLLAPSED) {
                    Log.d(TAG,"Collapsed");
                }
                state = State.COLLAPSED;
            } else {
                if (state != State.IDLE) {
                    Log.d(TAG,"Idle");
                }
                state = State.IDLE;
            }
        }
    });
}

10

以下を使用して、collapsingToolBarアルファパーセンテージを取得できます。

appbarLayout.addOnOffsetChangedListener( new AppBarLayout.OnOffsetChangedListener() {
        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
            float percentage = ((float)Math.abs(verticalOffset)/appBarLayout.getTotalScrollRange());
            fadedView.setAlpha(percentage);
    });

参考のために:リンク


2
これは正規化されたオフセットを提供するので、すばらしい答えです。私の意見では、APIはこれをverticalOffsetピクセル距離ではなく直接提供しているはずです。
dbm 2017

5

これがKotlinソリューションです。をに追加OnOffsetChangedListenerAppBarLayoutます。

方法A:

AppBarStateChangeListener.ktプロジェクトに追加:

import com.google.android.material.appbar.AppBarLayout
import kotlin.math.abs

abstract class AppBarStateChangeListener : AppBarLayout.OnOffsetChangedListener {

    enum class State {
        EXPANDED, COLLAPSED, IDLE
    }

    private var mCurrentState = State.IDLE

    override fun onOffsetChanged(appBarLayout: AppBarLayout, i: Int) {
        if (i == 0 && mCurrentState != State.EXPANDED) {
            onStateChanged(appBarLayout, State.EXPANDED)
            mCurrentState = State.EXPANDED
        }
        else if (abs(i) >= appBarLayout.totalScrollRange && mCurrentState != State.COLLAPSED) {
            onStateChanged(appBarLayout, State.COLLAPSED)
            mCurrentState = State.COLLAPSED
        }
        else if (mCurrentState != State.IDLE) {
            onStateChanged(appBarLayout, State.IDLE)
            mCurrentState = State.IDLE
        }
    }

    abstract fun onStateChanged(
        appBarLayout: AppBarLayout?,
        state: State?
    )

}

にリスナーを追加しますappBarLayout

appBarLayout.addOnOffsetChangedListener(object: AppBarStateChangeListener() {
        override fun onStateChanged(appBarLayout: AppBarLayout?, state: State?) {
            Log.d("State", state.name)
            when(state) {
                State.COLLAPSED -> { /* Do something */ }
                State.EXPANDED -> { /* Do something */ }
                State.IDLE -> { /* Do something */ }
            }
        }
    }
)

方法B:

appBarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
        if (abs(verticalOffset) - appBarLayout.totalScrollRange == 0) { 
            // Collapsed
        } else if (verticalOffset == 0) {
            // Expanded
        } else {
            // Idle
        }
    }
)

3

このソリューションは私のために働いています:

@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int i) {
  if (i == 0) {
    if (onStateChangeListener != null && state != State.EXPANDED) {
      onStateChangeListener.onStateChange(State.EXPANDED);
    }
    state = State.EXPANDED;
  } else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) {
    if (onStateChangeListener != null && state != State.COLLAPSED) {
      onStateChangeListener.onStateChange(State.COLLAPSED);
    }
    state = State.COLLAPSED;
  } else {
    if (onStateChangeListener != null && state != State.IDLE) {
      onStateChangeListener.onStateChange(State.IDLE);
    }
    state = State.IDLE;
  }
}

AppBarLayoutでaddOnOffsetChangedListenerを使用します。


完全なコードを共有できますか?State.EXPANDEDなどとは何ですか?
Chetna 2015

1

CollapsingToolBarLayoutを使用している場合は、これを置くことができます

collapsingToolbar.setExpandedTitleColor(ContextCompat.getColor(activity, android.R.color.transparent));
collapsingToolbar.setTitle(title);

1

このコードは私にとって完璧に機能しています。パーセンテージスケールを使用できます

@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
    double percentage = (double) Math.abs(verticalOffset) / collapsingToolbar.getHeight();
    if (percentage > 0.8) {
        collapsingToolbar.setTitle("Collapsed");
    } else {
        collapsingToolbar.setTitle("Expanded");
    }
}

0

私のツールバーのオフセット値は、折りたたむと-582で、expand = 0になるので、Toastでoffsetvalueを設定して値を見つけ、それに応じてコードを変更します。

 mAppBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
            if(verticalOffset == -582) {
            Toast.makeText(MainActivity.this, "collaped" + verticalOffset, Toast.LENGTH_SHORT).show();
            mCollapsingToolbarLayout.setTitle("Collapsed");
            }else if(verticalOffset == 0){
                Toast.makeText(MainActivity.this, "expanded" + verticalOffset, Toast.LENGTH_SHORT).show();
            mCollapsingToolbarLayout.setTitle("expanded");
            }
        }
    });
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.