实现头部放下拉放大RecyclerView
-
项目需求需要实现头部图片可下拉放大效果, 网上搜到很多都是自定义scrollView来实现,这种方式也可以实现所需要的效果,但是当与RecyclerView配合使用时,会一次性加载RecyclerView 中的所有数据,着样总是感觉不太好,并且我希望是的是整个页面只使用RecyclerView,而不是使用ScrollView 进行包裹, 所以决定还是自定义一个RecyclerView。
实现思路
- 无非就是重写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,大家根据实际情况修改
ImageView img =(ImageView)v.findViewById(R.id.img);
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) img.getLayoutParams();
//获取屏幕宽度
lp.width =screenWidth;
//设置宽高比为16:9
lp.height = screenWidth * 9 / 16;
//给imageView重新设置宽高属性
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()) {
//触摸结束
case MotionEvent.ACTION_UP:
mScaling = false;
replyImage();
break;
//触摸中
case MotionEvent.ACTION_MOVE:
//判断是否正在放大 mScaling 的默认值为false
if (!mScaling) {
//当图片也就是第一个item完全可见的时候,记录触摸屏幕的位置
if (mLinearLayoutManager.findViewByPosition(mLinearLayoutManager.findFirstVisibleItemPosition()).getTop() == 0) {
//记录首次按下位置
mFirstPosition = event.getY();
} else {
break;
}
}
// 滚动距离乘以一个系数
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);
// 设置控件水平居中(如果不设置,图片的放大缩小是从图片顶点开始)
((ViewGroup.MarginLayoutParams) lp).setMargins(-(lp.width -screenWidth) / 2, 0, 0, 0);
zoomView.setLayoutParams(lp);
return true; // 返回true表示已经完成触摸事件,不再处理
}
}
return super.onTouchEvent(event);
}
/**
* 图片回弹动画
*/
private void replyImage() {
final RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) zoomView.getLayoutParams();
final float wPresent = zoomView.getLayoutParams().width;// 图片当前宽度
final float hPresent = zoomView.getLayoutParams().height;// 图片当前高度
final float width = screenWidth;// 图片原宽度
final float heigh = screenWidth * 9 / 16;// 图片原高度
// 设置动画
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 + "条数据") ;
}
return lsit;
}
}
其中adapter 是使用BRVAH 的 BaseRecyclerViewAdapterHelper(强烈推荐,你值得拥有)我这里使用的是将Image放在头部具中实现的,当然你也可以使用RecycleView的多布局,只是相应的你需要在adpter中判断当时第一条item时 执行setZoomView 方法进行view的传递。