首页 > 代码库 > android 自定义scrollview 仿QQ空间效果 下拉伸缩顶部图片,上拉回弹 上拉滚动顶部title 颜色渐变

android 自定义scrollview 仿QQ空间效果 下拉伸缩顶部图片,上拉回弹 上拉滚动顶部title 颜色渐变

首先要知道  自定义scrollview 仿QQ效果 下拉伸缩放大顶部图片 的原理是监听ontouch事件,在MotionEvent.ACTION_MOVE事件时候,使用不同倍数的系数,重置布局位置【注此处是伸缩隐藏,不是同比例放大】

inner.layout(normal.left, (int) (normal.top + inner_move_H),
normal.right, (int) (normal.bottom + inner_move_H));

关于“自定义scrollview 仿QQ效果 下拉放大顶部图片,上拉回弹”这个问题,网上有很多demo,可是或多或少都有一些问题。比如,上拉滚动不回弹,事件分发处理等。这里主要解决调的问题如下:

1. ScrollView+RelativeLayout 高度计算不准确 当设置margin为负数的时候显示无效果。此时的解决办法是使用FrameLayout、LinearLayout代替完成布局

 参考文档http://blog.csdn.net/peidonghui/article/details/8502190

android总结之ScrollView与RelativeLayout和LinearLayout同时使用时问题总结  

2.事件分发处理和滚动位置的处理,对处理子控件如button和父控件获取焦点,点击冲突,产生跳跃的问题时候,可以在

case MotionEvent.ACTION_MOVE:
requestDisallowInterceptTouchEvent(true);
设置滚动时子控件在滚动时不获取焦点
http://thoreau.iteye.com/blog/2002272

3.标题变化

标题透明度的变化主要是设置监听,监听滚动的位置,并根据位置计算标题透明度

 

控件修改自http://blog.csdn.net/jj120522/article/details/8938308?utm_source=tuicool&utm_medium=referral

