Android CollapsingToolbarLayout thu gọn Listener


106

Tôi đang sử dụng CollapsingToolBarLayoutcùng với AppBarLayoutCoordinatorLayout, và chúng đang hoạt động tốt hoàn toàn. Tôi đặt của tôi Toolbarlà cố định khi tôi cuộn lên, tôi muốn biết có cách nào để thay đổi văn bản tiêu đề của Thanh công cụ khi CollapsingToolBarLayoutnó bị thu gọn không.

Tóm lại, tôi muốn có hai tiêu đề khác nhau khi cuộn và khi mở rộng .

trước tiên xin cảm ơn tất cả các bạn

Câu trả lời:


150

Tôi chia sẻ cách triển khai đầy đủ, dựa trên mã @Frodio Beggins và @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);
}

Và sau đó bạn có thể sử dụng nó:

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

21
Đúng rồi. Nhưng xin đừng nói rằng sử dụng Proguard rằng enum sẽ được dịch sang một giá trị số nguyên.
rciovati

1
Tôi không biết điều đó. Thật tuyệt!
tim687,

2
Ngoài ra enums là một cách rất hay để đảm bảo an toàn cho kiểu. Bạn không thể có State.IMPLODED vì nó không tồn tại (trình biên dịch sẽ phàn nàn) nhưng với hằng số nguyên, bạn có thể sử dụng một giá trị mà trình biên dịch không biết là sai. Họ cũng giỏi như những người độc thân nhưng đó là một câu chuyện khác.
droppin_science

@droppin_science cho enums android kiểm tra IntDef
David Darias

1
@DavidDarias Cá nhân tôi thấy enums có một cách tiếp cận rõ ràng hơn nhiều ngay cả với chi phí của họ (bắt đầu tranh luận tại đây ... :-)
droppin_science.

95

Giải pháp này hoạt động hoàn hảo để tôi phát hiện thu AppBarLayoutgọn hoặc mở rộng.

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

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


            }
            else
            {
                //Expanded


            }
        }
    });

Được sử dụng addOnOffsetChangedListenertrên AppBarLayout.


36

Kết nối một OnOffsetChangedListenervới của bạn AppBarLayout. Khi verticalOffsetđạt đến 0 hoặc thấp hơn Toolbarchiều cao, điều đó có nghĩa là CollapsingToolbarLayout đã thu gọn, nếu không nó đang mở rộng hoặc mở rộng.

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
nó không làm việc cho tôi. OnCollapse tôi muốn bật nút home và Mở rộng giấu các nút home
Maheshwar Ligade

9
Các giá trị verticalOffset dường như bằng 0 khi thanh công cụ được mở rộng hoàn toàn, sau đó chuyển sang âm trong khi thu gọn. Khi thanh công cụ được thu gọn, verticalOffset bằng âm với chiều cao thanh công cụ (-mToolbar.getHeight ()). Vì vậy, ... thanh công cụ được mở rộng một phần "if (verticalOffset> -mToolbar.getHeight ())"
Mike

Trong trường hợp có ai đó đang thắc mắc appBarLayout.getVerticalOffset()phương thức ở đâu , bạn có thể gọi appBarLayout.getY()để lấy cùng một giá trị được sử dụng trong lệnh gọi lại.
Jarett Millard,

Thật không may, Jarett Millard không đúng. Tùy thuộc vào sự phù hợp của bạn cấu hình SystemWindow và cấu hình StatusBar (minh bạch), appBarLayout.getY()nó có thể là như vậyverticalOffset = appBarLayout.getY() + statusBarHeight
Ma Kết

1
Có ai nhận thấy nếu mAppBarLayout.addOnOffsetChangedListener (người nghe) được gọi nhiều lần ngay cả khi chúng tôi không thực sự tương tác với thanh ứng dụng? Hoặc đó là lỗi trong bố cục / ứng dụng của tôi, nơi tôi đang quan sát hành vi này. Làm ơn giúp tôi!
Rahul Shukla,

16

Mã này phù hợp với tôi

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

Câu trả lời tốt hơn so với Nikola Despotoski
Vignesh Bala

Có vẻ không phải là một giải pháp đáng tin cậy. Tôi đã thử nghiệm nó và các giá trị trên thiết bị của tôi như sau: mCollapsingToolbarLayout.getHeight () = 1013, mToolbar.getHeight () = 224. Vì vậy, theo giải pháp của bạn verticalOffset ở trạng thái thu gọn phải là -789, tuy nhiên nó bằng -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

Bạn có thể nhận được tỷ lệ phần trăm alpha của sậpToolBar bằng cách sử dụng bên dưới:

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

Để tham khảo: liên kết


2
Đây là một câu trả lời tuyệt vời vì nó cung cấp một phần bù được chuẩn hóa. Theo ý kiến ​​của tôi, API lẽ ra phải cung cấp điều này trực tiếp thay vì verticalOffsetkhoảng cách pixel.
dbm

5

Đây là một giải pháp Kotlin . Thêm một OnOffsetChangedListenervào AppBarLayout.

Phương pháp A:

Thêm AppBarStateChangeListener.ktvào dự án của bạn:

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

}

Thêm người nghe vào 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 */ }
            }
        }
    }
)

Phương pháp B:

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

3

Giải pháp này đang làm việc cho tôi:

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

Sử dụng addOnOffsetChangedListener trên AppBarLayout.


Bạn có thể chia sẻ mã hoàn chỉnh của bạn? State.EXPANDED vv là gì?
Chetna

1

Nếu bạn đang sử dụng CollapsingToolBarLayout, bạn có thể đặt nó

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

1

Mã này đang hoạt động hoàn hảo đối với tôi. Bạn có thể sử dụng tỷ lệ phần trăm Theo cách bạn muốn

@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

Giá trị bù đắp trên Thanh công cụ của tôi nhận -582 khi thu gọn, khi mở rộng = 0 Vì vậy, tôi tìm giá trị bằng cách đặt giá trị bù trong Toast & thay đổi mã cho phù hợp.

 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");
            }
        }
    });
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.