用过iphone的朋友相信都体验过页面上拉下拉有一个弹性的效果,使用起来用户体验很好;Android并没有给我们封装这样一个效果,我们来看下在Android里如何实现这个效果。先看效果,感觉有些时候还是蛮实用的。
思路:其实原理很简单,实现一个自定义的Scrollview方法(来自网上大神),然后在布局文件中使用自定义方法Scrollview就可以了。 代码: 自定义View,继承自Scrollview。MyReboundScrollView类
package com.wj.myreboundscrollview.customview;import android.content.Context;import android.graphics.Rect;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.animation.TranslateAnimation;import android.widget.ScrollView;//仿ios可上提下拉的ScrollViewpublic class MyReboundScrollView extends ScrollView {private static final String TAG = "ElasticScrollView";        //移动因子, 是一个百分比, 比如手指移动了100px, 那么View就只移动50px    //目的是达到一个延迟的效果    private static final float MOVE_FACTOR = 0.5f;         //松开手指后, 界面回到正常位置需要的动画时间    private static final int ANIM_TIME = 100;         //ScrollView的子View, 也是ScrollView的唯一一个子View    private View contentView;          //手指按下时的Y值, 用于在移动时计算移动距离    //如果按下时不能上拉和下拉, 会在手指移动时更新为当前手指的Y值    private float startY;         //用于记录正常的布局位置    private Rect originalRect = new Rect();         //手指按下时记录是否可以继续下拉    private boolean canPullDown = false;         //手指按下时记录是否可以继续上拉    private boolean canPullUp = false;         //在手指滑动的过程中记录是否移动了布局    private boolean isMoved = false;     public MyReboundScrollView(Context context) {        super(context);    }         public MyReboundScrollView(Context context, AttributeSet attrs) {        super(context, attrs);    }     @Override    protected void onFinishInflate() {        if (getChildCount() > 0) {            contentView = getChildAt(0);        }    }         @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        super.onLayout(changed, l, t, r, b);                 if(contentView == null) return;         //ScrollView中的唯一子控件的位置信息, 这个位置信息在整个控件的生命周期中保持不变        originalRect.set(contentView.getLeft(), contentView.getTop(), contentView                .getRight(), contentView.getBottom());    }     //在触摸事件中, 处理上拉和下拉的逻辑    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {                 if (contentView == null) {            return super.dispatchTouchEvent(ev);        }         int action = ev.getAction();                 switch (action) {        case MotionEvent.ACTION_DOWN:                         //判断是否可以上拉和下拉            canPullDown = isCanPullDown();            canPullUp = isCanPullUp();                         //记录按下时的Y值            startY = ev.getY();            break;                     case MotionEvent.ACTION_UP:                         if(!isMoved) break;  //如果没有移动布局, 则跳过执行                         // 开启动画            TranslateAnimation anim = new TranslateAnimation(0, 0, contentView.getTop(),                    originalRect.top);            anim.setDuration(ANIM_TIME);                         contentView.startAnimation(anim);                         // 设置回到正常的布局位置            contentView.layout(originalRect.left, originalRect.top,                     originalRect.right, originalRect.bottom);                         //将标志位设回false            canPullDown = false;            canPullUp = false;            isMoved = false;                         break;        case MotionEvent.ACTION_MOVE:                         //在移动的过程中, 既没有滚动到可以上拉的程度, 也没有滚动到可以下拉的程度            if(!canPullDown && !canPullUp) {                startY = ev.getY();                canPullDown = isCanPullDown();                canPullUp = isCanPullUp();                                 break;            }                         //计算手指移动的距离            float nowY = ev.getY();            int deltaY = (int) (nowY - startY);                         //是否应该移动布局            boolean shouldMove =                     (canPullDown && deltaY > 0)    //可以下拉, 并且手指向下移动                    || (canPullUp && deltaY< 0)    //可以上拉, 并且手指向上移动                    || (canPullUp && canPullDown); //既可以上拉也可以下拉(这种情况出现在ScrollView包裹的控件比ScrollView还小)                         if(shouldMove){                //计算偏移量                int offset = (int)(deltaY * MOVE_FACTOR);                                 //随着手指的移动而移动布局                contentView.layout(originalRect.left, originalRect.top + offset,                        originalRect.right, originalRect.bottom + offset);                                 isMoved = true;  //记录移动了布局            }                         break;        default:            break;        }         return super.dispatchTouchEvent(ev);    }          //判断是否滚动到顶部    private boolean isCanPullDown() {        return getScrollY() == 0 ||                 contentView.getHeight() < getHeight() + getScrollY();    }         //判断是否滚动到底部    private boolean isCanPullUp() {        return  contentView.getHeight() <= getHeight() + getScrollY();    }}
代码注释非常清楚。 布局文件直接使用
<com.wj.myreboundscrollview.customview.MyReboundScrollView    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity"    android:orientation="vertical">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:orientation="vertical">        <EditText            android:id="@+id/et_name"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_marginTop="12dip"            android:hint="Your Name"/>        <EditText            android:id="@+id/et_feedback"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_marginTop="32dip"            android:hint="Your Feedback"            android:lines="5"/>        <Button            android:id="@+id/btn_submit"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="center"            android:layout_marginTop="42dip"            android:text="Submit"            android:onClick="submit"/>    </LinearLayout></com.wj.myreboundscrollview.customview.MyReboundScrollView>
这里直接在外层包裹实现。注意,因为Myreboundscrollview是继承自Scrollview,因此要遵循Scrollview的使用原则,里面只能包含一个LinearLayout,所以无论里面多门复杂的布局,最后我们都要将其包含在一个LinearLayout中。
ok,功能实现,效果也演示,具体需要使用直接拿来用就可以。
如果觉得对你有帮助,顶起留言啊!

更多相关文章

  1. Android(安卓)Studio插件Android(安卓)Code Generator的使用
  2. 【IMOOC学习笔记】多种多样的App主界面Tab实现方法(一)
  3. TextView和EditText中添加图片(ImageSpan)
  4. Android开发指南(35) —— Toast Notifications
  5. Android(安卓)PullToRefresh 详解
  6. 第一个变化———由support库到Androidx
  7. Android(安卓)Fragment 剖析 - 01
  8. 简单分析Android里面的TimePicker控件
  9. Android(安卓)自定义View控件,实现跟随手指触摸移动的小球

随机推荐

  1. Android中Drawable分类汇总
  2. Android中Context
  3. 关于Android发送邮件
  4. 【Android(安卓)XMPP】 学习资料收集贴(持
  5. Ubuntu下使用adb和USB连接的方式进行andr
  6. AndroidManifest.xml文件剖析 (二)
  7. android2.2中EditText不可编辑的问题
  8. android之TextView属性
  9. Android(安卓)数字标记
  10. android开发常用知识点备忘录