Android中ScrollView 滑到头部或尾部可伸缩放大效果
程序员文章站
2023-12-05 13:19:10
最近做项目,想要这么一个效果,就是scrollview 滑动到顶部,当不能在滑动的时候,图片可以下拉放大,松开又恢复。滑到底部没有内容的时候,也有伸缩效果,先看看效果图吧。...
最近做项目,想要这么一个效果,就是scrollview 滑动到顶部,当不能在滑动的时候,图片可以下拉放大,松开又恢复。滑到底部没有内容的时候,也有伸缩效果,先看看效果图吧。
就是如上图这么个效果。系统提供的scrollview 是不能做到这个效果的,所以需要自己自定义,网上找了一些资料。也参考了下其他人的做法。自己也整合了一下。希望对大家有所帮助。
核心的控件就是下面的这段代码:
package com.kokjuis.travel.customview; import android.animation.objectanimator; import android.animation.valueanimator; import android.content.context; import android.graphics.rect; import android.util.attributeset; import android.view.motionevent; import android.view.view; import android.view.viewgroup; import android.view.animation.translateanimation; import android.widget.scrollview; /** * 注意使用的时候需要放大的view,一般是第一个relativelayout或者linearlayout。要加上 android:layout_gravity="center_horizontal" * <p> * created by kokjuis on 2017/3/14. 189155278@qq.com */ public class bouncezoomscrollview extends scrollview { private static final string tag = "bouncescrollview"; //----头部收缩属性-------- // 记录首次按下位置 private float mfirstposition = 0; // 头部图片是否正在放大 private boolean mscaling = false; private view dropzoomview;//需要被放大的view private int dropzoomviewwidth; private int dropzoomviewheight; //----头部收缩属性end-------- //------尾部收缩属性-------- private view inner;// 子view private float y;// 点击时y坐标 private rect normal = new rect();// 矩形(这里只是个形式,只是用于判断是否需要动画.) private boolean iscount = false;// 是否开始计算 //最后的坐标 private float lastx = 0; private float lasty = 0; //当前坐标 private float currentx = 0; private float currenty = 0; //移动的坐标量 private float distancex = 0; private float distancey = 0; private boolean updownslide = false; //判断上下滑动的flag //------尾部收缩属性end-------- public bouncescrollview(context context, attributeset attrs) { super(context, attrs); } //初始化 private void init() { setoverscrollmode(over_scroll_never); if (getchildat(0) != null) { inner = getchildat(0);//这个是底部收缩的view //头部收缩的 viewgroup vg = (viewgroup) getchildat(0); if (vg.getchildat(0) != null) { dropzoomview = vg.getchildat(0); } } } /*** * 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆盖了 onfinishinflate * 方法,也应该调用父类的方法,使该方法得以执行. */ @override protected void onfinishinflate() { //初始化 init(); super.onfinishinflate(); } @override public boolean dispatchtouchevent(motionevent ev) { //这里只是计算尾部坐标 currentx = ev.getx(); currenty = ev.gety(); switch (ev.getaction()) { case motionevent.action_move: distancex = currentx - lastx; distancey = currenty - lasty; if (math.abs(distancex) < math.abs(distancey) && math.abs(distancey) > 12) { updownslide = true; } break; } lastx = currentx; lasty = currenty; if (updownslide && inner != null) commontouchevent(ev); return super.dispatchtouchevent(ev); } /*** * 触摸事件 * * @param ev */ public void commontouchevent(motionevent ev) { //头部缩放计算 if (dropzoomviewwidth <= 0 || dropzoomviewheight <= 0) { dropzoomviewwidth = dropzoomview.getmeasuredwidth(); dropzoomviewheight = dropzoomview.getmeasuredheight(); } switch (ev.getaction()) { case motionevent.action_up: //手指离开后头部恢复图片 mscaling = false; replyimage(); // 手指松开尾部恢复 if (isneedanimation()) { animation(); iscount = false; } clear0(); break; //这里头尾分开处理,互不干扰 case motionevent.action_move: //尾部处理 final float prey = y;// 按下时的y坐标 float nowy = ev.gety();// 时时y坐标 int deltay = (int) (prey - nowy);// 滑动距离 if (!iscount) { deltay = 0; // 在这里要归0. } y = nowy; // 当滚动到最上或者最下时就不会再滚动,这时移动布局 if (isneedmove()) { // 初始化头部矩形 if (normal.isempty()) { // 保存正常的布局位置 normal.set(inner.getleft(), inner.gettop(), inner.getright(), inner.getbottom()); } // 移动布局 inner.layout(inner.getleft(), inner.gettop() - deltay / 2, inner.getright(), inner.getbottom() - deltay / 2); } iscount = true; //尾部处理end //头部处理 if (!mscaling) { if (getscrolly() == 0) { mfirstposition = ev.gety();// 滚动到顶部时记录位置,否则正常返回 } else { break; } } int distance = (int) ((ev.gety() - mfirstposition) * 0.6); // 滚动距离乘以一个系数 if (distance < 0) { // 当前位置比记录位置要小,正常返回 break; } // 处理放大 mscaling = true; setzoom(1 + distance); //头部处理end break; } } /*** * 回缩动画,尾部往下缩动画 */ public void animation() { // 开启移动动画 translateanimation ta = new translateanimation(0, 0, inner.gettop(), normal.top); ta.setduration(200); inner.startanimation(ta); // 设置回到正常的布局位置 inner.layout(normal.left, normal.top, normal.right, normal.bottom); normal.setempty(); } // 是否需要开启动画 public boolean isneedanimation() { return !normal.isempty(); } // 回弹动画,header往上缩动画 (使用了属性动画) public void replyimage() { final float distance = dropzoomview.getmeasuredwidth() - dropzoomviewwidth; // 设置动画 valueanimator anim = objectanimator.offloat(0.0f, 1.0f).setduration((long) (distance * 0.7)); anim.addupdatelistener(new valueanimator.animatorupdatelistener() { @override public void onanimationupdate(valueanimator animation) { float cval = (float) animation.getanimatedvalue(); setzoom(distance - ((distance) * cval)); } }); anim.start(); } //头部缩放 public void setzoom(float s) { if (dropzoomviewheight <= 0 || dropzoomviewwidth <= 0) { return; } viewgroup.layoutparams lp = dropzoomview.getlayoutparams(); lp.width = (int) (dropzoomviewwidth + s); lp.height = (int) (dropzoomviewheight * ((dropzoomviewwidth + s) / dropzoomviewwidth)); dropzoomview.setlayoutparams(lp); } /*** * 是否需要移动布局 inner.getmeasuredheight():获取的是控件的总高度 * * getheight():获取的是屏幕的高度 * * @return */ public boolean isneedmove() { int offset = inner.getmeasuredheight() - getheight(); int scrolly = getscrolly(); // 0是顶部,后面那个是底部 if (scrolly == 0 || scrolly == offset) { return true; } return false; } //清理尾部属性值 private void clear0() { lastx = 0; lasty = 0; distancex = 0; distancey = 0; updownslide = false; } }
下面是我自己使用的一个layout例子:
<?xml version="1.0" encoding="utf-8"?> <com.kokjuis.travel.customview.bouncezoomscrollview xmlns:android="http://schemas.android.com/apk/res/android" xmlns:imagecontrol="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="none"> <!-- <linearlayout android:id="@+id/ui_allchatlist_header_relativelayout" android:layout_width="match_parent" android:layout_height="45dp" android:background="@drawable/bar_bg" android:orientation="horizontal" android:paddingbottom="5dp" android:paddingtop="5dp"> <button android:id="@+id/ui_allchatlist_backbtn" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_marginbottom="3dp" android:layout_marginleft="5dp" android:layout_margintop="3dp" android:background="@null" android:gravity="center" android:text="我" android:textcolor="@color/white" android:textsize="18sp" /> </linearlayout> --> <linearlayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <relativelayout android:layout_width="match_parent" android:layout_height="250dp" android:layout_gravity="center_horizontal"> <imageview android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginbottom="40dp" android:background="@drawable/personinfo_bg" /> <com.kokjuis.travel.customview.roundimageview android:id="@+id/headimage" android:layout_width="80dp" android:layout_height="80dp" android:layout_alignparentbottom="true" android:layout_centerhorizontal="true" android:src="@drawable/headimg" imagecontrol:border_inside_color="#fff7f2e9" imagecontrol:border_outside_color="#ffd5d1c8" imagecontrol:border_thickness="2dp" /> </relativelayout> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <textview android:id="@+id/name_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_margintop="6dp" android:gravity="center_vertical" android:text="昵称:" android:textsize="20sp" /> <textview android:id="@+id/motto_tv" android:layout_width="wrap_content" android:layout_height="40dp" android:layout_gravity="center_horizontal" android:gravity="center_vertical" android:text="座右铭:" android:textsize="11sp" /> <linearlayout android:layout_width="150dp" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:orientation="vertical"> <textview android:id="@+id/accounts_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margintop="8dp" android:gravity="center_vertical" android:text="帐号:" android:textsize="12sp" /> <textview android:id="@+id/gender_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margintop="2dp" android:gravity="center_vertical" android:text="性别:" android:textsize="12sp" /> </linearlayout> <button android:id="@+id/logout_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_margintop="20dp" android:text="注销" /> </linearlayout> </linearlayout> </com.kokjuis.travel.customview.bouncezoomscrollview>
以上所述是小编给大家介绍的android scrollview 滑到头部或尾部可伸缩放大效果,希望对大家有所帮助