實現類似貓眼影片詳情頁電影海報滾動效果(RcyclerView+LinearSnapHelper )
阿新 • • 發佈:2019-02-09
(前一篇ViewPager實現和本篇的程式碼,都在這個專案)
效果
第一行為ViewPager實現效果
第二行為RcyclerView+LinearSnapHelper 實現效果
重點
LinearSnapHelper是什麼
LinearSnapHelper是一個讓
RcyclerView在滑動scroll、快速滑動fling過程中,使得最後停止在一個Item的中間位置,而不是隨意的一個位置
使用LinearSnapHelper後,如何讓RcyclerView的第0個Item和最後一個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,讓這個Item居中
- 找到這個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);
}
貼上程式碼,詳細註釋
佈局
<android.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"/>
Activity
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", "====================");
}
});
adapter
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<RecAdapter.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);
}
}
}