我使用以下自定义ListView进行橡皮筋效果,该效果仅从上到下拉伸图像。
我需要在两侧从上到下和从下到上拉伸图像。
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.ListView;
import java.util.ArrayList;
public class ParallaxListView extends ListView implements OnScrollListener {
public final static double NO_ZOOM = 1;
private ArrayList<OnOverScrollByListener> mOnOverScrollByList = new ArrayList<OnOverScrollByListener>();
private ArrayList<OnTouchEventListener> mOnTouchEventList = new ArrayList<OnTouchEventListener>();
private ImageView mImageView;
private int mDrawableMaxHeight = -1;
private int mImageViewHeight = -1;
private OnOverScrollByListener scrollByListener = new OnOverScrollByListener() {
@Override
public boolean overScrollBy(int deltaX, int deltaY, int scrollX,
int scrollY, int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
if (mImageView.getHeight() <= mDrawableMaxHeight && isTouchEvent) {
if (deltaY < 0) {
if (mImageView.getHeight() - deltaY / 2 >= mImageViewHeight) {
mImageView.getLayoutParams().height = mImageView
.getHeight() - deltaY / 2 < mDrawableMaxHeight ? mImageView
.getHeight() - deltaY / 2
: mDrawableMaxHeight;
mImageView.requestLayout();
}
} else {
if (mImageView.getHeight() > mImageViewHeight) {
mImageView.getLayoutParams().height = mImageView
.getHeight() - deltaY > mImageViewHeight ? mImageView
.getHeight() - deltaY
: mImageViewHeight;
mImageView.requestLayout();
return true;
}
}
}
return false;
}
};
private OnTouchEventListener touchListener = new OnTouchEventListener() {
@Override
public void onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_UP) {
if (mImageViewHeight - 1 < mImageView.getHeight()) {
ResetAnimimation animation = new ResetAnimimation(
mImageView, mImageViewHeight);
animation.setDuration(300);
mImageView.startAnimation(animation);
}
}
}
};
private OnOverScrollByListener onScroll = new OnOverScrollByListener() {
@Override
public boolean overScrollBy(int deltaX, int deltaY, int scrollX,
int scrollY, int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
if (mImageView.getHeight() <= mDrawableMaxHeight && isTouchEvent) {
if (deltaY < 0) {
if (mImageView.getHeight() - deltaY / 2 >= mImageViewHeight) {
mImageView.getLayoutParams().height = mImageView
.getHeight() - deltaY / 2 < mDrawableMaxHeight ? mImageView
.getHeight() - deltaY / 2
: mDrawableMaxHeight;
mImageView.requestLayout();
}
} else {
if (mImageView.getHeight() > mImageViewHeight) {
mImageView.getLayoutParams().height = mImageView
.getHeight() - deltaY > mImageViewHeight ? mImageView
.getHeight() - deltaY
: mImageViewHeight;
mImageView.requestLayout();
return true;
}
}
}
return false;
}
};
private OnTouchEventListener onTouched = new OnTouchEventListener() {
@Override
public void onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_UP) {
if (mImageViewHeight - 1 < mImageView.getHeight()) {
BackAnimimation animation = new BackAnimimation(mImageView,
mImageViewHeight, false);
animation.setDuration(300);
mImageView.startAnimation(animation);
}
}
}
};
private double mZoomRatio = 1;
public ParallaxListView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
public ParallaxListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public ParallaxListView(Context context) {
super(context);
init(context, null);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
public void setParallaxImageView(ImageView iv) {
mImageView = iv;
mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
}
private void init(Context context, AttributeSet attrs) {
if (attrs != null) {
TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
R.styleable.ParallaxScrollView, 0, 0);
mZoomRatio = a
.getFloat(R.styleable.ParallaxScrollView_zoomRatio, 1);
}
post(new Runnable() {
@Override
public void run() {
setViewsBounds(mZoomRatio);
}
});
}
@Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX,
int scrollY, int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
boolean isCollapseAnimation = false;
Logger.LOGE("overScrollBy",""+true);
for (int i = 0; i < mOnOverScrollByList.size(); i++) {
isCollapseAnimation = mOnOverScrollByList.get(i).overScrollBy(
deltaX, deltaY, scrollX, scrollY, scrollRangeX,
scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent)
|| isCollapseAnimation;
}
return isCollapseAnimation ? true : super.overScrollBy(deltaX, deltaY,
scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX,
maxOverScrollY, isTouchEvent);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
Logger.LOGE("onTouchEvent",ev.toString());
for (int i = 0; i < mOnTouchEventList.size(); i++) {
mOnTouchEventList.get(i).onTouchEvent(ev);
}
return super.onTouchEvent(ev);
}
/**
* Set the ImageView that will be used in the parallax changing his
* {@link ImageView.ScaleType} to CENTER_CROP.
*
* @paramview - An {@link ImageView} that will have the parallax effect.
*/
public void setImageViewToParallax(ImageView imageView) {
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
mImageView = imageView;
addOnScrolledListener(onScroll);
addOnTouchListener(onTouched);
}
private void addOnScrolledListener(OnOverScrollByListener onScrolled) {
Logger.LOGE("addOnScrolledLi",onScrolled.toString());
mOnOverScrollByList.add(onScrolled);
}
private void addOnTouchListener(OnTouchEventListener onTouched) {
Logger.LOGE("addOnTouchListener",onTouched.toString());
mOnTouchEventList.add(onTouched);
}
/**
* Set the bounds of the views and set the zoom of the view.
* <p/>
* Necessary to get the size of the Views.
* <p/>
* Have to put in the {@link #onWindowFocusChanged(boolean)} of the
* activity.
*
* @param zoomRatio Double - How many times is the max zoom of the image, minimum
* 1.
*/
public void setViewsBounds(double zoomRatio) {
if (mImageViewHeight == -1) {
mImageViewHeight = mImageView.getHeight();
double imageRatio = ((double) mImageView.getDrawable()
.getIntrinsicWidth()) / ((double) mImageView.getWidth());
mDrawableMaxHeight = (int) ((mImageView.getDrawable()
.getIntrinsicHeight() / imageRatio) * (zoomRatio > 1 ? zoomRatio
: 1));
}
}
private interface OnOverScrollByListener {
public boolean overScrollBy(int deltaX, int deltaY, int scrollX,
int scrollY, int scrollRangeX, int scrollRangeY,
int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent);
}
private interface OnTouchEventListener {
public void onTouchEvent(MotionEvent ev);
}
public class ResetAnimimation extends Animation {
int targetHeight;
int originalHeight;
int extraHeight;
View mView;
protected ResetAnimimation(View view, int targetHeight) {
this.mView = view;
this.targetHeight = targetHeight;
originalHeight = view.getHeight();
extraHeight = this.targetHeight - originalHeight;
}
@Override
protected void applyTransformation(float interpolatedTime,
Transformation t) {
int newHeight;
newHeight = (int) (targetHeight - extraHeight
* (1 - interpolatedTime));
mView.getLayoutParams().height = newHeight;
mView.requestLayout();
}
}
}
用于拉伸图像的attr.xml,它基于zoomRatio:
<resources>
<declare-styleable name="ParallaxScrollView">
<attr name="zoomRatio" format="float" />
</declare-styleable>
<declare-styleable name="JazzyViewPager">
<attr name="style">
<enum name="standard" value="0" />
<enum name="tablet" value="1" />
<enum name="cubein" value="2" />
<enum name="cubeout" value="3" />
<enum name="flipvertical" value="4" />
<enum name="fliphorizontal" value="5" />
<enum name="stack" value="6" />
<enum name="zoomin" value="7" />
<enum name="zoomout" value="8" />
<enum name="rotateup" value="9" />
<enum name="rotatedown" value="10" />
<enum name="accordion" value="11" />
</attr>
<attr name="fadeEnabled" format="boolean" />
<attr name="outlineEnabled" format="boolean" />
<attr name="outlineColor" format="color|reference" />
</declare-styleable>
<declare-styleable name="ScrimInsetsView">
<attr name="insetForeground" format="reference|color" />
</declare-styleable>
<declare-styleable name="CircleImageView">
<attr name="civ_border_width" format="dimension" />
<attr name="civ_border_color" format="color" />
<attr name="civ_border_overlay" format="boolean" />
<attr name="civ_fill_color" format="color" />
</declare-styleable>
</resources>
感谢。