Android CollapsingToolbarLayout collapse Listener

106

Saya menggunakan CollapsingToolBarLayoutbersama dengan AppBarLayoutdanCoordinatorLayout , dan semuanya berfungsi dengan baik sama sekali. Saya mengatur Toolbaragar saya diperbaiki ketika saya menggulir ke atas, saya ingin tahu apakah ada cara untuk mengubah teks judul Toolbar, ketika CollapsingToolBarLayoutitu runtuh.

Sebagai penutup, saya ingin dua judul berbeda saat di- scroll dan saat diperluas .

Terima kasih sebelumnya

Anaximandro Andrade
sumber

Jawaban:

150

Saya membagikan implementasi lengkap, berdasarkan kode @Frodio Beggins dan @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);
}

Dan kemudian Anda dapat menggunakannya:

appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() {
    @Override
    public void onStateChanged(AppBarLayout appBarLayout, State state) {
        Log.d("STATE", state.name());
    }
});
rciovati.dll
sumber
21
Itu benar. Tapi tolong jangan menggunakan Proguard bahwa enum akan diterjemahkan dalam nilai integer.
rciovati
1
Saya tidak tahu itu. Itu hebat!
tim687
2
Juga enum adalah cara yang sangat bagus untuk memastikan keamanan tipe. Anda tidak dapat memiliki State.IMPLODED karena tidak ada (kompilator akan mengeluh) tetapi dengan konstanta Integer Anda dapat menggunakan nilai yang menurut kompilator tidak salah. Mereka bagus sebagai lajang juga tapi itu cerita lain.
droppin_science
@droppin_science untuk enum android, periksa IntDef
David Darias
1
@DavidDarias Secara pribadi saya menemukan enum pendekatan yang jauh lebih bersih bahkan dengan overhead mereka (mulai argumen di sini ... :-)
droppin_science
95

Solusi ini berfungsi dengan sempurna bagi saya untuk mendeteksi AppBarLayoutruntuh atau meluas.

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

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


            }
            else
            {
                //Expanded


            }
        }
    });

Digunakan addOnOffsetChangedListenerdi AppBarLayout.

Muhamed Riyas M
sumber
36

Hubungkan OnOffsetChangedListenerke AppBarLayout. Ketika verticalOffsetmencapai 0 atau kurang dari Toolbartingginya, itu berarti CollapsingToolbarLayout telah menciut, jika tidak maka akan meluas atau diperluas.

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);
                }

            }
        });
Nikola Despotoski
sumber
1
itu tidak berhasil untuk saya. OnCollapse saya ingin mengaktifkan tombol beranda dan di Perluas menyembunyikan tombol beranda
Maheshwar Ligade
9
Nilai verticalOffset tampaknya menjadi nol saat bilah alat diperluas sepenuhnya, lalu menjadi negatif saat menciutkan. Ketika toolbar diciutkan, verticalOffset sama dengan negatif tinggi toolbar (-mToolbar.getHeight ()). Jadi ... bilah alat diperluas sebagian "if (verticalOffset> -mToolbar.getHeight ())"
Mike
Jika ada yang bertanya-tanya di mana appBarLayout.getVerticalOffset()metodenya, Anda dapat memanggil appBarLayout.getY()untuk mengambil nilai yang sama dengan yang digunakan dalam callback.
Jarett Millard
Sayangnya Jarett Millard tidak benar. Tergantung pada konfigurasi fitSystemWindow Anda dan konfigurasi StatusBar (transparan), appBarLayout.getY()mungkin ituverticalOffset = appBarLayout.getY() + statusBarHeight
Capricorn
1
Adakah yang memperhatikan jika mAppBarLayout.addOnOffsetChangedListener (listener) dipanggil berulang kali meskipun kita tidak benar-benar berinteraksi dengan appbar? Atau itu adalah bug di tata letak / aplikasi saya tempat saya mengamati perilaku ini. Tolong bantu!
Rahul Shukla
16

Kode ini berhasil untuk saya

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
            }
        }
    });
SAI
sumber
Jawaban yang lebih baik daripada Nikola Despotoski
Vignesh Bala
Tampaknya bukan solusi yang dapat diandalkan. Saya mengujinya dan nilai pada perangkat saya adalah sebagai berikut: mCollapsingToolbarLayout.getHeight () = 1013, mToolbar.getHeight () = 224. Jadi menurut solusi Anda, verticalOffset dalam keadaan runtuh harus -789, namun sama dengan -693
Leo Droidcoder
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;
            }
        }
    });
}
terrakok
sumber
10

Anda bisa mendapatkan persentase alpha collapsingToolBar menggunakan di bawah ini:

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

Untuk Referensi: link

Naveen Kumar M
sumber
2
Ini adalah jawaban yang bagus karena memberikan offset yang dinormalisasi. Menurut pendapat saya, API seharusnya menyediakan ini secara langsung, bukan verticalOffsetjarak piksel.
dbm
5

Inilah solusi Kotlin . Tambahkan OnOffsetChangedListenerke AppBarLayout.

Metode A:

Tambahkan AppBarStateChangeListener.ktke proyek Anda:

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?
    )

}

Tambahkan pendengar ke 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 */ }
            }
        }
    }
)

Metode B:

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

Solusi ini berhasil untuk saya:

@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;
  }
}

Gunakan addOnOffsetChangedListener di AppBarLayout.

Nifhel
sumber
Bisakah Anda membagikan kode lengkap Anda? Apa itu State.EXPANDED dll?
Chetna
1

Jika Anda menggunakan CollapsingToolBarLayout, Anda dapat meletakkan ini

collapsingToolbar.setExpandedTitleColor(ContextCompat.getColor(activity, android.R.color.transparent));
collapsingToolbar.setTitle(title);
Irving Lóp
sumber
1

Kode ini berfungsi sempurna untuk saya. Anda dapat menggunakan skala persentase sesuka Anda

@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");
    }
}
Artur Gniewowski
sumber
0

Nilai offset Toolbar saya mendapatkan -582 saat runtuh, saat diperluas = 0 Jadi saya menemukan nilai dengan menyetel offsetvalue di Toast & ubah kode yang sesuai.

 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");
            }
        }
    });
Mazhar Ali
sumber