您的位置:首页 > 其它

RecycleView实现横向带指示器翻页滑动,一行两列自定义布局

2017-09-18 14:03 549 查看
1AutoGridLayoutManager

2PageIndicatorView

3PageRecyclerView

4使用

首先看需求效果



在acvitity中有一个控件,需要实现这种分页效果,还要指示器,并且每页的两列不能太分散,使用GridView就很不好实现,这里用RecycleView展示,先看成型后需要用到的结构(需要用到哪些自定义的东西)



自己在Java下建一个新的包,需要这三个自定义的东西,一个用来展示GridView布局样式自定义的GridViewLayoutManger,一个指示器的自定义控件,第三个就是自定义RecleView,实现翻页效果,另外还有一个工具类,实现获取屏幕尺寸,并且让px和dp相互转换的功能,网上有很多,没有几行代码,之前也专门写过,不再赘述,接下来就看着三个自定义东西怎么写

1、AutoGridLayoutManager

package inditor.recycleview.horizontal;

import android.content.Context;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;

/**
* Created by YTF on 2017/9/16.
*/

public class AutoGridLayoutManager extends GridLayoutManager {
private int measuredWidth = 0;
private int measuredHeight = 0;

public AutoGridLayoutManager(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}

public AutoGridLayoutManager(Context context, int spanCount) {
super(context, spanCount);
}

public AutoGridLayoutManager(Context context, int spanCount,
int orientation, boolean reverseLayout) {
super(context, spanCount, orientation, reverseLayout);
}

@Override
public void onMeasure(RecyclerView.Recycler recycler,
RecyclerView.State state, int widthSpec, int heightSpec) {
if (measuredHeight <= 0) {
int count = state.getItemCount();
if(count>0){
View view = recycler.getViewForPosition(0);
if (view != null) {
measureChild(view, widthSpec, heightSpec);
measuredWidth = View.MeasureSpec.getSize(widthSpec);
measuredHeight = view.getMeasuredHeight() * getSpanCount();
}
}

}
setMeasuredDimension(measuredWidth, measuredHeight);
}

}


2、PageIndicatorView

package inditor.recycleview.horizontal;

import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.LinearLayout;

import com.lab.web.entity.UtilDynamicWidth;

import java.util.ArrayList;
import java.util.List;

/**
* Created by shichaohui on 2015/7/10 0010.
* <p/>
* 页码指示器类,获得此类实例后,可通过{@link PageIndicatorView#initIndicator(int)}方法初始化指示器
* </P>
*/

public class PageIndicatorView extends LinearLayout {

private Context mContext = null;
private int dotSize = 10; // 指示器的大小(dp)
private int margins = 10; // 指示器间距(dp)
private List<View> indicatorViews = null; // 存放指示器

public PageIndicatorView(Context context) {
this(context, null);
}

public PageIndicatorView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public PageIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}

private void init(Context context) {
this.mContext = context;

setGravity(Gravity.CENTER);
setOrientation(HORIZONTAL);

dotSize = UtilDynamicWidth.dip2px(context, dotSize);
margins = UtilDynamicWidth.dip2px(context, margins);
}

/**
* 初始化指示器,默认选中第一页
*
* @param count 指示器数量,即页数
*/
public void initIndicator(int count) {

if (indicatorViews == null) {
indicatorViews = new ArrayList<>();
} else {
indicatorViews.clear();
removeAllViews();
}
View view;
LayoutParams params = new LayoutParams(dotSize, dotSize);
params.setMargins(margins, margins, margins, margins);
for (int i = 0; i < count; i++) {
view = new View(mContext);
view.setBackgroundResource(android.R.drawable.presence_invisible);
addView(view, params);
indicatorViews.add(view);
}
if (indicatorViews.size() > 0) {
indicatorViews.get(0).setBackgroundResource(android.R.drawable.presence_online);
}
}

/**
* 设置选中页
*
* @param selected 页下标,从0开始
*/
public void setSelectedPage(int selected) {
for (int i = 0; i < indicatorViews.size(); i++) {
if (i == selected) {
indicatorViews.get(i).setBackgroundResource(android.R.drawable.presence_online);
} else {
indicatorViews.get(i).setBackgroundResource(android.R.drawable.presence_invisible);
}
}
}

}


