android开发中,当一个页面存放的控件超出屏幕时,通常需要使用scrollview来包裹布局。这样用户可以通过手指的滑动来查看超出屏幕的部分。然而当scrollview滑动到边界时,继续滑动只会显示一个阴影效果。ios自带的控件却可以实现边界的阻尼回弹效果,这种阻尼回弹效果会让用户有更好的使用体验。这里给出一个android上的实现方案
解决思路:
scrollview使用时要求内部有且仅一个子view。当scrollview滑动到边界时,让子view在scrollview中随着手指按一定的规则进行平移,模拟出拉伸效果。当手指松开时,再让子view恢复拉伸前的位置,模拟出回弹效果。
完整的代码如下,详细的原理见注释即可
public class stretchscrollview extends nestedscrollview { // 子view private view innerview; // 上次手势事件的y坐标 private float mlasty; // 记录子view的正常位置 private rect normal = new rect(); public stretchscrollview(context context, attributeset attrs) { super(context, attrs); } @override protected void onfinishinflate() { initview(); super.onfinishinflate(); } /** * 获取scrollview的子布局 */ private void initview() { // 去除原本scrollview滚动到边界时的阴影效果 setoverscrollmode(over_scroll_never); if (getchildat(0) != null) { innerview = getchildat(0); } } @override public boolean ontouchevent(motionevent ev) { switch (ev.getaction()) { case motionevent.action_up: // 手指松开恢复 if (!normal.isempty()) { plananimation(); normal.setempty(); mlasty = 0; } break; case motionevent.action_move: float currenty = ev.gety(); // 滑动距离 int distancey = (int) (mlasty - currenty); // 处理y轴的滚动事件,当滚动到最上或者最下时需要移动布局 // 手指刚触及屏幕时,也会触发此事件,此时mlasty的值还是0,会立即触发一个比较大的移动。这里过滤掉这种情况 if (isneedtranslate() && mlasty != 0) { if (normal.isempty()) { // 保存正常的布局位置 normal.set(innerview.getleft(), innerview.gettop(), innerview.getright(), innerview.getbottom()); } // 移动布局, 使distance / 2 防止平移过快 innerview.layout(innerview.getleft(), innerview.gettop() - distancey / 2, innerview.getright(), innerview.getbottom() - distancey / 2); } mlasty = currenty; break; } return super.ontouchevent(ev); } /** * 回缩动画 */ public void plananimation() { // 开启移动动画 translateanimation animation = new translateanimation(0, 0, innerview.gettop(), normal.top); animation.setduration(200); innerview.startanimation(animation); // 补间动画并不会真正修改innerview的位置,这里需要设置使得innerview回到正常的布局位置 innerview.layout(normal.left, normal.top, normal.right, normal.bottom); } /** * 是否需要y移动布局 */ public boolean isneedtranslate() { int offset = innerview.getmeasuredheight() - getheight(); int scrolly = getscrolly(); // 顶部或者底部 return scrolly == 0 || scrolly == offset; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
声明:如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。