recyclerview+viewpager实现多分类fragment界面 仿京东分类界面
Android : ViewPager+RecyclerView的联动效果
recycleView实现item点击更改该item颜色,其它item颜色变回
教你如何自定义实现可上下滑动的ViewPager
1、自定义ViewPager(VerticalViewPager)
public class VerticalViewPager extends ViewPager {
public VerticalViewPager(@NonNull Context context) {
super(context);
init();
}
public VerticalViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
// 最重要的设置,将viewpager翻转
setPageTransformer(true, new VerticalPageTransformer());
// 设置去掉滑到最左或最右时的滑动效果
setOverScrollMode(OVER_SCROLL_NEVER);
}
private class VerticalPageTransformer implements ViewPager.PageTransformer {
@Override
public void transformPage(@NonNull View view, float position) {
if (position < -1) { // [-Infinity,-1)
// 当前页的上一页
view.setAlpha(0);
} else if (position <= 1) { // [-1,1]
view.setAlpha(1);
// 抵消默认幻灯片过渡
view.setTranslationX(view.getWidth() * -position);
// 设置从上滑动到Y位置
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);
} else { // (1,+Infinity]
// 当前页的下一页
view.setAlpha(0);
}
}
}
/**
* 交换触摸事件的 X 和 Y 坐标
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();
float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;
ev.setLocation(newX, newY);
return ev;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev);
return intercepted; //为所有子视图返回触摸的原始坐标
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
return super.onTouchEvent(swapXY(ev));
}
}
2、使用
xml
代码
public class SortFragment extends BaseFragment implements SortView {
@BindView(R.id.recyclerview)
RecyclerView recyclerview;
@BindView(R.id.viewpager)
VerticalViewPager viewpager;
private SortRvAdapter mSortRvAdapter;
private ViewPagerAdapter mViewPagerAdapter;
public SortFragment() {
// Required empty public constructor
}
@Override
protected SortPresenter initPresenter() {
return new SortPresenter();
}
@Override
protected int initLayoutId() {
return R.layout.fragment_sort;
}
@Override
protected void initView() {
super.initView();
// 初始化数据
ArrayList strings = new ArrayList<>();
strings.add("服装");
strings.add("餐厨");
strings.add("配件");
strings.add("居家");
strings.add("洗护");
strings.add("婴童");
strings.add("杂货");
strings.add("饮食");
// 布局管理器
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerview.setLayoutManager(layoutManager);
// 初始化适配器
mSortRvAdapter = new SortRvAdapter(strings, getActivity());
// 绑定适配器
recyclerview.setAdapter(mSortRvAdapter);
// 一进来默认选中第一条
mSortRvAdapter.setBg(0);
// 适配器监听回调
mSortRvAdapter.setSendDataToFragment(new SortRvAdapter.SendDataToFragment() {
@Override
public void sendData(int position) {
viewpager.setCurrentItem(position);
}
});
// 初始化 ViewPager 的数据
ArrayList fragments = new ArrayList<>();
for (int i = 0; i < strings.size(); i++) {
if (i%2==0){
fragments.add(new ClothesFragment());
}else {
fragments.add(new FurnitureFragment());
}
}
// 初始化 ViewPager 的适配器 并 绑定适配器
mViewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager(), fragments);
viewpager.setAdapter(mViewPagerAdapter);
// ViewPager 的滑动监听方法
viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int i, float v, int i1) {
}
@Override
public void onPageSelected(int i) {
recyclerview.smoothScrollToPosition(i);
// 改变 RecyclerView 的选中条目
mSortRvAdapter.setBg(i);
}
@Override
public void onPageScrollStateChanged(int i) {
}
});
}
}
RecyclerView的适配器
public class SortRvAdapter extends RecyclerView.Adapter {
private ArrayList strings;
Context mContext;
// 控件是否被点击,默认为 false,如果被点击,改变值,控件根据值改变自身颜色
private List isClicks;
public SortRvAdapter(ArrayList strings, Context context) {
this.strings = strings;
mContext = context;
isClicks = new ArrayList<>();
for (int i = 0; i < strings.size(); i++) {
isClicks.add(false);
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(mContext).inflate(R.layout.item_sort_rv, null);
// 这里记录一个问题,有时会遇到 item 条目的布局很简单,就是一个 TextView,宽度是占满全屏,
// 但是在 RecyclerView 中 item 条目的宽度却只是包裹自身,这时在 RecyclerView 的 Adapter 中
// 获取 item 条目布局的时候可以用下面这个方法:
// View view = LayoutInflater.from(mContext).inflate(R.layout.item_sort_rv, viewGroup, false);
// LayoutInflater 的 inflate 方法有多个重载的方法,常用的是下面三个参数的方法。
// public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) {
// return inflate(resource, root, root != null);
// }
// resource:要解析的 xml 布局文件 Id。
// root:表示根布局。
// attachToRoot:是否要添加到父布局 root 中。
// 1、当 attachToRoot == true 且 root != null 时,新解析出来的 View 会被 add 到 root 中去,然后将 root 作为结果返回。
// 2、当 attachToRoot == false 且 root != null 时,新解析的 View 会直接作为结果返回,而且 root 会为新解析的 View 生成 LayoutParams 并设置到该 View 中去。
// 3、当 attachToRoot == false 且 root == null 时,新解析的 View 会直接作为结果返回。
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final ViewHolder viewHolder, final int i) {
String s = strings.get(i);
// 判断是否被选中 并 设置不同的背景和字体颜色
if (isClicks.get(i)){
viewHolder.name.setTextColor(mContext.getResources().getColor(R.color.c_2ab795));
viewHolder.ll.setBackgroundColor(mContext.getResources().getColor(R.color.white));
}else {
viewHolder.name.setTextColor(mContext.getResources().getColor(R.color.c_000000));
viewHolder.ll.setBackgroundColor(mContext.getResources().getColor(R.color.c_f2f2f2));
}
viewHolder.name.setText(s);
// 条目的点击监听
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mSendDataToFragment!=null){
mSendDataToFragment.sendData(i);
for (int j = 0; j < isClicks.size(); j++) {
isClicks.set(j,false);
}
isClicks.set(i,true);
notifyDataSetChanged();
}
}
});
}
@Override
public int getItemCount() {
return strings.size();
}
// 主界面传给适配器被选中条目的下标
public void setBg(int i) {
for (int j = 0; j < isClicks.size(); j++) {
isClicks.set(j,false);
}
isClicks.set(i,true);
notifyDataSetChanged();
}
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView name;
private LinearLayout ll;
public ViewHolder(@NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.name);
ll = itemView.findViewById(R.id.ll);
}
}
SendDataToFragment mSendDataToFragment;
public void setSendDataToFragment(SendDataToFragment sendDataToFragment) {
mSendDataToFragment = sendDataToFragment;
}
public interface SendDataToFragment{
void sendData(int position);
}
}
ViewPager的适配器
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import java.util.List;
public class ViewPagerAdapter extends FragmentPagerAdapter {
List list;
public ViewPagerAdapter(@NonNull FragmentManager fm) {
super(fm);
}
public ViewPagerAdapter(@NonNull FragmentManager fm, List list) {
super(fm);
this.list = list;
}
@NonNull
@Override
public Fragment getItem(int position) {
return list.get(position);
}
@Override
public int getCount() {
return list.size();
}
}
适配器的布局文件和 ViewPager 中的 Fragment 自己写就可以了
这种方法没有考虑 ViewPager 中的 Fragment 中的 RecyclerView 的数据超过屏幕的高度下的情况,如有问题,请自行百度解决