3、PageRecyclerView

package inditor.recycleview.horizontal;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;

import com.lab.web.entity.UtilDynamicWidth;

import java.util.List;
import java.util.Map;

/**
* Created by shichaohui on 2015/7/9 0009.
* <p>
* 横向分页的GridView效果
* </p>
* <p>
* 默认为1行,每页3列,如果要自定义行数和列数,请在调用{@link PageRecyclerView#setAdapter(Adapter)}方法前调用
* {@link PageRecyclerView#setPageSize(int, int)}方法自定义行数
* </p>
*/
public class PageRecyclerView extends RecyclerView {

private Context mContext = null;

private PageAdapter myAdapter = null;

private int shortestDistance; // 超过此距离的滑动才有效
private float slideDistance = 0; // 滑动的距离
private float scrollX = 0; // X轴当前的位置

private int spanRow = 1; // 行数
private int spanColumn = 2; // 每页列数
private int totalPage = 0; // 总页数
private int currentPage = 1; // 当前页

private int pageMargin = 0; // 页间距

private PageIndicatorView mIndicatorView = null; // 指示器布局

private int realPosition = 0; // 真正的位置(从上到下从左到右的排列方式变换成从左到右从上到下的排列方式后的位置)

/*
* 0: 停止滚动且手指移开; 1: 开始滚动; 2: 手指做了抛的动作(手指离开屏幕前,用力滑了一下)
*/
private int scrollState = 0; // 滚动状态

public PageRecyclerView(Context context) {
this(context, null);
}

public PageRecyclerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public PageRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
defaultInit(context);
}

// 默认初始化
private void defaultInit(Context context) {
this.mContext = context;
setLayoutManager(new AutoGridLayoutManager(
mContext, spanRow, AutoGridLayoutManager.HORIZONTAL, false));
setOverScrollMode(OVER_SCROLL_NEVER);
}

/**
* 设置行数和每页列数
*
* @param spanRow    行数,<=0表示使用默认的行数
* @param spanColumn 每页列数,<=0表示使用默认每页列数
*/
public void setPageSize(int spanRow, int spanColumn) {
this.spanRow = spanRow <= 0 ? this.spanRow : spanRow;
this.spanColumn = spanColumn <= 0 ? this.spanColumn : spanColumn;
setLayoutManager(new AutoGridLayoutManager(
mContext, this.spanRow, AutoGridLayoutManager.HORIZONTAL, false));
}

/**
* 设置页间距
*
* @param pageMargin 间距(px)
*/
public void setPageMargin(int pageMargin) {
this.pageMargin = pageMargin;
}

/**
* 设置指示器
*
* @param indicatorView 指示器布局
*/
public void setIndicator(PageIndicatorView indicatorView) {
this.mIndicatorView = indicatorView;
}

@Override
protected void onMeasure(int widthSpec, int heightSpec) {
super.onMeasure(widthSpec, heightSpec);
shortestDistance = getMeasuredWidth() / 3;
}

@Override
public void setAdapter(Adapter adapter) {
super.setAdapter(adapter);
this.myAdapter = (PageAdapter) adapter;
update();
}

// 更新页码指示器和相关数据
private void update() {
// 计算总页数
int temp = ((int) Math.ceil(myAdapter.dataList.size() / (double) (spanRow * spanColumn)));
if (temp != totalPage) {
mIndicatorView.initIndicator(temp);
// 页码减少且当前页为最后一页
if (temp < totalPage && currentPage == totalPage) {
currentPage = temp;
// 执行滚动
smoothScrollBy(-getWidth(), 0);
}
mIndicatorView.setSelectedPage(currentPage - 1);
totalPage = temp;
}
}

