Ẩn/Hiện thanh toolbar khi scroll trên recycle view

Tạo recycle view

Để control được việc ẩn / hiện của toolbar hoặc bất kì một view nào trong quá trình scroll recycleview thì việc đầu tiên chúng ta cần làm là tạo một recycle view và một thanh toolbar đơn giản. Đầu tiên là việc import thư viện:

.....
  dataBinding {
        enabled = true
    }
.....

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.2.0'
    compile 'com.android.support:recyclerview-v7:25.1.1'
    compile 'com.android.support:cardview-v7:25.2.0'
    testCompile 'junit:junit:4.12'
}

Tạo adapter cho recycleview Adapter.java

public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> {
    private String[] mItems;
    private LayoutInflater mLayoutInflater;

    public Adapter(String[] items) {
        mItems = items;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (mLayoutInflater == null) mLayoutInflater = LayoutInflater.from(parent.getContext());
        ItemRecycleViewBinding binding =
            ItemRecycleViewBinding.inflate(mLayoutInflater, parent, false);
        return new Adapter.ViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        holder.bind(position);
    }

    @Override
    public int getItemCount() {
        return mItems == null ? 0 : mItems.length;
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        private ItemRecycleViewBinding mBinding;

        public ViewHolder(ItemRecycleViewBinding binding) {
            super(binding.getRoot());
            mBinding = binding;
        }

        private void bind(int pos) {
            mBinding.setText(mItems[pos]);
            mBinding.executePendingBindings();
        }
    }
}

Custom việc init Recycleview bằng databinding BindingUtil.java

public class BindingUtil {
    @BindingAdapter({"adapter", "context"})
    public static void initRecycleview(RecyclerView recyclerView, Adapter adapter,
                                       AppCompatActivity activity) {
        if (recyclerView == null || adapter == null) return;
        recyclerView.setLayoutManager(new LinearLayoutManager(activity));
        recyclerView.setAdapter(adapter);
    }
}

Tạo layout cho MainActivity.java activity_main.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:bind="http://schemas.android.com/apk/res-auto">
        
    <data>
    
        <variable
            name="activity"
            type="beemusic.framgia.com.controlscrollrecycleview.MainActivity"/>
    </data>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            bind:adapter="@{activity.adapter}"
            bind:context="@{activity}"/>
            
        <android.support.v7.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/colorPrimary"
            android:title="@string/app_name"/>
            
    </FrameLayout>
</layout>

Tạo layout item_recycle_view.xml

<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

        <variable
            name="text"
            type="String"/>
    </data>

    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="8dp"
        app:cardCornerRadius="4dp"
        app:cardElevation="@dimen/dp_2">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="?attr/listPreferredItemHeight"
            android:gravity="center"
            android:text="@{text}"/>
    </android.support.v7.widget.CardView>
</layout>

Control việc ẩn/ hiện toolbar

Để control được việc ẩn hiện thanh toolbar, ta viết lại lớp RecyclerView.OnScrollListener ControlScrollListener.java

public abstract class ControlScrollListener extends RecyclerView.OnScrollListener {
    private static final int HIDE_THRESHOLD = 20;
    private int mScrolledDistance = 0;
    private boolean mVisible = true;

    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        int firstVisibleItem =
            ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
        //show views if first item is first visible position and views are hidden
        if (firstVisibleItem == 0) {
            if (!mVisible) {
                onShow();
                mVisible = true;
            }
        } else {
            if (mScrolledDistance > HIDE_THRESHOLD && mVisible) {
                onHide();
                mVisible = false;
                mScrolledDistance = 0;
            } else if (mScrolledDistance < -HIDE_THRESHOLD && !mVisible) {
                onShow();
                mVisible = true;
                mScrolledDistance = 0;
            }
        }
        if ((mVisible && dy > 0) || (!mVisible && dy < 0)) {
            mScrolledDistance += dy;
        }
    }

    public abstract void onHide();
    public abstract void onShow();
}

Bây giờ, trong file BindingUtil.java, chúng ta sẽ tạo callback để control bằng việc khởi tạo một đối tượng ControlScrollListener thực sự cho recycleview.

 @BindingAdapter({"adapter", "context", "toolbar"})
    public static void initRecycleview(RecyclerView recyclerView, Adapter adapter,
                                       AppCompatActivity activity, final Toolbar toolbar) {
        if (recyclerView == null || adapter == null) return;
        recyclerView.setLayoutManager(new LinearLayoutManager(activity));
        recyclerView.setAdapter(adapter);
        recyclerView.setOnScrollListener(new ControlScrollListener() {
            @Override
            public void onHide() {
                toolbar.animate().translationY(-toolbar.getHeight())
                    .setInterpolator(new AccelerateInterpolator(2));
            }

            @Override
            public void onShow() {
                toolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator(2));
            }
        });
    }

Vậy là chúng ta đã hoàn tất project. Các bạn có thể tham khảo source code tại đây