下面放出控件源码

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.ImageView;import android.widget.ScrollView;public class PersonalScrollView extends ScrollView {    private final String TAG = PersonalScrollView.class.getSimpleName();    private View inner;// 孩子View    private float touchY;// 点击时Y坐标    private float deltaY;// Y轴滑动的距离    private float initTouchY;// 首次点击的Y坐标    private boolean shutTouch = false;// 是否关闭ScrollView的滑动.    private Rect normal = new Rect();// 矩形(这里只是个形式,只是用于判断是否需要动画.)    private boolean isMoveing = false;// 是否开始向下移动.    private ImageView imageView;// 背景图控件.//    private View line_up;// 上线//    private int line_up_top;// 上线的top//    private int line_up_bottom;// 上线的bottom    private int initTop, initBottom;// 初始高度    private int current_Top, current_Bottom;// 拖动时时高度。    //private int lineUp_current_Top, lineUp_current_Bottom;// 上线    private onTurnListener turnListener;    // 状态:上部,下部,默认    private enum State {        UP, DOWN, NOMAL    };    private boolean isclick = true;    // 默认状态    private State state = State.NOMAL;    private ScrollViewListener scrollViewListener = null;    public interface ScrollViewListener {        void onScrollChanged(PersonalScrollView scrollView, int x, int y,                             int oldx, int oldy);    }    public void setScrollViewListener(ScrollViewListener scrollViewListener) {        this.scrollViewListener = scrollViewListener;    }    @Override    protected void onScrollChanged(int x, int y, int oldx, int oldy) {        super.onScrollChanged(x, y, oldx, oldy);        if (scrollViewListener != null) {            scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);        }    }    public void setTurnListener(onTurnListener turnListener) {        this.turnListener = turnListener;    }//    public void setLine_up(View line_up) {//        this.line_up = line_up;//    }    // 注入背景图    public void setImageView(ImageView imageView) {        this.imageView = imageView;    }    /***     * 构造方法     *     * @param context     * @param attrs     */    public PersonalScrollView(Context context, AttributeSet attrs) {        super(context, attrs);    }    /***     * 根据 XML 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆盖了 onFinishInflate     * 方法,也应该调用父类的方法,使该方法得以执行.     *///    @Override//    protected void onFinishInflate() {////        if (getChildCount() > 0) {////            inner = getChildAt(0);////        }//    }    public void setinner(View inner) {        this.inner = inner;    }    /** touch 事件处理 **/    @Override    public boolean onTouchEvent(MotionEvent ev) {        if (inner != null) {            commOnTouchEvent(ev);        }        //super.onTouchEvent(ev);        // ture:禁止控件本身的滑动.//        if (shutTouch)//            return true;//        else{//            return super.onTouchEvent(ev);//        }        return super.onTouchEvent(ev);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        return  super.onInterceptTouchEvent(ev);        //TRUE 当前的控件的onTouchEvent()        //false 子控件的onInterceptTouchEvent()//        if(ev.getAction()==MotionEvent.ACTION_DOWN){//            return super.onInterceptTouchEvent(ev);//        }//        if(ev.getAction()==MotionEvent.ACTION_MOVE){//            return true;//        }////        Log.d("isclick", shutTouch + "  "+state+"  ");//        if (shutTouch)//            return true;//        if(state!=State.NOMAL){//            return true;//        }else if(isclick){//            return true;//        }else {//            return super.onInterceptTouchEvent(ev);//        }//        if (!isclick) {//            //向上向下滚动时候不触发子控件的touch//            //屏蔽抬起事件以后,要重置isclick事件,准备下一次点击//            if (!isclick&&State.NOMAL!=state) {//                //一次滚动结束//                isclick = true;//            }//            return true;//        } else//            return super.onInterceptTouchEvent(ev);        // return super.onInterceptTouchEvent(ev);    }    /***     * 触摸事件     *     * @param ev     */    public void commOnTouchEvent(MotionEvent ev) {        int action = ev.getAction();        switch (action) {            case MotionEvent.ACTION_DOWN:                initTouchY = ev.getY();                requestDisallowInterceptTouchEvent(false);                current_Top = initTop = imageView.getTop();                current_Bottom = initBottom = imageView.getBottom();                isclick = true;                break;            case MotionEvent.ACTION_UP:                /** 回缩动画 **/                requestDisallowInterceptTouchEvent(false);                if (isNeedAnimation()) {                    animation();                }//            if (getScrollY() == 0) {//                state = State.NOMAL;//            }                if(state!=State.NOMAL){                    isclick = false;                }else{                    isclick = true;                }                state = State.NOMAL;                isMoveing = false;                touchY = 0;                shutTouch = false;                break;            /***             * 排除出第一次移动计算,因为第一次无法得知deltaY的高度, 然而我们也要进行初始化,就是第一次移动的时候让滑动距离归0.             * 之后记录准确了就正常执行.             */            case MotionEvent.ACTION_MOVE:                requestDisallowInterceptTouchEvent(true);                touchY = ev.getY();                deltaY = touchY - initTouchY;// 滑动距离                isclick = false;                /** 对于首次Touch操作要判断方位:UP OR DOWN **/                if (deltaY < 0 && state == state.NOMAL&&Math.abs(deltaY)>40) {                    state = State.UP;                } else if (deltaY > 0 && state == state.NOMAL&&Math.abs(deltaY)>40) {                    state = State.DOWN;                }                if (state == State.UP) {                    deltaY = deltaY < 0 ? deltaY : 0;                    isMoveing = false;                    shutTouch = false;                } else if (state == state.DOWN) {                    if (getScrollY() <= deltaY) {                        shutTouch = true;                        isMoveing = true;                    }                    deltaY = deltaY < 0 ? 0 : deltaY;                }                if (isMoveing) {                    // 初始化头部矩形                    if (normal.isEmpty()) {                        // 保存正常的布局位置                        normal.set(inner.getLeft(), inner.getTop(),                                inner.getRight(), inner.getBottom());                    }                    // 移动布局(手势移动的1/3)                    float inner_move_H = deltaY / 5;                    inner.layout(normal.left, (int) (normal.top + inner_move_H),                            normal.right, (int) (normal.bottom + inner_move_H));                    /** image_bg **/                    float image_move_H = deltaY / 10;                    current_Top = (int) (initTop + image_move_H);                    current_Bottom = (int) (initBottom + image_move_H);                    imageView.layout(imageView.getLeft(), current_Top,                            imageView.getRight(), current_Bottom);                }                break;            default:                break;        }    }    /***     * 回缩动画     */    public void animation() {        TranslateAnimation image_Anim = new TranslateAnimation(0, 0,                Math.abs(initTop - current_Top), 0);        image_Anim.setDuration(200);        imageView.startAnimation(image_Anim);        imageView.layout(imageView.getLeft(), (int) initTop,                imageView.getRight(), (int) initBottom);        // 开启移动动画        TranslateAnimation inner_Anim = new TranslateAnimation(0, 0,                inner.getTop(), normal.top);        inner_Anim.setDuration(200);        inner.startAnimation(inner_Anim);        inner.layout(normal.left, normal.top, normal.right, normal.bottom);        normal.setEmpty();        /** 动画执行 **/        if (current_Top > initTop + 50 && turnListener != null)            turnListener.onTurn();    }    /** 是否需要开启动画 **/    public boolean isNeedAnimation() {        return !normal.isEmpty();    }    /***     * 执行翻转     *     * @author jia     *     */    public interface onTurnListener {        /** 必须达到一定程度才执行 **/        void onTurn();    }}

布局 如图

技术分享

<FrameLayout 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:background="#f4f4f4" >    <com.example.scrollviewdemo.PersonalScrollView        android:id="@+id/personalScrollView"        android:layout_width="wrap_content"        android:layout_height="wrap_content" >        <FrameLayout            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:orientation="vertical" >            <ImageView                android:id="@+id/iv_personal_bg"                android:layout_width="match_parent"                android:layout_height="300dip"                android:layout_marginTop="-50dip"                android:scaleType="centerCrop"                android:src="http://www.mamicode.com/@drawable/profiles_default_personal_bg" />            <LinearLayout                android:id="@+id/test"                android:layout_width="match_parent"                android:layout_height="wrap_content"                android:orientation="vertical" >                <LinearLayout                    android:id="@+id/mine_main_login"                    android:layout_width="match_parent"                    android:layout_height="wrap_content"                    android:gravity="center_horizontal"                    android:orientation="vertical"                    android:paddingTop="48dip" >                    <ImageView                        android:id="@+id/avatar"                        android:layout_width="60dip"                        android:layout_height="60dip"                        android:layout_marginTop="8dip"                        android:src="http://www.mamicode.com/@drawable/default_user_hole" />                    <LinearLayout                        android:id="@+id/mine_main_loginedly"                        android:layout_width="match_parent"                        android:layout_height="wrap_content"                        android:gravity="center_horizontal"                        android:orientation="vertical" >                        <TextView                            android:id="@+id/mine_main_nikename"                            android:layout_width="wrap_content"                            android:layout_height="40dip"                            android:layout_margin="0dip"                            android:background="@null"                            android:gravity="center"                            android:includeFontPadding="false"                            android:padding="0dip"                            android:text="用户名"                            android:textSize="14sp" />                        <LinearLayout                            android:layout_width="wrap_content"                            android:layout_height="40dip"                            android:gravity="center_horizontal"                            android:orientation="horizontal" >                            <TextView                                android:id="@+id/mine_main_phone"                                android:layout_width="wrap_content"                                android:layout_height="wrap_content"                                android:drawablePadding="3dip"                                android:text="151****6663"                                android:textSize="12sp" />                            <TextView                                android:id="@+id/mine_main_role"                                android:layout_width="wrap_content"                                android:layout_height="wrap_content"                                android:layout_marginLeft="30dip"                                android:drawablePadding="3dip"                                android:text="text特甜"                                android:textSize="12sp" />                        </LinearLayout>                    </LinearLayout>                                    </LinearLayout>                <LinearLayout android:layout_width="match_parent"                    android:layout_height="wrap_content"                    android:orientation="vertical">                <LinearLayout                    android:layout_width="match_parent"                    android:layout_height="wrap_content"                    android:background="#FFFFFF"                    android:paddingBottom="10dip"                    android:paddingLeft="15dip"                    android:paddingRight="15dip"                    android:paddingTop="10dip" >                    <LinearLayout                        android:layout_width="0dip"                        android:layout_height="62dip"                        android:layout_weight="1"                        android:gravity="center_vertical"                        android:orientation="horizontal" >                        <TextView                            android:id="@+id/mine_to_studyrecord"                            android:layout_width="0dip"                            android:layout_height="wrap_content"                            android:layout_marginLeft="8dip"                            android:layout_weight="1"                            android:background="@null"                            android:gravity="left|center_vertical"                            android:text="mine_main_tab1"                            android:textSize="13sp" />                    </LinearLayout>                    <LinearLayout                        android:layout_width="0dip"                        android:layout_height="62dip"                        android:layout_marginLeft="18dip"                        android:layout_weight="1"                        android:gravity="center_vertical"                        android:orientation="horizontal" >                        <TextView                            android:id="@+id/mine_to_myorder"                            android:layout_width="0dip"                            android:layout_height="wrap_content"                            android:layout_marginLeft="8dip"                            android:layout_weight="1"                            android:background="@null"                            android:gravity="left|center_vertical"                            android:text="mine_main_tab2"                            android:textSize="13sp" />                    </LinearLayout>                </LinearLayout>                <LinearLayout                     android:layout_width="match_parent"                    android:layout_height="wrap_content"                    android:background="#FFFFFF"                    android:orientation="vertical">                <TextView                    android:id="@+id/mine_to_mystore"                    android:layout_width="match_parent"                    android:layout_height="38dip"                    android:text="mine_main_mycollection" />                <TextView                    android:layout_width="match_parent"                    android:layout_height="38dip"                    android:text="mine_main_mycollection" />                <TextView                    android:layout_width="match_parent"                    android:layout_height="38dip"                    android:text="mine_main_mycollection" />                <TextView                    android:layout_width="match_parent"                    android:layout_height="38dip"                    android:text="mine_main_mycollection" />                <TextView                    android:layout_width="match_parent"                    android:layout_height="38dip"                    android:text="mine_main_mycollection" />                <TextView                    android:layout_width="match_parent"                    android:layout_height="38dip"                    android:text="mine_main_mycollection" />                <TextView                    android:layout_width="match_parent"                    android:layout_height="38dip"                    android:text="mine_main_mycollection" />                <TextView                    android:layout_width="match_parent"                    android:layout_height="38dip"                    android:text="mine_main_mycollection" />                <TextView                    android:layout_width="match_parent"                    android:layout_height="38dip"                    android:text="mine_main_mycollection" />                <TextView                    android:layout_width="match_parent"                    android:layout_height="38dip"                    android:text="mine_main_mycollection" />                <TextView                    android:layout_width="match_parent"                    android:layout_height="38dip"                    android:text="mine_main_mycollection" />                <TextView                    android:layout_width="match_parent"                    android:layout_height="38dip"                    android:text="mine_main_mycollection" />                </LinearLayout>                </LinearLayout>            </LinearLayout>        </FrameLayout>    </com.example.scrollviewdemo.PersonalScrollView>    <RelativeLayout        android:id="@+id/mine_title"        android:layout_width="match_parent"        android:layout_height="48dip" >        <TextView            android:id="@+id/common_title_left_text"            android:layout_width="wrap_content"            android:layout_height="fill_parent"            android:layout_alignParentLeft="true"            android:layout_centerVertical="true"            android:gravity="center"            android:paddingLeft="16dp"            android:paddingRight="16dp"            android:text="取消"            android:textColor="#FFFFFF" />        <TextView            android:id="@+id/common_title_middle"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_centerInParent="true"            android:ellipsize="marquee"            android:focusable="true"            android:focusableInTouchMode="true"            android:marqueeRepeatLimit="marquee_forever"            android:singleLine="true"            android:textSize="20sp" />    </RelativeLayout></FrameLayout>

  上面是布局的简单示意

 

android 自定义scrollview 仿QQ空间效果 下拉伸缩顶部图片,上拉回弹 上拉滚动顶部title 颜色渐变