@Override
public void onScrollStateChanged(int state) {
switch (state) {
case 2:
scrollState = 2;
break;
case 1:
scrollState = 1;
break;
case 0:
if (slideDistance == 0) {
break;
}
scrollState = 0;
if (slideDistance < 0) { // 上页
currentPage = (int) Math.ceil(scrollX / getWidth());
if (currentPage * getWidth() - scrollX < shortestDistance) {
currentPage += 1;
}
} else { // 下页
currentPage = (int) Math.ceil(scrollX / getWidth()) + 1;
if (currentPage <= totalPage) {
if (scrollX - (currentPage - 2) * getWidth() < shortestDistance) {
// 如果这一页滑出距离不足,则定位到前一页
currentPage -= 1;
}
} else {
currentPage = totalPage;
}
}
// 执行自动滚动
smoothScrollBy((int) ((currentPage - 1) * getWidth() - scrollX), 0);
// 修改指示器选中项
mIndicatorView.setSelectedPage(currentPage - 1);
slideDistance = 0;
break;
}
super.onScrollStateChanged(state);
}

@Override
public void onScrolled(int dx, int dy) {
scrollX += dx;
if (scrollState == 1) {
slideDistance += dx;
}

super.onScrolled(dx, dy);
}

/**
* 数据适配器
*/
public class PageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

private List<Map<String, Object>> dataList = null;
private CallBack mCallBack = null;
private int itemWidth = 0;
private int itemCount = 0;

/**
* 实例化适配器
*
* @param data
* @param callBack
*/
public PageAdapter(List<Map<String, Object>> data, CallBack callBack) {
this.dataList = data;
this.mCallBack = callBack;
itemCount = dataList.size(); //+ spanRow * spanColumn;
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (itemWidth <= 0) {
// 计算Item的宽度
//                parent.post(new Runnable() {
//                    @Override
//                    public void run() {
//                        itemWidth = (getWidth() - pageMargin * 2) / spanColumn;
//                    }
//                });
//                itemWidth = (parent.getWidth() - pageMargin * 2) / spanColumn;
//获取手机屏幕宽度px
WindowManager wm = (WindowManager) mContext
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
int withScreen=outMetrics.widthPixels;
itemWidth = withScreen/6;
}

RecyclerView.ViewHolder holder = mCallBack.onCreateViewHolder(parent, viewType);

holder.itemView.measure(0, 0);
holder.itemView.getLayoutParams().width = itemWidth;
holder.itemView.getLayoutParams().height = holder.itemView.getMeasuredHeight();

return holder;
}

@Override
public void onBindViewHolder(ViewHolder holder, int position) {

WindowManager wm = (WindowManager) mContext
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
int withScreen=outMetrics.widthPixels;
if (spanColumn == -1) {
// 每个Item距离左右两侧各pageMargin
//                holder.itemView.getLayoutParams().width = itemWidth + pageMargin * 2;
//                holder.itemView.setPadding(pageMargin, 0, pageMargin, 0);
} else {

int m = position % (spanRow * spanColumn);
if (m < spanRow) {
// 每页左侧的Item距离左边pageMargin
//                    holder.itemView.getLayoutParams().width = itemWidth + pageMargin;
//                    mContext.getWindowManager().getDefaultDisplay().getWidth();//获取手机屏幕宽度px

holder.itemView.getLayoutParams().width =  withScreen/2;
holder.itemView.setPadding(pageMargin*7, 0, 0, 0);
} else if (m >= spanRow * spanColumn - spanRow) {
// 每页右侧的Item距离右边pageMargin
//                    holder.itemView.getLayoutParams().width = itemWidth + pageMargin;
holder.itemView.getLayoutParams().width =  withScreen/2;
holder.itemView.setPadding(0, 0, pageMargin*7, 0);
} else {
// 中间的正常显示
//                    holder.itemView.getLayoutParams().width = itemWidth;
//                    holder.itemView.setPadding(0, 0, 0, 0);
}
}

countRealPosition(position);

holder.itemView.setTag(realPosition);

setListener(holder);
mCallBack.onBindViewHolder(holder, position);
//            if (realPosition < dataList.size()) {
//                holder.itemView.setVisibility(View.VISIBLE);
//                mCallBack.onBindViewHolder(holder, realPosition);
//            } else {
//                holder.itemView.setVisibility(View.INVISIBLE);
//            }

}

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

