您的位置:首页 > 移动开发 > Android开发

Android RecyclerView 实现横向滚动效果

2017-10-09 20:04 721 查看
         滚动控件的实现方式有很多, 使用RecyclerView也比较简单. 做了一个简单的年龄滚动控件, 让我们来看看RecyclerView的使用方式, 主要有以下几点: 
(1) 对齐控件中心位置. 
(2) 计算滚动距离. 
(3) 高亮中心视图. 
(4) 实时显示中心数据. 
(5) 停止时自动对齐. 
(6) 滚动时, 设置按钮状态开关


类似源码下载:  点击下载源码            点击下载源码2








1.RecyclerView部分逻辑:



/**
* 初始化年龄滑动条
*/
private void initAgeList() {
LinearLayoutManager mLayoutManager =
new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
mRvAgeList.setLayoutManager(mLayoutManager);
mAgeAdapter = new PersonAgeAdapter(START_NUM, END_NUM);
mRvAgeList.setAdapter(mAgeAdapter);
mRvAgeList.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);

mBDownStep.setEnabled(false);

// 效果在暂停时显示, 否则会导致重绘异常
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
mAgeAdapter.highlightItem(getMiddlePosition());
mRvAgeList.scrollToPosition(getScrollPosition());
mLastValue = getMiddlePosition();
UserInfoManager.setAge(getMiddlePosition() + START_NUM);

mBDownStep.setEnabled(true); // 滑动时不可用, 停止时才可以
}
}

@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
// 值是实时增加
mTvAgeValue.setText(String.valueOf(getMiddlePosition() + START_NUM));
}
});

mAgeAdapter.highlightItem(getMiddlePosition());
}

 1).设置一个水平布局:

LinearLayoutManager mLayoutManager =
new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false);
mRvAgeList.setLayoutManager(mLayoutManager);

 2).添加Adapter, 设置起始和结束位置:

mAgeAdapter = new PersonAgeAdapter(START_NUM, END_NUM);
mRvAgeList.setAdapter(mAgeAdapter);

2.Adapter:

Adapter定制一些功能,
如标示指向中心位置, 数据联动显示, 高亮Item等

/**
* 年龄的适配器
* <p>
* Created by wangchenlong on 15/11/12.
*/
public class PersonAgeAdapter extends RecyclerView.Adapter<PersonAgeAdapter.AgeItemViewHolder> {

public static final int ITEM_NUM = 7; // 每行拥有的Item数, 必须是奇数

private int mFrom; // 起始
private int mTo; // 终止
private int mHighlight = -1; // 高亮

public PersonAgeAdapter(int from, int to) {
mFrom = from;
mTo = to;
}

@Override public AgeItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View item = LayoutInflater.from(parent.getContext()).
inflate(R.layout.view_age_item, parent, false);

// 设置Item的宽度
ViewGroup.LayoutParams lp = item.getLayoutParams();
lp.width = getItemStdWidth();

return new AgeItemViewHolder(item);
}

@Override public void onBindViewHolder(AgeItemViewHolder holder, int position) {
holder.getTextView().setText(String.valueOf(mFrom + position));

// 高亮显示
if (isSelected(position)) {
holder.getTextView().setTextSize(30);
holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.black));
} else {
holder.getTextView().setTextSize(20);
holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.gray_line));
}
}

// 高亮中心, 更新前后位置
public void highlightItem(int position) {
mHighlight = position;
int offset = ITEM_NUM / 2;
for (int i = position - offset; i <= position + offset; ++i)
notifyItemChanged(i);
}

// 判断是否是高亮
public boolean isSelected(int position) {
return mHighlight == position;
}

@Override public int getItemCount() {
return mTo - mFrom + 1;
}

// 获取标准宽度
public static int getItemStdWidth() {
DisplayMetrics displayMetrics = ChunyuApp.getAppContext().getResources().getDisplayMetrics();
return displayMetrics.widthPixels / ITEM_NUM;
}

// ViewHolder
public class AgeItemViewHolder extends RecyclerView.ViewHolder {

private TextView mTextView;

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

mTextView = (TextView) itemView.findViewById(R.id.item_age_value);
mTextView.setTag(this);
}

