我必须为我的ListView
实现Parallax
动画和Swipe to refresh
。当向下拖动列表视图时,列表视图头部图像应该显示视差动画。当视差动画超过限制时,列表视图应该显示滑动刷新指示。我知道使用setRefreshing(true)
是可能的。但是使用这个方法不会显示刷新指示器的动画,比如从顶部滑动。
所以有任何方法显示刷新指示器默认动画在运行时?
<RelativeLayout
android:id="@+id/layoutListing"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.xxx.views.ParallaxListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadingEdge="none"
android:overScrollMode="never" >
</com.xxx.views.ParallaxListView>
</android.support.v4.widget.SwipeRefreshLayout>
</RelativeLayout>
public class ParallaxListView extends ListView implements OnScrollListener {
public final static double ZOOM_X2 = 2;
private Context context = null;
private ImageView mImageView;
private int mDrawableMaxHeight = -1;
private int mImageViewHeight = -1;
private int mDefaultImageViewHeight = 0;
private double mZoomRatio;
private int firstVisibleItem =0;
private int lastTopValueAssigned;
private Handler uiHandler = new Handler();
private boolean isRefreshListView = false;
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);
}
/**
*
* Constructor for ParallaxListView.
* @param context
* @param attrs
* @param defStyle
*/
public ParallaxListView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
init(context);
}
/**
*
* Constructor for ParallaxListView.
* @param context
* @param attrs
*/
public ParallaxListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ParallaxListView(Context context) {
super(context);
init(context);
}
public void init(Context context) {
this.context = context;
//setOnScrollListener(this);
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mDefaultImageViewHeight = context.getResources().getDrawable(R.drawable.dflt,context.getTheme()).getIntrinsicHeight();
} else {
mDefaultImageViewHeight = context.getResources().getDrawable(R.drawable.dflt).getIntrinsicHeight();
}
} catch (Exception e) {
}
}
/*
* (non-Javadoc)
* @see android.widget.AbsListView#onLayout(boolean, int, int, int, int)
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
new Handler().post(new Runnable() {
@Override
public void run() {
initViewsBounds(mZoomRatio);
}
});
}
/*
* (non-Javadoc)
* @see android.widget.AbsListView.OnScrollListener#onScrollStateChanged(android.widget.AbsListView, int)
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
/*
* (non-Javadoc)
* @see android.view.View#overScrollBy(int, int, int, int, int, int, int, int, boolean)
*/
@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;
isCollapseAnimation = scrollByListener.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 void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
this.firstVisibleItem = firstVisibleItem;
parallaxImage(mImageView);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if(mImageView != null){
View firstView = (View) mImageView.getParent();
// firstView.getTop < getPaddingTop means mImageView will be covered by top padding,
// so we can layout it to make it shorter
if (firstView.getTop() < getPaddingTop() && mImageView.getHeight() > mImageViewHeight) {
mImageView.getLayoutParams().height = Math.max(mImageView.getHeight() - (getPaddingTop() - firstView.getTop()), mImageViewHeight);
// to set the firstView.mTop to 0,
// maybe use View.setTop() is more easy, but it just support from Android 3.0 (API 11)
firstView.layout(firstView.getLeft(), 0, firstView.getRight(), firstView.getHeight());
mImageView.requestLayout();
}
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
touchListener.onTouchEvent(ev);
return super.onTouchEvent(ev);
}
public void setParallaxImageView(ImageView iv) {
try {
mImageView = iv;
mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
} catch (Exception e) {
}
}
private void initViewsBounds(double zoomRatio) {
if (mImageViewHeight == -1) {
mImageViewHeight = mImageView.getMeasuredHeight();
if (mImageViewHeight <= 0) {
mImageViewHeight = mDefaultImageViewHeight;
}
double ratio = ((double) mImageView.getDrawable().getIntrinsicWidth()) / ((double) mImageView.getWidth());
mDrawableMaxHeight = (int) ((mImageView.getDrawable().getIntrinsicHeight() / ratio) * (zoomRatio > 1 ?
zoomRatio : 1));
}
}
public void setZoomRatio(double zoomRatio) {
mZoomRatio = zoomRatio;
}
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) {
if(mImageView.getHeight() > (mDrawableMaxHeight * 0.70)){
//here i want to show refresh indicator
}
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 void fireSwipeToRefresh(){
if(!isRefreshListView){
uiHandler.post(new Runnable() {
@Override
public void run() {
isRefreshListView = true;
Intent intent = new Intent(INTENT_ACTION_SWIPE_TO_REFRESH);
intent.putExtra(INTENT_EXTRA_FIRST_VISIBLE_INDEX, firstVisibleItem);
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
}
}) ;
}
}
private OnTouchEventListener touchListener = new OnTouchEventListener() {
@Override
public void onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_UP) {
isRefreshListView = false;
if (mImageViewHeight - 1 < mImageView.getHeight()) {
ResetAnimimation animation = new ResetAnimimation(
mImageView, mImageViewHeight);
animation.setDuration(400);
animation.setInterpolator(new DecelerateInterpolator());
mImageView.startAnimation(animation);
}
}
}
};
public class ResetAnimimation extends Animation {
private int targetHeight;
private int originalHeight;
private int extraHeight;
private 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();
}
}
}
把你的listView放到你的滑动中,像这样刷新布局。
<LinearLayout
android:id="@+id/images_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/imagesList"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="05dp"
android:layout_marginTop="05dp"
android:divider="@android:color/transparent"
android:dividerHeight="0.0sp" />
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>