Android CollapsingToolbarLayout Collapse Listener


106

Ben kullanıyorum CollapsingToolBarLayoutile birlikte AppBarLayoutve CoordinatorLayoutve onlar tamamen İnce çalışıyoruz. ToolbarYukarı kaydırdığımda sabitlenecek şekilde ayarlıyorum CollapsingToolBarLayout, daraltıldığında Araç Çubuğunun başlık metnini değiştirmenin bir yolu olup olmadığını öğrenmek istiyorum .

Tamamlayan iki farklı istiyorum başlıkları zaman kaydırılan ve ne zaman genişletildi .

Şimdiden teşekkür ederim

Yanıtlar:


150

@Frodio Beggins ve @Nifhel koduna dayalı olarak tam uygulamayı paylaşıyorum:

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

Ve sonra onu kullanabilirsiniz:

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

21
Bu doğru. Ama lütfen Proguard kullanıldığında bu numaralamanın bir tamsayı değerine çevrileceğini unutmayın.
rciovati

1
Bunu bilmiyordum. Bu harika!
tim687

2
Ayrıca numaralandırmalar, tür güvenliğini sağlamanın çok güzel bir yoludur. State.IMPLODED olamaz çünkü varolmaz (derleyici şikayet eder), ancak Tamsayı sabitleri ile derleyicinin yanlış bir fikrinin olmadığı bir değer kullanabilirsiniz. Aynı zamanda bekarlar kadar iyiler ama bu başka bir hikaye.
droppin_science

@droppin_science for android enums IntDef'e
David Darias

1
@DavidDarias Şahsen enumları ek yükleriyle bile çok daha temiz bir yaklaşım buluyorum (tartışmaya buradan başlayın ... :-)
droppin_science

95

Bu çözüm, AppBarLayoutçökmüş veya genişlemiş durumları algılamak için mükemmel çalışıyor .

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

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


            }
            else
            {
                //Expanded


            }
        }
    });

Kullanılan addOnOffsetChangedListenerüzerinde AppBarLayout.


36

Bir Hook OnOffsetChangedListeneradresinden Müşteri AppBarLayout. Tüm verticalOffsetulaşır, 0 veya daha az Toolbaryükseklikte, bu CollapsingToolbarLayout çöktüğü anlamına gelir, aksi takdirde genişleyen ya da genişletilir.

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
benim için çalışmıyor. OnCollapse Ana Sayfa düğmesini etkinleştirmek istiyorum ve Genişlet seçeneğinde ana düğmeyi gizlemek istiyorum
Maheshwar Ligade

9
DikeyOffset değerleri, araç çubuğu tam olarak genişletildiğinde sıfır olarak görünür ve ardından daraltılırken negatif olur. Araç çubuğu daraltıldığında, verticalOffset, araç çubuğu yüksekliğinin negatifine eşittir (-mToolbar.getHeight ()). Yani ... araç çubuğu kısmen genişletildi "if (verticalOffset> -mToolbar.getHeight ())"
Mike

Herhangi birinin appBarLayout.getVerticalOffset()yöntemin nerede olduğunu merak etmesi durumunda , appBarLayout.getY()geri aramada kullanılan aynı değeri almak için arama yapabilirsiniz.
Jarett Millard

Maalesef Jarett Millard haklı değil. Uygunluk sisteminize bağlı olarakSystemWindow yapılandırmanıza ve StatusBar yapılandırmanıza (şeffaf) bağlı olarak şunlar appBarLayout.getY()olabilirverticalOffset = appBarLayout.getY() + statusBarHeight
Oğlak

1
MAppBarLayout.addOnOffsetChangedListener (dinleyici) appbar ile gerçekten etkileşimde olmasak bile tekrar tekrar çağrıldığını kimse fark etti mi? Veya bu davranışı gözlemlediğim düzenimde / uygulamada bir hata. Plz yardım et!
Rahul Shukla

16

Bu kod benim için çalıştı

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'den daha iyi cevap
Vignesh Bala

Görünüşe göre güvenilir bir çözüm değil. Test ettim ve cihazımdaki değerler şunlar: mCollapsingToolbarLayout.getHeight () = 1013, mToolbar.getHeight () = 224. Dolayısıyla, çözümünüze göre, daraltılmış durumda verticalOffset -789 olmalıdır, ancak -693'e eşittir
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;
            }
        }
    });
}

10

CollapsingToolBar alfa yüzdesini aşağıdakileri kullanarak alabilirsiniz:

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

Referans için: link


2
Bu, normalleştirilmiş bir ofset sağladığı için harika bir cevaptır. Bana göre, API'nin bunu verticalOffsetpiksel mesafesi yerine doğrudan sağlaması gerekirdi .
dbm

5

İşte bir Kotlin çözümü. Bir ekleme OnOffsetChangedListeneriçin AppBarLayout.

Yöntem A:

AppBarStateChangeListener.ktProjenize ekleyin :

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

}

Dinleyiciyi şuraya ekleyin 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 */ }
            }
        }
    }
)

Yöntem B:

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

3

Bu çözüm benim için çalışıyor:

@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'ta addOnOffsetChangedListener kullanın.


Kodunuzun tamamını paylaşabilir misiniz? State.EXPANDED vb. Nedir?
Chetna

1

CollapsingToolBarLayout kullanıyorsanız, bunu koyabilirsiniz

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

1

Bu kod benim için mükemmel çalışıyor. Yüzde ölçeğini kullanabilirsiniz.

@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

Araç Çubuğu ofset değerim daraldığında -582 alıyor, genişlemede = 0 Bu yüzden Toast'ta ofset değerini ayarlayarak değeri buluyorum ve kodu buna göre değiştiriyorum.

 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");
            }
        }
    });
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.