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 체크 아웃 IntDef
데이비드 Darias

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당신에게 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
그것은 나를 위해 작동하지 않습니다. 내가 홈 버튼을 활성화하고에 홈 버튼 HID 확장 할 OnCollapse
Maheshwar Ligade

9
도구 모음이 완전히 확장되면 verticalOffset 값이 0 인 것 같고 축소되는 동안 음수가됩니다. 툴바가 축소되면 verticalOffset은 툴바 높이의 음수 (-mToolbar.getHeight ())와 같습니다. 따라서 도구 모음이 부분적으로 확장되었습니다. "if (verticalOffset> -mToolbar.getHeight ())"
Mike

appBarLayout.getVerticalOffset()메서드가 어디에 있는지 궁금한 사람이 appBarLayout.getY()있는 경우 콜백에 사용 된 것과 동일한 값을 검색하도록 호출 할 수 있습니다 .
Jarett Millard

불행히도 Jarett Millard는 옳지 않습니다. 당신의 fitsSystemWindow 구성 및 상태 표시 구성 (투명)에 따라하면 appBarLayout.getY()그것은이있을 수 있습니다verticalOffset = appBarLayout.getY() + statusBarHeight
염소 자리

1
우리가 실제로 appbar와 상호 작용하지 않더라도 mAppBarLayout.addOnOffsetChangedListener (listener)가 반복적으로 호출되는 경우 누구든지 눈치 채 셨나요? 또는이 동작을 관찰하고있는 레이아웃 / 앱의 버그입니다. PLZ 도움!
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
            }
        }
    });

니콜라 Despotoski보다 더 나은 답변
인 Vignesh 발라

신뢰할 수있는 솔루션이 아닌 것 같습니다. 그러나 그것은 -693 같다, mCollapsingToolbarLayout.getHeight () = 1013, mToolbar.getHeight ()을 축소 된 상태에서 솔루션 verticalOffset에 따른 -789해야합니다 그래서 224 = : 나는 그것을 내 장치의 값은 다음과 같다 테스트
레오 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 알파 백분율을 얻을 수 있습니다.

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

다음은 Kotlin 솔루션입니다. 에를 추가 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;
  }
}

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를 얻습니다.

 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.