實(shí)現(xiàn)頭部放下拉放大RecyclerView
-
項(xiàng)目需求需要實(shí)現(xiàn)頭部圖片可下拉放大效果, 網(wǎng)上搜到很多都是自定義scrollView來實(shí)現(xiàn)凶伙,這種方式也可以實(shí)現(xiàn)所需要的效果郭毕,但是當(dāng)與RecyclerView配合使用時(shí),會(huì)一次性加載RecyclerView 中的所有數(shù)據(jù)函荣,著樣總是感覺不太好显押,并且我希望是的是整個(gè)頁面只使用RecyclerView,而不是使用ScrollView 進(jìn)行包裹傻挂, 所以決定還是自定義一個(gè)RecyclerView乘碑。
實(shí)現(xiàn)思路
- 無非就是重寫onTouchEvent方法,再將需要控制放大縮小的view 傳遞給自身即可金拒。
直接上代碼
/**
* Created by lsh on 2018/4/24.
*/
public class MyRecyclerView extends RecyclerView {
private static final String TAG = "MyRecyclerView";
private LinearLayoutManager mLayoutManager;
private int mTouchSlop;
private View zoomView;
// 記錄首次按下位置
private float mFirstPosition = 0;
// 是否正在放大
private Boolean mScaling = false;
LinearLayoutManager mLinearLayoutManager ;
private int screenWidth;
public MyRecyclerView(Context context) {
this(context, null);
}
public MyRecyclerView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MyRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mLayoutManager = new LinearLayoutManager(context);
setLayoutManager(mLayoutManager);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
}
public void setZoomView(View v, LinearLayoutManager linearLayoutManager) {
//獲取屏幕寬度
screenWidth = ScreenUtils.getScreenWidth();
//此處我的圖片命名為img兽肤,大家根據(jù)實(shí)際情況修改
ImageView img =(ImageView)v.findViewById(R.id.img);
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) img.getLayoutParams();
//獲取屏幕寬度
lp.width =screenWidth;
//設(shè)置寬高比為16:9
lp.height = screenWidth * 9 / 16;
//給imageView重新設(shè)置寬高屬性
img.setLayoutParams(lp);
this.zoomView = img;
mLinearLayoutManager = linearLayoutManager ;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(zoomView !=null){
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) zoomView.getLayoutParams();
//判斷觸摸事件
switch (event.getAction()) {
//觸摸結(jié)束
case MotionEvent.ACTION_UP:
mScaling = false;
replyImage();
break;
//觸摸中
case MotionEvent.ACTION_MOVE:
//判斷是否正在放大 mScaling 的默認(rèn)值為false
if (!mScaling) {
//當(dāng)圖片也就是第一個(gè)item完全可見的時(shí)候,記錄觸摸屏幕的位置
if (mLinearLayoutManager.findViewByPosition(mLinearLayoutManager.findFirstVisibleItemPosition()).getTop() == 0) {
//記錄首次按下位置
mFirstPosition = event.getY();
} else {
break;
}
}
// 滾動(dòng)距離乘以一個(gè)系數(shù)
int distance = (int) ((event.getY() - mFirstPosition) * 0.4);
if (distance < 0) {
break;
}
// 處理放大
mScaling = true;
lp.width = zoomView.getWidth() + distance;
lp.height = (zoomView.getWidth() + distance) * 9 / 16;
System.out.println( "寬度是 = " + lp.width + "高度是" + lp.height);
// 設(shè)置控件水平居中(如果不設(shè)置绪抛,圖片的放大縮小是從圖片頂點(diǎn)開始)
((ViewGroup.MarginLayoutParams) lp).setMargins(-(lp.width -screenWidth) / 2, 0, 0, 0);
zoomView.setLayoutParams(lp);
return true; // 返回true表示已經(jīng)完成觸摸事件资铡,不再處理
}
}
return super.onTouchEvent(event);
}
/**
* 圖片回彈動(dòng)畫
*/
private void replyImage() {
final RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) zoomView.getLayoutParams();
final float wPresent = zoomView.getLayoutParams().width;// 圖片當(dāng)前寬度
final float hPresent = zoomView.getLayoutParams().height;// 圖片當(dāng)前高度
final float width = screenWidth;// 圖片原寬度
final float heigh = screenWidth * 9 / 16;// 圖片原高度
// 設(shè)置動(dòng)畫
ValueAnimator anim = ObjectAnimator.ofFloat(0.0F, 1.0F).setDuration(200);
anim.addUpdateListener(animation -> {
float cVal = (Float) animation.getAnimatedValue();
lp.width = (int) (wPresent- (wPresent- width ) * cVal);
lp.height = (int) (hPresent - (hPresent - heigh ) * cVal);
((MarginLayoutParams) lp).setMargins(-(lp.width - screenWidth) / 2, 0, 0, 0);
zoomView.setLayoutParams(lp);
});
anim.start();
}
}
其中ScreenUtils 是 utilcode中提供的工具類
- Java代碼
public class PullZoomActivity extends AppCompatActivity {
private DisplayMetrics metric;
private MyRecyclerView recy;
private LinearLayoutManager mLinearLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pull_zoom);
recy = (MyRecyclerView)findViewById(R.id.hehe);
if (mLinearLayoutManager == null) {
mLinearLayoutManager = new LinearLayoutManager(this);
}
TestAdpter testAdpter = new TestAdpter(R.layout.text, getData());
recy.setLayoutManager(mLinearLayoutManager) ;
recy.setAdapter(testAdpter);
View view = getLayoutInflater().inflate(R.layout.header, (ViewGroup) recy.getParent(), false);
testAdpter.addHeaderView(view);
//給Recycle中傳遞需要控制的view
recy.setZoomView(view , mLinearLayoutManager);
}
public List<String> getData() {
ArrayList<String> lsit = new ArrayList<>();
for (int i = 0; i <20 ; i++) {
lsit.add("第" + i + "條數(shù)據(jù)") ;
}
return lsit;
}
}
其中adapter 是使用BRVAH 的 BaseRecyclerViewAdapterHelper(強(qiáng)烈推薦,你值得擁有)我這里使用的是將Image放在頭部具中實(shí)現(xiàn)的幢码,當(dāng)然你也可以使用RecycleView的多布局笤休,只是相應(yīng)的你需要在adpter中判斷當(dāng)時(shí)第一條item時(shí) 執(zhí)行setZoomView 方法進(jìn)行view的傳遞。