private void countRealPosition(int position) {
// 为了使Item从左到右从上到下排列,需要position的值
//            int m = position % (spanRow * spanColumn);
realPosition = position;
//            switch (m) {
//
//                case 1:
//                case 5:
//                    realPosition = position + 2;
//                    break;
//                case 3:
//                case 7:
//                    realPosition = position - 2;
//                    break;
//                case 2:
//                    realPosition = position + 4;
//                    break;
//                case 6:
//                    realPosition = position - 4;
//                    break;
//                case 0:
//                case 4:
//                case 8:
//                    realPosition = position;
//                    break;
//            }
}

private void setListener(ViewHolder holder) {
// 设置监听
holder.itemView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mCallBack.onItemClickListener(v, (Integer) v.getTag());
}
});

holder.itemView.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
mCallBack.onItemLongClickListener(v, (Integer) v.getTag());
return true;
}
});
}

/**
* 删除Item
*
* @param position 位置
*/
public void remove(int position) {
if (position < dataList.size()) {
// 删除数据
dataList.remove(position);
itemCount--;
// 删除Item
notifyItemRemoved(position);
// 更新界面上发生改变的Item
notifyItemRangeChanged((currentPage - 1) * spanRow * spanColumn, currentPage * spanRow * spanColumn);
// 更新页码指示器
update();
}
}

}

public interface CallBack {

/**
* 创建VieHolder
*
* @param parent
* @param viewType
*/
RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType);

/**
* 绑定数据到ViewHolder
*
* @param holder
* @param position
*/
void onBindViewHolder(RecyclerView.ViewHolder holder, int position);

void onItemClickListener(View view, int position);

void onItemLongClickListener(View view, int position);

}
}


4、使用

写完了上边的123,就是相当于实现了一整个自定义的控件,这个控件可以实现横向滑动翻页,可以设置行数和列数,并且可以自定义设置指定两个item之间的距离,避免一页中显示连个item显示间距太大的问题,并且翻页的同时会显示指示器

4-1:xml文件使用控件:

<!--自定义RecycleView加指示器横向滑动布局-->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="85dp">
<inditor.recycleview.horizontal.PageRecyclerView
android:id="@+id/cusom_swipe_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">

</inditor.recycleview.horizontal.PageRecyclerView>

<inditor.recycleview.horizontal.PageIndicatorView
android:id="@+id/indicator"
android:layout_width="match_parent"
android:layout_height="12dp"
android:layout_alignParentBottom="true"
android:layout_marginBottom="3dp"></inditor.recycleview.horizontal.PageIndicatorView>
</RelativeLayout>


4-2 java 代码绑定数据并展示,添加item的点击和长按事件

mRecyclerView = (PageRecyclerView) findViewById(R.id.cusom_swipe_view);
// 设置指示器
mRecyclerView.setIndicator((PageIndicatorView) findViewById(R.id.indicator));
// 设置行数和列数
mRecyclerView.setPageSize(1, 2);

// 设置页间距
mRecyclerView.setPageMargin(30);
// 设置数据
mRecyclerView.setAdapter(myAdapter=mRecyclerView.new PageAdapter(list_tequan1, new PageRecyclerView.CallBack() {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(HuiYuanCenterActivity.this).inflate(R.layout.tequan_item, parent, false);
return new MyHolder(view);
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
Map<String,Object> map= (Map<String, Object>) list_tequan1.get(position);
Glide.with(HuiYuanCenterActivity.this).load(map.get("img").toString()).into( ((MyHolder) holder).iv_huanyuan_zuo);
((MyHolder) holder).gv_text.setText((String) map.get("txt"));
}

@Override
public void onItemClickListener(View view, int position) {
//                                        Toast.makeText(HuiYuanCenterActivity.this, "点击:"
//                                                + list_tequan1.get(position), Toast.LENGTH_SHORT).show();

}

@Override
public void onItemLongClickListener(View view, int position) {
//                                        Toast.makeText(HuiYuanCenterActivity.this, "删除:"
//                                                + list_tequan1.get(position), Toast.LENGTH_SHORT).show();
//                                        myAdapter.remove(position);
}
}));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