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

  上面是布局的简单示意

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

  1. android开发学习 ------- 仿QQ侧滑效果的实现

    需要做一个仿QQ侧滑删除的一个效果: 一开始是毫无头绪,百度找思路,找到  https://blog.csdn.net/xiaxiazaizai01/article/details/53036994  ...

  2. JS仿QQ空间鼠标停在长图片时候图片自动上下滚动效果

    JS仿QQ空间鼠标停在长图片时候图片自动上下滚动效果 今天是2014年第一篇博客是关于类似于我们的qq空间长图片展示效果,因为一张很长的图片不可能全部把他展示出来,所以外层用了一个容器给他一个高度,超 ...

  3. Android 自定义ScrollView(具有反弹效果的ScrollView,能够兼容横向的滑动)

    package com.itau.jingdong.widgets; import android.content.Context; import android.graphics.Rect; imp ...

  4. Fragment,仿QQ空间

    转载请注明出处:http://blog.csdn.net/yangyu20121224/article/details/9023451          在今天的这篇文章当中,我依然会以实战加理论结合 ...

  5. 仿QQ空间和微信朋友圈,高解耦高复用高灵活

    先看看效果: 用极少的代码实现了 动态详情 及 二级评论 的 数据获取与处理 和 UI显示与交互,并且高解耦.高复用.高灵活. 动态列表界面MomentListFragment支持 下拉刷新与上拉加载 ...

  6. 仿QQ空间动态界面分享

    先看看效果: 用极少的代码实现了 动态详情 及 二级评论 的 数据获取与处理 和 UI显示与交互,并且高解耦.高复用.高灵活. 动态列表界面MomentListFragment支持 下拉刷新与上拉加载 ...

  7. android 自定义ScrollView实现背景图片伸缩(阻尼效果)

    android 自定义ScrollView实现强调内容背景图片伸缩(仿多米,qq空间背景的刷新) 看到一篇文章,自己更改了一下bug: 原文地址:http://www.aiuxian.com/arti ...

  8. Android 自定义ScrollView ListView 体验各种纵向滑动的需求

      分类: [android 进阶之路]2014-08-31 12:59 6190人阅读 评论(10) 收藏 举报 Android自定义ScrollView纵向拖动     转载请标明出处:http: ...

  9. iOS传感器集锦、飞机大战、开发调试工具、强制更新、Swift仿QQ空间头部等源码

    iOS精选源码 飞机大作战 MUPhotoPreview -简单易用的图片浏览器 LLDebugTool是一款针对开发者和测试者的调试工具,它可以帮... 多个UIScrollView.UITable ...

随机推荐

  1. Linux Svn 安装过程及配置

    重要的是第一步的安装,第二步配置可能没用,但是没试过,因为服务器上已经安装了第一步. 此处的第二步只为做个记录,说明一下里边的配置文件的用途. 3. 自己实际操作中的的配置记录(参照服务器别人的配置记 ...

  2. NLP学术组织、会与论文

    1. 自然语言处理怎么最快入门? 2. 初学者如何查阅自然语言处理(NLP)领域学术资料 2.0  ACL Anthology 2.1  Association for Computational L ...

  3. java_js_检查是否全为数字

    //检查所有输入文本都是数字类型 var len=blackNumber.length; var regExp=new RegExp("\\d{"+len+"}" ...

  4. vs2015 现用插件

    1.abphelper abp app自动生成接口和input output 2.ankhsvn svn插件 3.c#outline2015 大括号折叠 4.codemaid 格式化 5.go to ...

  5. js闭包使用

    闭包就是在一个函数内定义一个内部函数 并返回内部函数 function f1(){ var a=1; add=function(){a=a+1;} function f1Sub(){ console. ...

  6. FormatMessage与GetLastError配合使用,排查windows api调用过程中的错误

    前一段时间在学习windows api调用过程中,遇到过一些调用错误或者程序没能显示预期的结果,或者直接出现vc运行时错误. 这对新手来说是司空见惯的事,因为不太熟悉难免会出错,出错的信息如果能显示很 ...

  7. 淌水 UE4的shootergame 案例 准备

    从毕业到现在,从GIS到游戏. 先记录一下cesium源码研究停止了一个多月了,还是有点放不下,等有机会一定研究透彻.感谢一下法克鸡丝博主. 好,研究了近两个月的游戏整体制作,熟悉了maya\unfl ...

  8. 关于读取txt文件中文乱码问题

    在处理文件的过程中,读取txt文件出现中文乱码.这种情况是由于编码字符不一致导致. public static string ReadFile(string path, string fileName ...

  9. mongo基本操作

    创建数据库文件的存放位置,比如d:/mongodb/data/db.启动mongodb服务之前需要必须创建数据库文件的存放文件夹,否则命令不会自动创建,而且不能启动成功. 打开cmd(windows键 ...

  10. 02-Swift初体验

    Playground是什么? 从Xcode6开始出现(Swift开始出现) 翻译为:操场/游乐场 对于学习Swift基本语法非常方便 所见即所得(快速查看结果) 语法特性发生改变时,可以快速查看. S ...