在android开发中,常常会要求IOS应用和android应用的体验一致,所以对应android中开发时,很多控件就需要开发人员自己定义,下面就为大家分享一个仿苹果的弹性滑动ScrollView。

BounceScrollView源码:

package com.joke.widget;import android.content.Context;import android.graphics.Rect;import android.os.Build;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.animation.TranslateAnimation;import android.widget.ScrollView;/** * ScrollView反弹效果的实现 */public class BounceScrollView extends ScrollView {    private View inner;// 孩子View    private float y;// 点击时y坐标    private Rect normal = new Rect();// 矩形(这里只是个形式,只是用于判断是否需要动画.)    private boolean isCount = false;// 是否开始计算    public BounceScrollView(Context context, AttributeSet attrs) {        super(context, attrs);        // 取消滑动到顶部或底部时边缘的黄色或蓝色底纹        if (Build.VERSION.SDK_INT >= 9) {            this.setOverScrollMode(View.OVER_SCROLL_NEVER);        }    }    /***     * 根据 XML 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆盖了 onFinishInflate     * 方法,也应该调用父类的方法,使该方法得以执行.     */    @Override    protected void onFinishInflate() {        if (getChildCount() > 0) {            inner = getChildAt(0);        }    }    /***     * 监听touch     */    @Override    public boolean onTouchEvent(MotionEvent ev) {        if (inner != null) {            commOnTouchEvent(ev);        }        return super.onTouchEvent(ev);    }    /***     * 触摸事件     *      * @param ev     */    public void commOnTouchEvent(MotionEvent ev) {        int action = ev.getAction();        switch (action) {        case MotionEvent.ACTION_DOWN:            break;        case MotionEvent.ACTION_UP:            // 手指松开.            if (isNeedAnimation()) {                animation();                isCount = false;            }            break;        /***         * 排除出第一次移动计算,因为第一次无法得知y坐标, 在MotionEvent.ACTION_DOWN中获取不到,         * 因为此时是MyScrollView的touch事件传递到到了LIstView的孩子item上面.所以从第二次计算开始.         * 然而我们也要进行初始化,就是第一次移动的时候让滑动距离归0. 之后记录准确了就正常执行.         */        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());                }                // Log.e("jj", "矩形:" + inner.getLeft() + "," + inner.getTop()                // + "," + inner.getRight() + "," + inner.getBottom());                // 移动布局                inner.layout(inner.getLeft(), inner.getTop() - deltaY / 2, inner.getRight(), inner.getBottom() - deltaY / 2);            }            isCount = true;            break;        default:            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);        // Log.e("jj", "回归:" + normal.left + "," + normal.top + "," +        // normal.right        // + "," + normal.bottom);        normal.setEmpty();    }    // 是否需要开启动画    public boolean isNeedAnimation() {        return !normal.isEmpty();    }    /***     * 是否需要移动布局 inner.getMeasuredHeight():获取的是控件的总高度     *      * getHeight():获取的是屏幕的高度     *      * @return     */    public boolean isNeedMove() {        int offset = inner.getMeasuredHeight() - getHeight();        int scrollY = getScrollY();        // Log.e("jj", "scrolly=" + scrollY);        // 0是顶部,后面那个是底部        if (scrollY == 0 || scrollY == offset) {            return true;        }        return false;    }}

使用说明:
1、直接将BounceScrollView放到*.widget包中
2、在布局文件中直接使用BounceScrollView包裹其他布局

<com.joke.widget.BounceScrollView 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"    android:fadeScrollbars="false"    android:fadingEdge="none"    android:fadingEdgeLength="0dip"    tools:context=".MainActivity" >    <!-- android:background="@drawable/coversation_bg" -->    <LinearLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:background="#FF0000"        android:orientation="vertical" >        ...        </LinearLayout></com.joke.widget.BounceView>

值得注意的是:BounceScrollView是直接继承自ScrollView的,那么BounceScrollView也需要遵循ScrollView的约定,它内部只允许有一个子View,所以其他布局需要使用一个ViewGroup来包裹。

另外:还可以给BounceScrollView加上背景,使用:android:background="@drawable/coversation_bg"
例如:coversation_bg.xml还可以实现图片的叠加效果

<?xml version="1.0" encoding="utf-8"?><layer-list xmlns:android="http://schemas.android.com/apk/res/android" >    <item>        <bitmap            android:src="@drawable/cover_default_bg"            android:tileMode="repeat" />    </item>    <item android:top="10.0dip">        <bitmap            android:gravity="top|center"            android:src="@drawable/conversation_bg_logo" />    </item></layer-list>

更多相关文章

  1. 说说 Android(安卓)的 Material Design 设计(四)——卡片式布局
  2. [置顶] 【SwipeRefreshLayout】Google官方下拉刷新组件
  3. Android(安卓)ViewPager引导页
  4. Android(安卓)RecyclerView控件
  5. 个人经验 - Android的RelativeLayout布局的layout_height属性设
  6. Android(安卓)App启动图启动界面(Splash)的简单实现
  7. LayoutInflater那些事儿
  8. Android(安卓)GridView 方格中图标与文字如何同时存在
  9. Android换肤Demo

随机推荐

  1. 获取星期几的名称
  2. 通过SQL Server的位运算功能巧妙解决多选
  3. SQL语句的执行原理分析
  4. oracle学习笔记(二)
  5. sqlserver 数据库压缩与数据库日志(ldf)
  6. SQL查询效率注意事项小结
  7. SQLSERVER查询所有数据库名,表名,和字段名
  8. sqlserver 触发器实例代码
  9. 理解SQL SERVER中的逻辑读,预读和物理读
  10. 三种SQL分页查询的存储过程代码