(前一篇ViewPager实现和本篇的代码,都在这个项目)
第一行为ViewPager实现效果
第二行为RcyclerView+LinearSnapHelper 实现效果
LinearSnapHelper是一个让
RcyclerView在滑动scroll、快速滑动fling过程中,使得最后停止在一个Item的中间位置,而不是随意的一个位置
很显然,不做特殊处理,第0个和最后一个Item,无法居中;
我们只需要在第0个Item之前加上一个leftMargin,最后一个Item加上一个rightMargin即可
这个margin=RcyclerView中心点X坐标 减去 一个Item的宽度/2
final ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) holder.itemRoot.getLayoutParams();
// 为了居中, 第一个条目leftMagrin、最后一个条目的rightMargin是(recyclerView宽度减去一个条目的宽度)/2
int margin = (mRecyclerViewWidth - p.width) / 2;
if (position == 0) {
p.leftMargin = margin;
p.rightMargin = 0;
holder.itemRoot.setLayoutParams(p);
} else if (position == imageIdArray.length - 1) {
p.leftMargin = 0;
p.rightMargin = margin;
holder.itemRoot.setLayoutParams(p);
} else {
p.leftMargin = 0;
p.rightMargin = 0;
holder.itemRoot.setLayoutParams(p);
}
遍历RcyclerView的每一个子view
(注意RcyclerView的子view等于当前屏幕内所有子view的总和,而不是RcyclerView内部item的总数量,缓存你懂得)
得到所有子view的x坐标
- 换算出每个子view的中心点x坐标,x+itemWidth/2
- 获得RcyclerView的中心点x坐标
- 计算出每个Item中心点x坐标与RcyclerView的中心点x坐标之差offX
- 根据第offX,计算出每个Item所应该缩放的比例interpretateScale
- 让每一个Item去缩放吧
mRecyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int childCount = mRecyclerview.getChildCount();
Log.e("ccc", childCount + "");
int[] location = new int[2];
for (int i = 0; i < childCount; i++) {
View v = mRecyclerview.getChildAt(i);
v.getLocationOnScreen(location);
int recyclerViewCenterX = mRecyclerview.getLeft() + mRecyclerview.getWidth() / 2;
int itemCenterX = location[0] + v.getWidth() / 2;
// ★ 两边的图片缩放比例
float scale = 0.8f;
// ★某个item中心X坐标距recyclerview中心X坐标的偏移量
int offX = Math.abs(itemCenterX - recyclerViewCenterX);
// ★ 在一个item的宽度范围内,item从1缩放至scale,那么改变了(1-scale),
// 从下列公式算出随着offX变化,item的变化缩放百分比
float percent =offX * (1 - scale) / v.getWidth();
// ★ 取反哟
float interpretateScale = 1 - percent;
// 这个if不走的话,得到的是多级渐变模式
if (interpretateScale < scale) {
interpretateScale = scale;
}
v.setScaleX((interpretateScale));
v.setScaleY((interpretateScale));
}
}
});
- 找到这个Item的中心点x坐标
- 计算与RcyclerView中心点x坐标的差值offX
- mRecyclerView.smoothScrollBy(offX, 0);
int[] location = new int[2];
v.getLocationOnScreen(location);
int currentX = location[0];
int currentCenterX = (int) (currentX + p.width / 2 * 0.8f);//因为除了中间外的其他条目是被缩放为0.8的状态
int recyclerViewCenterX = mRecyclerViewWidth / 2;
int offX = currentCenterX - recyclerViewCenterX;
if (Math.abs(offX) >p.width / 2 * 0.21f) {//因为已经居中的Item,已经被放大到比例1了
mRecyclerView.smoothScrollBy(offX, 0);
}
.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="170dp"
android:layout_gravity="center"
android:layout_marginTop="30dp"
android:background="#f00987"
android:clipChildren="false"/>
mRecyclerview = findViewById(R.id.recyclerview);
final LinearLayoutManager manager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
mRecyclerview.setLayoutManager(manager);
int mRecyclerviewWidth;
ViewGroup.LayoutParams layoutParams = mRecyclerview.getLayoutParams();
if (layoutParams.width == -1) {
mRecyclerviewWidth = DisplayUtils.getScreenWidth(this);//我这里是全屏幕宽度,根据实际情况定
} else {
mRecyclerviewWidth = layoutParams.width;
}
mRecAdapter = new RecAdapter(this, mRecyclerviewWidth,mRecyclerview);
mRecyclerview.setAdapter(mRecAdapter);
final LinearSnapHelper helper = new LinearSnapHelper();
helper.attachToRecyclerView(mRecyclerview);
mRecyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int childCount = mRecyclerview.getChildCount();
Log.e("ccc", childCount + "");
int[] location = new int[2];
for (int i = 0; i < childCount; i++) {
View v = mRecyclerview.getChildAt(i);
v.getLocationOnScreen(location);
int recyclerViewCenterX = mRecyclerview.getLeft() + mRecyclerview.getWidth() / 2;
int itemCenterX = location[0] + v.getWidth() / 2;
// ★ 两边的图片缩放比例
float scale = 0.8f;
// ★某个item中心X坐标距recyclerview中心X坐标的偏移量
int offX = Math.abs(itemCenterX - recyclerViewCenterX);
// ★ 在一个item的宽度范围内,item从1缩放至scale,那么改变了(1-scale),从下列公式算出随着offX变化,item的变化缩放百分比
float percent =offX * (1 - scale) / v.getWidth();
// ★ 取反哟
float interpretateScale = 1 - percent;
// 这个if不走的话,得到的是多级渐变模式
if (interpretateScale < scale) {
interpretateScale = scale;
}
v.setScaleX((interpretateScale));
v.setScaleY((interpretateScale));
// Log.e("qwe", recyclerViewCenterX + "///" + itemCenterX + "///" + interpretateScale + "///" + percent + "///" + i);
// Log.e("qwe", "-----");
}
// Log.e("qwe", "====================");
}
});
package com.custom.view.gallerydemo;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
/** * Created by apple on 2018/1/2. */
class RecAdapter extends RecyclerView.Adapter.VH> {
private int mRecyclerViewWidth;
private Context mContext;
private RecyclerView mRecyclerView;
public RecAdapter(Context context, int recyclerViewWidth, RecyclerView recyclerview) {
mContext = context;
mRecyclerViewWidth = recyclerViewWidth;
mRecyclerView = recyclerview;
}
// 准备要显示的图片资源
private int[] imageIdArray = {R.drawable.iv1, R.drawable.iv2,
R.drawable.iv3, R.drawable.iv4, R.drawable.iv1, R.drawable.iv2,
R.drawable.iv3, R.drawable.iv4, R.drawable.iv1, R.drawable.iv2,
R.drawable.iv3, R.drawable.iv4, R.drawable.iv1, R.drawable.iv2,
R.drawable.iv3, R.drawable.iv4, R.drawable.iv1, R.drawable.iv2,
R.drawable.iv3, R.drawable.iv4, R.drawable.iv1, R.drawable.iv2,
R.drawable.iv3, R.drawable.iv4, R.drawable.iv1, R.drawable.iv2,
R.drawable.iv3, R.drawable.iv4, R.drawable.iv1, R.drawable.iv2,
R.drawable.iv3, R.drawable.iv4, R.drawable.iv1, R.drawable.iv2,
R.drawable.iv3, R.drawable.iv4, R.drawable.iv1, R.drawable.iv2,
R.drawable.iv3, R.drawable.iv4, R.drawable.iv1, R.drawable.iv2,
R.drawable.iv3, R.drawable.iv4, R.drawable.iv1, R.drawable.iv2,
R.drawable.iv3, R.drawable.iv4};
@Override
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater from = LayoutInflater.from(mContext);
View view = from.inflate(R.layout.viewpager_item, parent, false);
return new VH(view);
}
@Override
public void onBindViewHolder(final VH holder, final int position) {
holder.iv.setImageResource(imageIdArray[position]);
final ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) holder.itemRoot.getLayoutParams();
// 为了居中, 第一个条目leftMagrin、最后一个条目的rightMargin是(recyclerView宽度减去一个条目的宽度)/2
int margin = (mRecyclerViewWidth - p.width) / 2;
if (position == 0) {
p.leftMargin = margin;
p.rightMargin = 0;
holder.itemRoot.setLayoutParams(p);
} else if (position == imageIdArray.length - 1) {
p.leftMargin = 0;
p.rightMargin = margin;
holder.itemRoot.setLayoutParams(p);
} else {
p.leftMargin = 0;
p.rightMargin = 0;
holder.itemRoot.setLayoutParams(p);
}
holder.itemRoot.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int[] location = new int[2];
v.getLocationOnScreen(location);
int currentX = location[0];
int currentCenterX = (int) (currentX + p.width / 2 * 0.8f);//因为除了中间外的其他条目是被缩放为0.8的状态
int recyclerViewCenterX = mRecyclerViewWidth / 2;
int offX = currentCenterX - recyclerViewCenterX;
if (Math.abs(offX) >p.width / 2 * 0.21f) {//因为已经居中的Item,已经被放大到比例1了
mRecyclerView.smoothScrollBy(offX, 0);
}
}
});
}
@Override
public int getItemCount() {
return imageIdArray.length;
}
class VH extends RecyclerView.ViewHolder {
private RelativeLayout itemRoot;
private ImageView iv;
public VH(View itemView) {
super(itemView);
itemRoot = itemView.findViewById(R.id.item_root);
iv = itemView.findViewById(R.id.iv);
}
}
}