首先来看一下设计图,看到这个图其实我相信很多人直接就想到用ViewPager,用ViewPager绝对没问题,可是我比较懒,总觉得这个用ViewPager做不够轻量,于是乎百度,发现RecyclerView有一个辅助类PagerSnapHelper可以实现这种功能,于是乎试了一下,可是好像做下来也并没有我想的那么比ViewPager轻量,废话不多说了,记录一下,请大神多多指正。
主要是利用PagerSnapHelper的功能实现,代码如下:
final PagerSnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
switch (newState) {
case RecyclerView.SCROLL_STATE_IDLE:
View viewIdle = snapHelper.findSnapView(linearLayoutManager);
if (viewIdle != null) {
int position = linearLayoutManager.getPosition(viewIdle);
updateIndicators(position);
}
break;
}
}
});
adapter = new RecyclerViewAdapter();
recyclerView.setAdapter(adapter);
RecyclerView本身的写发不变,只是这里这一点儿就能实现了,够简单了也是,可是有一个,有一些机型会把第二页的内容也显示到第一页,原因是有的机型会不加载itemView的顶层布局,所以顶层布局的match_parent不起作用,所以应该在adapter中给itemView动态设置宽度
public class ViewHolder extends RecyclerView.ViewHolder { private TextView textView; public ViewHolder(@NonNull View itemView) { super(itemView); float[] size = getDeviceDisplaySize(getContext()); itemView.setMinimumWidth((int) size[0]); textView = itemView.findViewById(R.id.textView); } }
因为我这里的是公告,childView只是一个可以上下滑动的TextView,这样就有了不同方向的滑动冲突,可以使用外部拦截的办法处理滑动冲突,自定义RecyclerView重写onInterceptTouchEvent 做下处理,代码如下:
@Override public boolean onInterceptTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: startX = (int) event.getX(); startY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: //如果左右滑动距离大于上下滑动距离,说明是RecyclerView在横向滑动,拦截事件自己处理, //否则就是TextView在上下滑动,就不拦截,交给TextView自己处理 int dx = (int) (event.getX() - startX); int dy = (int) (event.getY() - startY); if (Math.abs(dx) > Math.abs(dy)) { return true; } else { return false; } } return super.onInterceptTouchEvent(event); }
好了,就这样完了,完整代码如下:
public class NoticeDialog extends Dialog implements View.OnClickListener { private CustomerRecyclerView recyclerView; private LinearLayout indicatorContainer; private RecyclerViewAdapter adapter; public NoticeDialog(@NonNull Context context) { this(context, R.style.dialog); } public NoticeDialog(Context context, int themeResId) { super(context, themeResId); Window dialogWindow = getWindow(); WindowManager.LayoutParams params = dialogWindow.getAttributes(); params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.height = WindowManager.LayoutParams.WRAP_CONTENT; dialogWindow.setGravity(Gravity.CENTER); dialogWindow.setAttributes(params); setCanceledOnTouchOutside(false); initView(); } private void initView() { View view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_notice, null, false); setContentView(view); view.findViewById(R.id.btn_close).setOnClickListener(this); recyclerView = view.findViewById(R.id.recyclerView); indicatorContainer = view.findViewById(R.id.indicator_container); final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext()); linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); recyclerView.setLayoutManager(linearLayoutManager); final PagerSnapHelper snapHelper = new PagerSnapHelper(); snapHelper.attachToRecyclerView(recyclerView); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); switch (newState) { case RecyclerView.SCROLL_STATE_IDLE: View viewIdle = snapHelper.findSnapView(linearLayoutManager); if (viewIdle != null) { int position = linearLayoutManager.getPosition(viewIdle); updateIndicators(position); } break; } } }); adapter = new RecyclerViewAdapter(); recyclerView.setAdapter(adapter); } /** * 更新到当前指示器 * * @param position */ private void updateIndicators(int position) { for (int i = 0; i < indicatorContainer.getChildCount(); i++) { View childView = indicatorContainer.getChildAt(i); childView.setBackground(position == i ? getContext().getDrawable(R.drawable.shape_indicator_blue) : getContext().getDrawable(R.drawable.shape_indicator_gray)); } } public void setNotices(ListmDataSources) { adapter.setData(mDataSources); //当只有一页的时候不显示指示器 if (mDataSources.size() <= 1) { return; } initIndicator(mDataSources); } /** * 添加滑动指示器 * * @param mDataSources */ private void initIndicator(List mDataSources) { indicatorContainer.removeAllViews(); for (int i = 0; i < mDataSources.size(); i++) { View indicatorView = new View(getContext()); indicatorView.setBackground(getContext().getDrawable(R.drawable.shape_indicator_gray)); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(DensityUtils.dp2px(getContext(), 6), DensityUtils.dp2px(getContext(), 6)); if (i != 0) layoutParams.leftMargin = DensityUtils.dp2px(getContext(), 8); indicatorView.setLayoutParams(layoutParams); indicatorContainer.addView(indicatorView); } updateIndicators(0); } @Override public void onClick(View v) { dismiss(); } private class RecyclerViewAdapter extends RecyclerView.Adapter { private List mDataSources = new ArrayList<>(); @NonNull @Override public RecyclerViewAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { View view = LayoutInflater.from(getContext()).inflate(R.layout.customer_text_view, viewGroup, false); return new RecyclerViewAdapter.ViewHolder(view); } @Override public void onBindViewHolder(@NonNull RecyclerViewAdapter.ViewHolder viewHolder, int i) { ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT); viewHolder.textView.setLayoutParams(layoutParams); viewHolder.textView.setText(Html.fromHtml(mDataSources.get(i).context)); viewHolder.textView.setMovementMethod(ScrollingMovementMethod.getInstance()); } @Override public int getItemCount() { return mDataSources.size(); } public class ViewHolder extends RecyclerView.ViewHolder { private TextView textView; public ViewHolder(@NonNull View itemView) { super(itemView); float[] size = getDeviceDisplaySize(getContext()); itemView.setMinimumWidth((int) size[0]); textView = itemView.findViewById(R.id.textView); } } public void setData(List noticeList) { this.mDataSources.clear(); this.mDataSources.addAll(noticeList); notifyDataSetChanged(); } } public static float[] getDeviceDisplaySize(Context context) { Resources resources = context.getResources(); DisplayMetrics dm = resources.getDisplayMetrics(); int width = dm.widthPixels; int height = dm.heightPixels; float[] size = new float[2]; size[0] = width; size[1] = height; return size; } } public class CustomerRecyclerView extends RecyclerView { private int startX, startY; public CustomerRecyclerView(@NonNull Context context) { this(context, null); } public CustomerRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public CustomerRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: startX = (int) event.getX(); startY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: //如果左右滑动距离大于上下滑动距离,说明是RecyclerView在横向滑动, //拦截事件自己处理,否则就是TextView在上下滑动,就不拦截,交给TextView自己处理 int dx = (int) (event.getX() - startX); int dy = (int) (event.getY() - startY); if (Math.abs(dx) > Math.abs(dy)) { return true; } else { return false; } } return super.onInterceptTouchEvent(event); } }