首先要知道  自定义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="@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="@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>

  上面是布局的简单示意