先上个图
原理不难,直接上代码:(当前代码不支持android2.3和2.3以下的版本)
/********************************************************************
* Copyright : 新英体育传媒集团 © 2013 ssports.com 版权所有
*
* Filename : .java
* Author : zhangxyfs
* Date : 2013-3-8
* Version : V1.00
* Description :
*
* History : Modify Id | Date | Origin | Description
*******************************************************************/
package com.scrollLayout;
import java.util.ArrayList;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.Scroller;
import android.widget.Toast;
@SuppressLint("NewApi")
public class ScrollLayout extends RelativeLayout {
private static final String TAG = "ScrollLayout";
private Context _context;
private Scroller _scroller;
/** 所有的子视图(正常的排序) */
private ArrayList<View> _childViewList;
/** 所有的子视图(为了显示层叠效果而生成的排序方式) */
private ArrayList<View> _sortChildViewList;
/** 屏幕上可以看到的视图+2, 例如:屏幕上有5个屏幕外有2个 */
private ArrayList<View> _visiableChildViewList;
/** 上移标识 */
private static final int MOVETOUP = 0x100;
/** 下移标识 */
private static final int MOVETODOWN = 0x200;
/** 默认屏幕上视图的个数(自动+2) */
private int _visiableChildViewNumber = 7;
/** 所有可见子视图缩放比例 列表 */
private ArrayList<Float> _childScaleList;
/** 所有可见子视图透明度列表 */
private ArrayList<Float> _childAlphaList;
/** 移动时候的缩放列表 */
private ArrayList<Float> _childMoveToScaleList;
/** 移动时候的透明度列表 */
private ArrayList<Float> _childMoveToAlphaList;
/** 所有可见子视图height */
private ArrayList<Float> _childHeightList;
/** 到中心的距离列表(中心以上是到中心上标,以下是到中心下标) */
private ArrayList<Float> _childYList;
/** 最大放大比例 */
private float _maxScale = 1.5f;
/** 相邻比例间差值 */
private float _scaleDVale = 0.2f;
/** 最大的透明度 */
private float _maxAlpha = 1f;
/** 相邻透明度间差值 */
private float _alphaDVale = 0.2f;
/** 最后一次滑动的距离 */
private float _lastionMotionY = 0;
/** 移动距离 */
private int move = 0;
/** 跳转activity需要 */
private Activity _fromActivity = null;
/** 跳转activity需要 */
private Class _toClass = null;
/** 跳转传参标识 */
private String _flag = null;
/** 跳转要传递的参数 */
private int _value = 0;
/** 屏幕的高度 */
private float _screenHeight = 1230f;
public ScrollLayout(Context context) {
super(context);
_context = context;
_scroller = new Scroller(context);
}
public ScrollLayout(Context context, AttributeSet attrs) {
super(context, attrs);
_context = context;
_scroller = new Scroller(context);
}
public ScrollLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
_context = context;
_scroller = new Scroller(context);
}
/** 自定义屏幕上显示子视图的个数(默认为5) */
public void setVisiableViewNumber(int visiableViewNumber) {
if (visiableViewNumber % 2 == 0) {
Toast.makeText(_context, "显示在屏幕上的子视图个数不能为偶数", Toast.LENGTH_SHORT).show();
} else {
this._visiableChildViewNumber = visiableViewNumber + 2;
}
}
/** 设置屏幕的高度 */
public void setScreenHeight(float sh) {
_screenHeight = sh;
}
/**
* 初始化
*
* @param viewList
* 子视图列表
* @param activity
* 跳转activity需要
* @param clzz
* 跳转activity需要
* @param flag
* 跳转传参标识
* @param value
* 跳转要传递的参数
*/
public void init(ArrayList<View> viewList, Activity fromActivity, Class toClass, String flag, int value) {
_fromActivity = fromActivity;
_toClass = toClass;
_flag = flag;
_value = value;
_childViewList = viewList;
initView();
}
/**
* 初始化
*
* @param viewList
* 子视图列表
* @param fromActivity
* 跳转activity需要
* @param toClass
* 跳转activity需要
*/
public void init(ArrayList<View> viewList, Activity fromActivity, Class toClass) {
_fromActivity = fromActivity;
_toClass = toClass;
_childViewList = viewList;
initView();
}
/**
* 初始化
*
* @param viewList
* 子视图列表
*/
public void init(ArrayList<View> viewList) {
_childViewList = viewList;
initView();
}
/**
* 初始化子视图
*/
private void initView() {
sortView();
createVisiableChildView();
addVisiableChildView();
createVisiableChildScaleList();
createVisiableChildAlphaList();
}
/**
* 设置可见视图(_visiableChildViewList)的缩放比例和透明度
*
* @param scale
* 最大放大比例
* @param dValue
* 相邻比例间差值
* @param maxAlpha
* 最大透明度
* @param alphaDVale
* 相邻透明度间差值
*/
public void setVisiableChildScale(float scale, float scaleDValue, float maxAlpha, float alphaDVale) {
_maxScale = scale;
_scaleDVale = _alphaDVale;
_maxAlpha = maxAlpha;
_alphaDVale = alphaDVale;
}
/**
* 生成可见视图(_visiableChildViewList)透明度列表(中间为1)
*/
private void createVisiableChildAlphaList() {
_childAlphaList = new ArrayList<Float>();
for (int i = _visiableChildViewList.size() / 2; i >= 0; i--) {
_childAlphaList.add(_maxAlpha - (float) i * _alphaDVale);
_childAlphaList.add(_maxAlpha - (float) i * _alphaDVale);
}
_childAlphaList.remove(_childAlphaList.size() - 1);
}
/**
* 生成可见视图(_visiableChildViewList)的缩放列表
*/
private void createVisiableChildScaleList() {
_childScaleList = new ArrayList<Float>();
for (int i = _visiableChildViewList.size() / 2; i >= 0; i--) {
_childScaleList.add(_maxScale - (float) i * _scaleDVale);
_childScaleList.add(_maxScale - (float) i * _scaleDVale);
}
_childScaleList.remove(_childScaleList.size() - 1);
}
/**
* 生成可见视图(_visiableChildViewList)高度列表
*/
private void createVisiableChildHeightList(ArrayList<Float> childScaleList) {
_childHeightList = new ArrayList<Float>();
float height = getChildAt(0).getMeasuredHeight();
for (int i = 0; i < _visiableChildViewList.size(); i++) {
_childHeightList.add(height * childScaleList.get(i));
}
}
/**
* 生成可见视图(_visiableChildViewList)Y坐标
*/
private void createVisiableChildYList() {
_childYList = new ArrayList<Float>();
float value = Math.abs(_screenHeight - getY() - getMeasuredHeight() - getY());
float centerChildUpY = ((float) getMeasuredHeight() - _childHeightList.get(_childHeightList.size() - 1)) / 2f;
float centerChildDownY = centerChildUpY + _childHeightList.get(_childHeightList.size() - 1);
for (int i = 0; i < _visiableChildViewList.size() - 1; i = i + 2) {
float height = 0;
for (int j = i; j < _visiableChildViewList.size() - 1; j = j + 2) {
height += _childHeightList.get(j) * 3 / 4;
}
_childYList.add(centerChildUpY - height + getY());
height = 0;
for (int j = i + 1; j < _visiableChildViewList.size() - 1; j = j + 2) {
height += _childHeightList.get(j) * 3 / 4;
}
_childYList.add(centerChildDownY + height - _childHeightList.get(i + 1) + value);
}
_childYList.add(centerChildUpY + getY());
}
/**
* 将子视图列表(_childViewList)重新排序,生成(_sortChildViewList)
*/
private void sortView() {
_sortChildViewList = new ArrayList<View>();
ArrayList<View> temp = new ArrayList<View>();
copyList(_childViewList, temp);
// 如果子视图列表size是偶数
if (temp.size() % 2 == 0) {
_sortChildViewList.add(temp.get(0));
temp.remove(0);
}
while (temp.size() > 1) {
_sortChildViewList.add(temp.get(0));
_sortChildViewList.add(temp.get(temp.size() - 1));
temp.remove(0);
temp.remove(temp.size() - 1);
}
if (temp.size() == 1) {
_sortChildViewList.add(temp.get(0));
}
}
/**
* 生成可见视图(_visiableChildViewList)
*/
private void createVisiableChildView() {
_visiableChildViewList = new ArrayList<View>();
int start = _sortChildViewList.size() - _visiableChildViewNumber;
for (int i = start; i < _sortChildViewList.size(); i++) {
_visiableChildViewList.add(_sortChildViewList.get(i));
}
}
/**
* 删除原有子视图,装载可见视图(_visiableChildViewList)到父视图中
*/
private void addVisiableChildView() {
removeAllViews();
for (int i = 0; i < _visiableChildViewList.size(); i++) {
addView(_visiableChildViewList.get(i));
}
}
/**
* 循环排列子视图列表(_childViewList)重新生成可见视图并装载到父视图中
*
* @param moveDirection
* 移动方向
*/
private void cycleSortChildViews(int moveDirection) {
ArrayList<View> temp = new ArrayList<View>();
View view;
if (moveDirection == MOVETOUP) {
view = _childViewList.get(0);
_childViewList.remove(0);
_childViewList.add(view);
}
if (moveDirection == MOVETODOWN) {
view = _childViewList.get(_childViewList.size() - 1);
_childViewList.remove(_childViewList.size() - 1);
temp.add(view);
copyList(_childViewList, temp);
_childViewList = temp;
}
}
/**
* 子视图放大或缩小
*
* @param scale
*/
private void scaleChildView(int position, float scale) {
getChildAt(position).setScaleX(scale);
getChildAt(position).setScaleY(scale);
}
/** 获取子视图左面的坐标 */
private int getChildViewLeft(int position) {
return (getMeasuredWidth() - getChildAt(position).getMeasuredWidth()) / 2;
}
/** 获取子视图右面的坐标 */
private int getChildViewRight(int position) {
return getChildViewLeft(position) + getChildAt(position).getMeasuredWidth();
}
/** 获得子视图的高度 */
private int getChildViewHeight(int position) {
return getChildAt(position).getMeasuredHeight();
}
/** 获取中间子视图上面的坐标 */
private int getCenterChildViewTop() {
return (getMeasuredHeight() - getChildAt(getChildCount() - 1).getMeasuredHeight()) / 2;
}
/** 获取中间子视图下面的坐标 */
private int getCenterChildViewBottom() {
return getCenterChildViewTop() + getChildAt(getChildCount() - 1).getMeasuredHeight();
}
/**
* 实现移动
*
* @param dy
*/
private void moveTo(int dy) {
scrollBy(0, dy);
move += dy;
// 下移
if (move < 0) {
_childMoveToScaleList = createMoveToProperty(move, _childScaleList, _scaleDVale, 0f);
_childMoveToAlphaList = createMoveToProperty(move, _childAlphaList, _alphaDVale, 1f);
scaleAlphaAndMoveChild();
if (_childMoveToScaleList.get(_childMoveToScaleList.size() - 3) > _maxScale) {
cycleSortChildViews(MOVETODOWN);
sortView();
createVisiableChildView();
addVisiableChildView();
createVisiableChildScaleList();
createVisiableChildAlphaList();
scrollBy(0, -move);
move = 0;
requestLayout();
}
}
// 上移
if (move >= 0) {
_childMoveToScaleList = createMoveToProperty(move, _childScaleList, _scaleDVale, 0f);
_childMoveToAlphaList = createMoveToProperty(move, _childAlphaList, _alphaDVale, 1f);
scaleAlphaAndMoveChild();
if (_childMoveToScaleList.get(_childMoveToScaleList.size() - 2) > _maxScale) {
cycleSortChildViews(MOVETOUP);
sortView();
createVisiableChildView();
addVisiableChildView();
createVisiableChildScaleList();
createVisiableChildAlphaList();
scrollBy(0, -move);
move = 0;
requestLayout();
}
}
}
/**
* 实现动画(移动,透明度变化,缩放)
*/
private void scaleAlphaAndMoveChild() {
if (_childMoveToScaleList.size() > 2 && _childMoveToAlphaList.size() > 2) {
for (int i = 0; i < getChildCount(); i++) {
scaleChildView(i, _childMoveToScaleList.get(i));
getChildAt(i).setAlpha(_childMoveToAlphaList.get(i));
}
createVisiableChildHeightList(_childMoveToScaleList);
createVisiableChildYList();
toLayout();
}
}
/**
* 生成移动时候的属性(透明度列表或缩放列表)
*
* @param move
* 移动距离
* @param propertyList
* _childScaleList或者_childAlphaList
* @param dValue
* 差值
* @param centerProperty
* 中间的值
* @return 移动时候需要生成的列表
*/
private ArrayList<Float> createMoveToProperty(int move, ArrayList<Float> propertyList, float dValue,
float centerProperty) {
ArrayList<Float> moveToList = new ArrayList<Float>();
ArrayList<Float> tempA = new ArrayList<Float>();
ArrayList<Float> tempB = new ArrayList<Float>();
int tempMove = Math.abs(move);
float property = 0f;
int end = propertyList.size() - 1;
// 向下移动
if (move < 0) {
for (int i = 0; i < _childHeightList.size() - 1; i = i + 2) {
property = dValue / (_childHeightList.get(i + 2) - _childHeightList.get(i) / 4) * (float) tempMove
+ propertyList.get(i);
tempA.add(property);
}
for (int i = 1; i < _childHeightList.size(); i = i + 2) {
if (i == 1) {
property = propertyList.get(1);
} else {
property = propertyList.get(i) - dValue
/ (_childHeightList.get(i - 2) - _childHeightList.get(i) / 4) * (float) tempMove;
}
tempB.add(property);
}
centerProperty = propertyList.get(end) - dValue
/ (_childHeightList.get(end - 1) - _childHeightList.get(end) / 4) * (float) tempMove;
}
// 向上移动
if (move >= 0) {
for (int i = 0; i < _childHeightList.size() - 1; i = i + 2) {
if (i == 0) {
property = propertyList.get(0);
} else {
property = propertyList.get(i) - dValue
/ (_childHeightList.get(i - 2) - _childHeightList.get(i) / 4) * (float) tempMove;
}
tempA.add(property);
// Log.e(TAG, scale+"");
}
for (int i = 1; i < _childHeightList.size(); i = i + 2) {
if (i + 2 < _childHeightList.size()) {
property = dValue / (_childHeightList.get(i + 2) - _childHeightList.get(i) / 4) * (float) tempMove
+ propertyList.get(i);
} else {
property = dValue / (_childHeightList.get(i + 1) - _childHeightList.get(i) / 4) * (float) tempMove
+ propertyList.get(i);
}
tempB.add(property);
}
centerProperty = propertyList.get(end) - dValue
/ (_childHeightList.get(end) - _childHeightList.get(end - 1) / 4) * (float) tempMove;
}
for (int i = 0; i < tempA.size(); i++) {
moveToList.add(tempA.get(i));
moveToList.add(tempB.get(i));
}
moveToList.add(centerProperty);
return moveToList;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// 手指位置地点
float Y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 如果屏幕的动画还没结束,你就按下了,我们就结束该动画
if (_scroller != null) {
if (!_scroller.isFinished()) {
_scroller.abortAnimation();
}
}
_lastionMotionY = Y;
break;
case MotionEvent.ACTION_MOVE:
moveTo((int) (_lastionMotionY - Y));
_lastionMotionY = Y;
break;
case MotionEvent.ACTION_UP:
if (_fromActivity != null && _toClass != null) {
if (Math.abs(Y - event.getY()) < 5) {
if ((event.getY() > getCenterChildViewTop() && event.getY() < getCenterChildViewBottom())
&& (event.getX() > getChildViewLeft(getChildCount() - 1) && event.getX() < getChildViewRight(getChildCount() - 1))) {
if (_flag != null) {
openActivity(_fromActivity, _toClass, _flag, _value);
} else {
openActivity(_fromActivity, _toClass);
}
}
}
}
// 下移
if (move < 0) {
scrollBy(0, -move);
move = 0;
requestLayout();
}
// 上移
if (move > 0) {
scrollBy(0, -move);
move = 0;
requestLayout();
}
break;
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
/**
* 只有当前LAYOUT中的某个CHILD导致SCROLL发生滚动,才会致使自己的COMPUTESCROLL被调用
*/
@Override
public void computeScroll() {
// 如果返回true,表示动画还没有结束
// 因为前面startScroll,所以只有在startScroll完成时 才会为false
if (_scroller.computeScrollOffset()) {
// 产生了动画效果 每次滚动一点
scrollTo(_scroller.getCurrX(), _scroller.getCurrY());
// 刷新View 否则效果可能有误差
postInvalidate();
}
}
// measure过程
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
measureChildren(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(width, height);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
createVisiableChildHeightList(_childScaleList);
createVisiableChildYList();
toLayout();
for (int i = 0; i < getChildCount(); i++) {
scaleChildView(i, _childScaleList.get(i));
}
for (int i = 0; i < getChildCount(); i++) {
getChildAt(i).setAlpha(_childAlphaList.get(i));
}
}
/**
* 重新刷新子视图的位置
*/
private void toLayout() {
for (int i = 0; i < getChildCount(); i += 2) {
getChildAt(i).layout(getChildViewLeft(i), (int) Math.rint(_childYList.get(i)), getChildViewRight(i),
(int) Math.rint(_childYList.get(i)) + getChildViewHeight(i));
if (i + 1 < getChildCount()) {
getChildAt(i + 1).layout(getChildViewLeft(i + 1), (int) Math.rint(_childYList.get(i + 1)),
getChildViewRight(i + 1), (int) Math.rint(_childYList.get(i + 1)) + getChildViewHeight(i + 1));
}
}
}
/**
* 测试输出用
*
* @param list
* @param str
*/
private void LOG(ArrayList list, String str) {
for (int i = 0; i < list.size(); i++) {
Log.e(TAG, list.get(i) + str);
}
}
/**
* 拷贝列表
*
* @param from
* @param to
*/
private void copyList(ArrayList from, ArrayList to) {
for (int i = 0; i < from.size(); i++) {
to.add(from.get(i));
}
}
/**
* 打开新的页面
*
* @param activity
* @param clzz
* @param strValue
* @param value
*/
private void openActivity(Activity activity, Class clzz, String strValue, int value) {
Intent intent = new Intent(activity, clzz);
intent.putExtra(strValue, value);
activity.startActivity(intent);
System.gc();
}
/**
* 打开新的页面
*
* @param activity
* @param clzz
*/
private void openActivity(Activity activity, Class clzz) {
activity.startActivity(new Intent(activity, clzz));
}
}
调用方式:
<com.scrollLayout.ScrollLayout
android:id="@+id/scrollLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
private ScrollLayout scrollLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
scrollLayout = (ScrollLayout) findViewById(R.id.scrollLayout);
scrollLayout.setScreenHeight(1230f);
scrollLayout.setVisiableViewNumber(5);
scrollLayout.setVisiableChildScale(1.7f, 0.2f, 1f, 0.2f);
scrollLayout.init(getViewList());
}
说明:
scrollLayout.setScreenHeight(1230f); 这个参数需要传入的高度为 屏幕的高度-状态条高度-title的高度, 默认为1230
scrollLayout.setVisiableViewNumber(5);可以设置可见的子视图数量,默认为5
scrollLayout.setVisiableChildScale(1.7f, 0.2f, 1f, 0.2f);设置可见视图的缩放比例和透明度
scrollLayout.init(getViewList());初始化,需要传入子视图列表,有3种初始化方式,直接看代码好了,注释写的很清楚,需要注意的是,应该在设置完基本参数后进行初始化
下载地址:
下载地址的代码有点问题,需要重新设置scrollLayout.setScreenHeight(xxxf)