public TextView getTextView() {
return mTextView;
}
}
}

每个单元格宽度是屏幕宽度的
奇数
分之一,
填充屏幕, 则起始指向中心

@Override public AgeItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View item = LayoutInflater.from(parent.getContext()).
inflate(R.layout.view_age_item, parent, false);

// 设置Item的宽度
ViewGroup.LayoutParams lp = item.getLayoutParams();
lp.width = getItemStdWidth();

return new AgeItemViewHolder(item);
}


单数Item数量, 则中心的指示器必指向中心Item的中心,根据选中状态, 更新Item样式.

@Override public void onBindViewHolder(AgeItemViewHolder holder, int position) {
holder.getTextView().setText(String.valueOf(mFrom + position));

// 高亮显示
if (isSelected(position)) {
holder.getTextView().setTextSize(30);
holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.black));
} else {
holder.getTextView().setTextSize(20);
holder.getTextView().setTextColor(ChunyuApp.getAppContext().getResources().getColor(R.color.gray_line));
}
}

设置高亮, 把中心位置高亮, 两边恢复, 通知Adapter重绘ViewHolder

// 高亮中心, 更新前后位置
public void highlightItem(int position) {
mHighlight = position;
int offset = ITEM_NUM / 2;
for (int i = position - offset; i <= position + offset; ++i)
notifyItemChanged(i);
}

// 判断是否是高亮
public boolean isSelected(int position) {
return mHighlight == position;
}


notifyItemChanged()会重绘所选择的页面,获取宽度, 把一行显示Item数量设置为单数, 则中心指向一个Item

// 获取标准宽度
public static int getItemStdWidth() {
DisplayMetrics displayMetrics = ChunyuApp.getAppContext().getResources().getDisplayMetrics();
return displayMetrics.widthPixels / ITEM_NUM;
}


注意RecyclerView不能移动半个单元, 每行数量是单数时, 则必会指向中心

3.滚动逻辑

在滚动时,
实时更新页面显示; 在停止时, 更新高亮和存储数据; 滚动结束时, 激活按钮

mRvAgeList.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
mBDownStep.setEnabled(false);

// 效果在暂停时显示, 否则会导致重绘异常
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
mAgeAdapter.highlightItem(getMiddlePosition());
mRvAgeList.scrollToPosition(getScrollPosition());
mLastValue = getMiddlePosition();
UserInfoManager.setAge(getMiddlePosition() + START_NUM);

mBDownStep.setEnabled(true); // 滑动时不可用, 停止时才可以
}
}

@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
// 值是实时增加
mTvAgeValue.setText(String.valueOf(getMiddlePosition() + START_NUM));
}
});

mAgeAdapter.highlightItem(getMiddlePosition());
}

/**
* 获取中间位置
*
* @return 当前值
*/
private int getMiddlePosition() {
return getScrollPosition() + (PersonAgeAdapter.ITEM_NUM / 2);
}

/**
* 获取滑动值, 滑动偏移 / 每个格子宽度
*
* @return 当前值
*/
private int getScrollPosition() {
return (int) ((double) mRvAgeList.computeHorizontalScrollOffset()
/ (double) PersonAgeAdapter.getItemStdWidth());
}

判断滚动的距离单位, 偏移总距离/单个Item宽度

private int getScrollPosition() {
return (int) ((double) mRvAgeList.computeHorizontalScrollOffset()
/ (double) PersonAgeAdapter.getItemStdWidth());
}


computeHorizontalScrollOffset()获取RecyclerView的偏移总位移

中间位置, 还要加上半行Item数量

private int getMiddlePosition() {
return getScrollPosition() + (PersonAgeAdapter.ITEM_NUM / 2);
}

判断滚动是否停止

if (newState == RecyclerView.SCROLL_STATE_IDLE)


在滚动停止时, 自动对齐

mRvAgeList.scrollToPosition(getScrollPosition());

调用需要高亮显示的Item

mAgeAdapter.highlightItem(getMiddlePosition());


注意在滚动停止时, 更新高亮比较好, 否则重绘速度较慢, 会影响滚动效果



OK

点击下载源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: