Recyclerview 自定義 Scroll Bar

 

如圖所示, 完全自定義的ScrollBar, 並且實現了拖動功能

佈局如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.test.demoone.scrollbar.ScrollBarActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <TextView
        android:id="@+id/toastView"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:textColor="@color/colorAccent"
        android:textSize="50sp" />

    <View
        android:id="@+id/scrollBar"
        android:layout_width="50dp"
        android:layout_height="100dp"
        android:layout_alignParentRight="true"
        android:background="@color/colorAccent" />

</RelativeLayout>

邏輯代碼:

public class ScrollBarActivity extends AppCompatActivity {

    private RecyclerView recyclerView;
    private Context context;
    private View bar;
    private float barTouchedLastY;
    private TextView toastView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scroll_bar);

        context = this;

        recyclerView = findViewById(R.id.recyclerView);
        LinearLayoutManager layoutManager = new LinearLayoutManager(context);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setAdapter(new MyAdapter());

        bar = findViewById(R.id.scrollBar);
        toastView = findViewById(R.id.toastView);

        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);

                changeBarPosition();
            }
        });


        bar.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        barTouchedLastY = event.getRawY();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        float dY = event.getRawY() - barTouchedLastY;
                        moveListView(dY);
                        showToastView();
                        barTouchedLastY = event.getRawY();

                        //上下邊界值
                        if (bar.getY() + dY + bar.getMeasuredHeight() >= recyclerView.getHeight()) {
                            //到底了
                            bar.setY(recyclerView.getHeight() - bar.getMeasuredHeight());
                        } else if (bar.getY() + dY <= 0) {
                            //到頂了
                            bar.setY(0);
                        } else {
                            bar.setY(bar.getY() + dY);
                        }
                        break;
                    case MotionEvent.ACTION_CANCEL:
                    case MotionEvent.ACTION_UP:
                        break;
                }

                return true;
            }
        });
    }

    private void showToastView() {
        LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        int position = layoutManager.findFirstVisibleItemPosition();
        toastView.setText("" + position);
    }

    private void moveListView(float dY) {

        //列表總長度
        int verticalScrollRange = recyclerView.computeVerticalScrollRange();
        //可見區域長度
        int verticalScrollExtent = recyclerView.computeVerticalScrollExtent();
        //向上滑動的大概距離
        int verticalScrollOffset = recyclerView.computeVerticalScrollOffset();

        int listMovableHeight = verticalScrollRange - verticalScrollExtent;
        int barMovableHeight = verticalScrollExtent - bar.getHeight();

        recyclerView.scrollBy(0, (int) (1.0f * listMovableHeight / barMovableHeight * dY));
    }

    private void changeBarPosition() {
        //列表總長度
        int verticalScrollRange = recyclerView.computeVerticalScrollRange();
        //可見區域長度
        int verticalScrollExtent = recyclerView.computeVerticalScrollExtent();
        //向上滑動的大概距離
        int verticalScrollOffset = recyclerView.computeVerticalScrollOffset();

        int listMovableHeight = verticalScrollRange - verticalScrollExtent;
        int barMovableHeight = verticalScrollExtent - bar.getHeight();
        bar.setY(1.0f * barMovableHeight / listMovableHeight * verticalScrollOffset);
    }

    public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

        @NonNull
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

            View itemView = LayoutInflater.from(context).inflate(R.layout.item_view, parent, false);

            return new MyViewHolder(itemView);
        }

        @Override
        public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
            holder = (MyViewHolder) holder;
            ((MyViewHolder) holder).textView.setText("Hello Position " + position);
        }

        @Override
        public int getItemCount() {
            return 100;
        }

        class MyViewHolder extends RecyclerView.ViewHolder {

            public TextView textView;

            public MyViewHolder(View itemView) {
                super(itemView);

                textView = itemView.findViewById(R.id.textView);
            }
        }
    }
}

關鍵代碼就只有兩個方法: moveListView 和 changeBarPosition,

爲了粘貼方便, 隨便寫的Adapter也粘出來了, 還請不要吐槽...

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章