本文是基于折叠布局实现的图片上拉滑动,下拉图片放大,松手放大的效果,先看下效果图。
1.使用CoordinatorLayout自带效果实现上滑。
2.重写CoordinatorLayout触摸事件,在分发之前判断当前是否是在最顶部,并且是下拉操作。
是:进行图片放大,平移下面布局;松手后执行图片回弹动画,恢复布局。
否:不处理事件,滑动事件自动交给下面的Nestscrollview
public class CustomCoordinatorLayout extends CoordinatorLayout {
private View mZoomView;
private int mZoomViewWidth;
private int mZoomViewHeight;
private float firstPosition;//记录第一次按下的位置
private boolean isScrolling;//是否正在缩放
private boolean isScrollDown;//是否下滑
private float mScrollRate = 0.6f;//缩放系数,缩放系数越大,变化的越大
private float mReplyRate = 0.3f;//回调系数,越大,回调越慢
private View mMoveView;
private View mMoveView2;
private int height,height2;
public CustomCoordinatorLayout(@NonNull Context context) {
super(context);
}
public CustomCoordinatorLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public CustomCoordinatorLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setmZoomView(View mZoomView) {
this.mZoomView = mZoomView;
}
public void setmMoveView(View mMoveView1,View mMoveView2) {
this.mMoveView = mMoveView1;
this.mMoveView2 = mMoveView2;
height = mMoveView.getMeasuredHeight();
height2 = mMoveView2.getMeasuredHeight();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int\[\] location = new int\[2\];
mZoomView.getLocationOnScreen(location);
int y = location\[1\];
if (mZoomViewWidth <= 0 || mZoomViewHeight <= 0) {
mZoomViewWidth = mZoomView.getMeasuredWidth();
mZoomViewHeight = mZoomView.getMeasuredHeight();
}
switch (ev.getAction()) {
case MotionEvent.ACTION\_UP:
if(isScrollDown) break;
//手指离开后恢复图片
isScrolling = false;
replyImage();
break;
case MotionEvent.ACTION\_MOVE:
if(y != 0) return super.dispatchTouchEvent(ev);
isScrollDown = false;
if (!isScrolling) {
if (getScrollY() == 0) {
firstPosition = ev.getY();// 滚动到顶部时记录位置,否则正常返回
} else {
break;
}
}
int distance = (int) ((ev.getY() - firstPosition) \* mScrollRate); // 滚动距离乘以一个系数
if (distance < 0) { // 当前位置比记录位置要小,正常返回
isScrollDown = true;
break;
}
// 处理放大
isScrolling = true;
setZoom(distance);
return super.dispatchTouchEvent(ev);
}
return super.dispatchTouchEvent(ev);
}
private void scrollDown(float zoom) {
mMoveView2.setScrollY(-(int)(height2 \* ((height2 + zoom) / height2)));
}
//回弹动画
private void replyImage() {
float distance = mZoomView.getMeasuredWidth() - mZoomViewWidth;
ValueAnimator valueAnimator = ValueAnimator.ofFloat(distance, 0f).setDuration((long) (distance \* mReplyRate));
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
setZoom((Float) animation.getAnimatedValue());
}
});
valueAnimator.start();
mMoveView.setScrollY(height);
mMoveView2.setScrollY(height2);
}
public void setZoom(float zoom) {
if (mZoomViewWidth <= 0 || mZoomViewHeight <= 0) {
return;
}
ViewGroup.LayoutParams lp = mZoomView.getLayoutParams();
lp.width = (int) (mZoomViewWidth \* ((mZoomViewWidth + zoom) / mZoomViewWidth));
lp.height = (int) (mZoomViewHeight \* ((mZoomViewWidth + zoom) / mZoomViewWidth));
((MarginLayoutParams) lp).setMargins(-(lp.width - mZoomViewWidth) / 2, 0, 0, 0);
mZoomView.setLayoutParams(lp);
try {
CollapsingToolbarLayout parent = (CollapsingToolbarLayout) (mMoveView.getParent());
ViewGroup.LayoutParams layoutParams = parent.getLayoutParams();
layoutParams.height = lp.height;
parent.setLayoutParams(layoutParams);
}catch (Exception e){
}
}
}
布局文件结构:
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar\_layout"
android:layout\_width="match\_parent"
android:layout\_height = "wrap\_content"
>
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/csl\_layout"
android:layout\_width="match\_parent"
android:layout\_height="wrap\_content"
android:fitsSystemWindows="true"
app:layout\_scrollFlags="scroll|exitUntilCollapsed">
//要放大的图片
//平移布局一
<LinearLayout
android:id="@+id/mine\_ll\_name"
android:layout\_width="match\_parent"
android:layout\_height="wrap\_content"
android:layout\_marginStart="24dp"
android:layout\_marginTop="50dp"
android:gravity="center\_vertical">
<TextView
android:id="@+id/mine\_tv\_name"
android:layout\_width="wrap\_content"
android:layout\_height="wrap\_content"
android:maxLines="1"
android:textColor="@color/yt\_color\_white"
android:textSize="@dimen/yt\_text\_name"
android:textStyle="normal"
tools:text="节操君" />
<ImageView
android:id="@+id/iv\_ensure\_icon"
android:layout\_width="20dp"
android:layout\_height="20dp"
android:layout\_marginStart="14dp"
android:src="@drawable/ic\_ensure\_icon" />
</LinearLayout>
<TextView
android:id="@+id/mine\_tv\_info"
android:layout\_width="wrap\_content"
android:layout\_height="wrap\_content"
android:layout\_below="@id/mine\_ll\_name"
android:layout\_alignStart="@id/mine\_ll\_name"
android:layout\_marginTop="6dp"
android:alpha="0.6"
android:background="@drawable/shape\_bg\_gray\_round\_stroke"
android:paddingLeft="6dp"
android:paddingTop="2dp"
android:paddingEnd="6dp"
android:paddingBottom="2dp"
android:text="我的主页"
android:textColor="@color/yt\_color\_white"
android:textSize="@dimen/yt\_text\_t1" />
<View
android:id="@+id/v\_personal\_info\_dot"
android:layout\_width="8dp"
android:layout\_height="8dp"
android:layout\_alignTop="@+id/mine\_tv\_info"
android:layout\_alignEnd="@+id/mine\_tv\_info"
android:background="@drawable/shape\_red\_dot" />
<TextView
android:id="@+id/tv\_mine\_user\_setting"
android:layout\_width="wrap\_content"
android:layout\_height="wrap\_content"
android:layout\_alignBottom="@id/mine\_tv\_info"
android:layout\_marginStart="8dp"
android:layout\_toEndOf="@+id/mine\_tv\_info"
android:alpha="0.6"
android:background="@drawable/shape\_bg\_gray\_round\_stroke"
android:paddingStart="6dp"
android:paddingTop="2dp"
android:paddingEnd="6dp"
android:paddingBottom="2dp"
android:text="编辑主页"
android:textColor="@color/yt\_color\_white"
android:textSize="@dimen/yt\_text\_t1" />
//代码省略
...
</RelativeLayout>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/nestedScrollView"
android:layout\_width="match\_parent"
android:layout\_height="match\_parent"
android:fillViewport="true"
app:layout\_behavior="@string/appbar\_scrolling\_view\_behavior”>
//平移布局二
//代码省略
…
</LinearLayout>
</androidx.core.widget.NestedScrollView>
使用就非常简单了,在代码中设置要放大的view以及需要平移的view就可以了。
private fun zoomImage() {
cl_layout.setmMoveView(rl_layout,ll_layout)
cl_layout.setmZoomView(mine_iv_avatar)
}
以上只是个例子用于实现特定布局的动画效果,实际应用可根据场景来自定义view进行操作。
实现效果如下:
重写recylerview的onTouchEvent方法,在顶部往下滑的时候,进行第一个item图片放大及布局下移操作。
好处:多布局中自带滑动,不用处理其他item的滑动,流畅程度100%
public class ZoomRecyclerView extends RecyclerView {
private View mZoomView;
private int mZoomViewWidth;
private int mZoomViewHeight;
private int mViewParentHeight;
private float mScrollRate = 0.3f;//缩放系数,缩放系数越大,变化的越大
private float mReplyRate = 0.3f;//回调系数,越大,回调越慢
// 记录首次按下位置
private float mFirstPosition = 0;
// 是否正在放大
private Boolean mScaling = false;
LinearLayoutManager mLinearLayoutManager ;
public ZoomRecyclerView( Context context) {
super(context);
}
public ZoomRecyclerView( Context context, AttributeSet attrs) {
super(context, attrs);
}
public ZoomRecyclerView( Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setZoomView(SimpleDraweeView v, LinearLayoutManager linearLayoutManager) {
this.mZoomView = v;
mLinearLayoutManager = linearLayoutManager ;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if(mZoomView !=null){
if (mZoomViewWidth <= 0 || mZoomViewHeight <= 0) {
mZoomViewWidth = mZoomView.getMeasuredWidth();
mZoomViewHeight = mZoomView.getMeasuredHeight();
}
if(mViewParentHeight <= 0) {
try {
RelativeLayout parent = (RelativeLayout) mZoomView.getParent();
ViewGroup.LayoutParams layoutParams = parent.getLayoutParams();
mViewParentHeight = layoutParams.height;
}catch (Exception e){}
}
//判断触摸事件
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) \* mScrollRate);
if (distance < 0) {
break;
}
// 处理放大
mScaling = true;
setZoom(distance);
default:
break;
}
}
return super.onTouchEvent(event);
}
private void setZoom(float distance) {
if (mZoomViewWidth <= 0 || mZoomViewHeight <= 0) {
return;
}
ViewGroup.LayoutParams lp = mZoomView.getLayoutParams();
lp.width = (int) (mZoomViewWidth \* ((mZoomViewWidth + distance) / mZoomViewWidth));
lp.height = (int) (mZoomViewHeight \* ((mZoomViewWidth + distance) / mZoomViewWidth));
mZoomView.setLayoutParams(lp);
try {
RelativeLayout parent = (RelativeLayout)mZoomView.getParent();
ViewGroup.LayoutParams layoutParams = parent.getLayoutParams();
layoutParams.height = (int) (mViewParentHeight \* ((mZoomViewWidth + distance) / mZoomViewWidth));
parent.setLayoutParams(layoutParams);
}catch (Exception e){
}
}
/\*\*
\* 图片回弹动画
\*/
private void replyImage() {
float distance = mZoomView.getMeasuredWidth() - mZoomViewWidth;
ValueAnimator valueAnimator = ValueAnimator.ofFloat(distance, 0f).setDuration((long) (distance \* mReplyRate));
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
setZoom((Float) animation.getAnimatedValue());
}
});
valueAnimator.start();
}
布局很简单:
<com.ingtube.common.widget.ZoomRecyclerView
android:id="@+id/rv\_personal\_info"
android:layout\_width="match\_parent"
android:layout\_height="wrap\_content" />
使用也非常简单了。
实现recylerview的滑动监听,在布局为0的时候,设置图片放大及布局下移操作。
rv_personal_info.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
this@PersonalInfoActivity.scrollY = recyclerView.computeVerticalScrollOffset()
if (scrollY == 0 && pageItems.size != 0) {
rv\_personal\_info.setZoomView(personalPageHeadViewBinder!!.getZoomView(), rv\_personal\_info.layoutManager as? LinearLayoutManager)
}
}catch (e:Exception){
e.printStackTrace()
}
}
})
手机扫一扫
移动阅读更方便
你可能感兴趣的文章