Слухач колапсу Android CollapsingToolbarLayout


106

Я використовую CollapsingToolBarLayoutпоряд з AppBarLayoutі CoordinatorLayout, і вони працюють нормально. Я встановлюю, Toolbarщо потрібно виправити під час прокрутки вгору, я хочу знати, чи є спосіб змінити текст заголовка на Панелі інструментів, коли CollapsingToolBarLayoutвін згортається.

Підгортаючи, я хочу два різних заголовки, коли прокручується і коли розгортається .

Дякую всім заздалегідь

Відповіді:


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, що enum буде переведений на ціле значення.
rciovati

1
Я цього не знав. Це чудово!
tim687

2
Також переписки - це дуже приємний спосіб забезпечення безпеки типу. Ви не можете мати State.IMPLODED, оскільки він не існує (компілятор скаржиться), але за допомогою констант Integer ви можете використовувати значення, яке компілятор не знає, що це неправильно. Вони також хороші як одинаки, але ось інша історія.
droppin_science

@droppin_science for android enums check out IntDef
David Darias

1
@DavidDarias Особисто я вважаю, що набагато чистіший підхід навіть з їхніми накладними витратами (
розпочніть

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до свого AppBarLayout. Коли verticalOffsetдосягає 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 я хочу ввімкнути кнопку "Додому", а на "Розгорнути" приховав кнопку "Додому"
Maheshwar Ligade

9
Здається, що значення вертикальних налаштувань дорівнюють нулю, коли панель інструментів повністю розгорнута, а потім переходить у мінус під час згортання. Коли панель інструментів згортається, вертикальний параметрOffset дорівнює від’ємній висоті панелі інструментів (-mToolbar.getHeight ()). Отже ... панель інструментів частково розгорнута "if (вертикальнийOffset> -mToolbar.getHeight ())"
Майк

Якщо когось цікавить, де цей appBarLayout.getVerticalOffset()метод, ви можете зателефонувати, appBarLayout.getY()щоб отримати те саме значення, яке використовується у зворотному дзвінку .
Джаретт Міллард

На жаль, Джарет Міллард не правий. Залежно від конфігурації вашого fitsSystemWindow та конфігурації StatusBar (прозоре), appBarLayout.getY()можливо, цеverticalOffset = appBarLayout.getY() + statusBarHeight
Козеріг

1
Хтось помічав, якщо mAppBarLayout.addOnOffsetChangedListener (слухач) викликається неодноразово, навіть якщо ми фактично не взаємодіємо з панеллю додатків? Або це помилка в моєму макеті / програмі, де я спостерігаю за такою поведінкою. Plz допомога!
Рахул Шукла

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

Краща відповідь, ніж Нікола Деспотоскі
Бала,

Здається, це не надійне рішення. Я перевірив його, і на моєму пристрої знаходяться такі значення: mCollapsingToolbarLayout.getHeight () = 1013, mToolbar.getHeight () = 224. Отже, згідно з вашим рішенням вертикальний параметрOffset у згорнутому стані повинен бути -789, однак він дорівнює -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;
            }
        }
    });
}

10

Ви можете отримати відсоток альфа-згортанняToolBar, використовуючи нижче:

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

5

Ось рішення Котліна . Додайте OnOffsetChangedListenerдо AppBarLayout.

Спосіб 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;
  }
}

Використовуйте addOnOffsetChangedListener на AppBarLayout.


Чи можете ви поділитися своїм повним кодом? Що таке State.EXPANDED тощо?
Четне

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 при згортанні, при розширенні = 0 Отже, я знаходжу значення, встановивши зміщення значення в тості та відповідно змінивши код.

 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");
            }
        }
    });
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.