Android实现果冻滑动效果的控件
程序员文章站
2024-03-01 09:40:58
前言
在微信是的处理方法是让用户滑动,但最终还是回滚到最初的地方,这样的效果很生动(毕竟成功还是取决于细节)。那么在安卓我们要怎么弄呢。下面为大家介绍一下jellyscr...
前言
在微信是的处理方法是让用户滑动,但最终还是回滚到最初的地方,这样的效果很生动(毕竟成功还是取决于细节)。那么在安卓我们要怎么弄呢。下面为大家介绍一下jellyscrollview,是我继承scrollview的一个有阻尼的效果的果冻滑动控件。
下面话不多说了,先来看看效果图
(在虚拟机或者真机跑起来是很流畅,可能是录制视频做成gif的时候有点卡顿。)
实现原理
其实只需要重写下它的拦截方法的逻辑就好了,scrollview的拦截方法onintercepttouchevent一般情况下都默认地返回false,表示不拦截该事件。我们只需要在用户滑动了界面的情况下,拦截下来并移动布局就好了,当用户松开手就恢复布局。很简单
第一步:集成scrollview重写几个构造方法;
第二步:重写下onfinishinflate方法,获得第一个子view;
第三步:在拦截方法里面处理上面所说的逻辑;
public class jellyscrollview extends scrollview { private view inner;// 子view private float y;// 点击时y坐标 private rect normal = new rect();// 矩形(这里只是个形式,只是用于判断是否需要动画.) private boolean iscount = false;// 是否开始计算 private boolean ismoving = false;// 是否开始移动. private int top;// 拖动时时高度。 private int mtouchslop;//系统最少滑动距离 public jellyscrollview(context context) { super(context); } public jellyscrollview(context context, attributeset attrs) { super(context, attrs); } public jellyscrollview(context context, attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); mtouchslop = viewconfiguration.get(context).getscaledtouchslop(); } /*** * 根据 xml 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆盖了 onfinishinflate * 方法,也应该调用父类的方法,使该方法得以执行. */ @override protected void onfinishinflate() { if (getchildcount() > 0) { inner = getchildat(0); } } /**拦截事件*/ @override public boolean onintercepttouchevent(motionevent ev) { if (inner != null) { int action = ev.getaction(); switch (action) { case motionevent.action_down: y = ev.gety(); top = 0; break; case motionevent.action_up: // 手指松开. ismoving = false; if (isneedanimation()) { animation(); } break; /*** * 排除出第一次移动计算,因为第一次无法得知y坐标, 在motionevent.action_down中获取不到, * 因为此时是scrollview的touch事件传递到到了listview的子item上面.所以从第二次计算开始. * 然而我们也要进行初始化,就是第一次移动的时候让滑动距离归0. 之后记录准确了就正常执行. */ case motionevent.action_move: final float prey = y;// 按下时的y坐标 float nowy = ev.gety();// 每时刻y坐标 int deltay = (int) (nowy - prey);// 滑动距离 if (!iscount) { deltay = 0; // 在这里要归0. } if (math.abs(deltay) < mtouchslop && top <= 0) return true; // 当滚动到最上或者最下时就不会再滚动,这时移动布局 isneedmove(); if (ismoving) { // 初始化头部矩形 if (normal.isempty()) { // 保存正常的布局位置 normal.set(inner.getleft(), inner.gettop(), inner.getright(), inner.getbottom()); } // 移动布局 inner.layout(inner.getleft(), inner.gettop() + deltay / 3, inner.getright(), inner.getbottom() + deltay / 3); top += (deltay / 6); } iscount = true; y = nowy; break; } } return super.onintercepttouchevent(ev); } /*** * 回缩动画 */ 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(); // 手指松开要归0. iscount = false; y = 0; } // 是否需要开启动画 public boolean isneedanimation() { return !normal.isempty(); } /*** * 是否需要移动布局 * inner.getmeasuredheight():获取的是控件的总高度 * getheight():获取的是屏幕的高度 * * @return */ public void isneedmove() { int offset = inner.getmeasuredheight() - getheight(); int scrolly = getscrolly(); // scrolly == 0是顶部 // scrolly == offset是底部 if (scrolly == 0 || scrolly == offset) { ismoving = true; } } }
然后在布局里面在最外层就使用我们的jellyscrollview
(为了方便展示,我只是大概写了一部分布局代码)
<?xml version="1.0" encoding="utf-8"?><cn.ichengxi.fang.view.jellyscrollview xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/bg" android:scrollbars="none"> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <textview android:id="@+id/personal_setting_txt" android:layout_width="match_parent" android:layout_height="wrap_content" android:alpha="0.8" android:gravity="center_vertical" android:text="设置" android:textcolor="@android:color/black" /> </linearlayout></cn.ichengxi.fang.view.jellyscrollview>12345678910111213141516171819202122231234567891011121314151617181920212223
总结
好了,这样就可以很优雅的实现了果冻控件的效果啦。以上就是本文的全部内容了,希望这篇文章的内容对大家能有所帮助,如果有疑问大家可以留言交流。