Last active
August 29, 2015 14:05
-
-
Save ixiyang/7f0292dd1055adc15392 to your computer and use it in GitHub Desktop.
When the listview is scrolled to bottom,you can still scroll up to show the discoverview.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin" | |
android:paddingRight="@dimen/activity_horizontal_margin" | |
android:paddingTop="@dimen/activity_vertical_margin" | |
android:paddingBottom="@dimen/activity_vertical_margin" | |
tools:context=".MyActivity"> | |
<com.discoverlistview.xy.discoverlistview.DiscoverLayout | |
android:layout_width="match_parent" | |
android:layout_height="match_parent"> | |
<View | |
android:id="@+id/discoverview" | |
android:text="@string/hello_world" | |
android:background="@android:color/holo_red_light" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" /> | |
<ListView | |
android:id="@+id/listview" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="@android:color/holo_blue_light" /> | |
</com.discoverlistview.xy.discoverlistview.DiscoverLayout> | |
</RelativeLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.discoverlistview.xy.discoverlistview; | |
import android.content.Context; | |
import android.support.v4.view.ViewCompat; | |
import android.util.AttributeSet; | |
import android.view.MotionEvent; | |
import android.view.View; | |
import android.view.ViewConfiguration; | |
import android.view.ViewGroup; | |
import android.view.animation.AccelerateInterpolator; | |
import android.view.animation.Animation; | |
import android.view.animation.DecelerateInterpolator; | |
import android.view.animation.Transformation; | |
import android.widget.FrameLayout; | |
import android.widget.ListView; | |
/** | |
* Created by ixy on 2014/8/17. | |
*/ | |
public class DiscoverLayout extends FrameLayout { | |
private View mListView; | |
private View mDiscoverView; | |
private int mCurrentOffsetTop; | |
private int mTouchSlop; | |
private float mDownY; | |
private float mPreY; | |
private HideDiscoverViewAnimation mHideDiscoverViewAnim; | |
private ShowDiscoverViewAnimation mShowDiscoverViewAnim; | |
private int mMediumAnimationDuration; | |
private int mOriginalOffsetTop; | |
private int mShowDiscoverViewOffsetTop; | |
private int mFrom; | |
private boolean mIsListviewShown = true; | |
private boolean mIsHandled; | |
private final Animation.AnimationListener mHideDiscoverViewAnimListener = new BaseAnimationListener() { | |
@Override | |
public void onAnimationEnd(Animation animation) { | |
// Toast.makeText(getContext(), "reset", Toast.LENGTH_SHORT).show(); | |
mIsListviewShown = true; | |
mDiscoverView.setVisibility(View.INVISIBLE); | |
} | |
}; | |
private final Animation.AnimationListener mShowDiscoverViewAnimListener = new BaseAnimationListener() { | |
@Override | |
public void onAnimationEnd(Animation animation) { | |
// Toast.makeText(getContext(), "complete", Toast.LENGTH_SHORT).show(); | |
mIsListviewShown = false; | |
} | |
}; | |
public DiscoverLayout(Context context) { | |
this(context, null, 0); | |
} | |
public DiscoverLayout(Context context, AttributeSet attrs) { | |
this(context, attrs, 0); | |
} | |
public DiscoverLayout(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); | |
mHideDiscoverViewAnim = new HideDiscoverViewAnimation(); | |
mShowDiscoverViewAnim = new ShowDiscoverViewAnimation(); | |
mMediumAnimationDuration = getResources().getInteger(android.R.integer.config_mediumAnimTime); | |
} | |
@Override | |
public void addView(View child, int index, ViewGroup.LayoutParams params) { | |
super.addView(child, index, params); | |
} | |
@Override | |
protected void onFinishInflate() { | |
super.onFinishInflate(); | |
if (getChildCount() != 2) { | |
throw new IllegalStateException("must hava two child"); | |
} else { | |
View secondChild = getChildAt(1); | |
if (!(secondChild instanceof ListView)) { | |
throw new IllegalStateException("the sceond child must be a Listview"); | |
} | |
} | |
} | |
@Override | |
public boolean onInterceptTouchEvent(MotionEvent ev) { | |
// return super.onInterceptTouchEvent(ev); | |
switch (ev.getAction()) { | |
case MotionEvent.ACTION_DOWN: | |
mDownY = ev.getY(); | |
mPreY = ev.getY(); | |
return false; | |
case MotionEvent.ACTION_MOVE: | |
float y = ev.getY(); | |
float diffY = y - mDownY; | |
if (Math.abs(diffY) > mTouchSlop) { | |
if (mListView == null) { | |
mListView = getChildAt(1); | |
mOriginalOffsetTop = mListView.getTop(); | |
mShowDiscoverViewOffsetTop = mOriginalOffsetTop - getPaddingTop() - getPaddingBottom() - mListView.getHeight(); | |
} | |
if (mDiscoverView == null) { | |
mDiscoverView = getChildAt(0); | |
mDiscoverView.setVisibility(View.INVISIBLE); | |
} | |
if (mIsListviewShown) { | |
if (!ViewCompat.canScrollVertically(mListView, 1) && diffY < 0) { | |
return true; | |
} | |
} else { | |
if (!ViewCompat.canScrollVertically(mDiscoverView, -1) && diffY > 0) { | |
return true; | |
} | |
} | |
} | |
} | |
return false; | |
} | |
@Override | |
public boolean onTouchEvent(MotionEvent event) { | |
System.err.println("touch event"); | |
switch (event.getAction()) { | |
case MotionEvent.ACTION_DOWN: | |
System.err.println("action_down"); | |
mDownY = event.getY(); | |
mPreY = event.getY(); | |
break; | |
case MotionEvent.ACTION_MOVE: | |
System.err.println("action_move"); | |
float diffY = event.getY() - mDownY; | |
System.err.println("diffY====" + diffY); | |
if (Math.abs(diffY) > mTouchSlop) { | |
if (diffY > 0 && mIsListviewShown) { | |
mIsHandled = false; | |
} else if (diffY < 0 && !mIsListviewShown) { | |
mIsHandled = false; | |
} else { | |
mIsHandled = true; | |
setListviewOffsetTopAndBottom((int) (event.getY() - mPreY)); | |
showDiscoverView((int) (event.getY() - mDownY)); | |
} | |
} | |
mPreY = event.getY(); | |
break; | |
case MotionEvent.ACTION_CANCEL: | |
case MotionEvent.ACTION_UP: | |
if (mListView == null || !mIsHandled) return true; | |
if (mIsListviewShown) { | |
if (mListView.getBottom() < getHeight() * 2 / 3) { | |
animateToShowDiscoverView(mListView.getTop(), mShowDiscoverViewAnimListener); | |
} else { | |
animateToHideDiscoverView(mListView.getTop(), mHideDiscoverViewAnimListener); | |
} | |
} else { | |
if (mListView.getBottom() > getHeight() / 3) { | |
animateToHideDiscoverView(mListView.getTop(), mHideDiscoverViewAnimListener); | |
} else { | |
animateToShowDiscoverView(mListView.getTop(), mShowDiscoverViewAnimListener); | |
} | |
} | |
break; | |
} | |
return true; | |
} | |
private void setListviewOffsetTopAndBottom(int offset) { | |
if (mListView == null) { | |
mListView = getChildAt(getChildCount() - 1); | |
mOriginalOffsetTop = mListView.getTop(); | |
mShowDiscoverViewOffsetTop = mOriginalOffsetTop - getPaddingTop() - getPaddingBottom() - mListView.getHeight(); | |
} | |
System.err.println("offset=======" + offset); | |
mListView.offsetTopAndBottom(offset); | |
mCurrentOffsetTop = mListView.getTop(); | |
invalidate(); | |
} | |
private void showDiscoverView(int offset) { | |
mDiscoverView.setVisibility(View.VISIBLE); | |
float radio = Math.abs(offset) / (float) getHeight(); | |
if (radio > 0 && radio < 1) { | |
if (!mIsListviewShown) { | |
radio = Math.abs(1 - radio); | |
} | |
mDiscoverView.getBackground().setAlpha((int) (radio * 255)); | |
mDiscoverView.setScaleX(radio); | |
mDiscoverView.setScaleY(radio); | |
} | |
} | |
private void animateToHideDiscoverView(int from, Animation.AnimationListener listener) { | |
mFrom = from; | |
mHideDiscoverViewAnim.reset(); | |
mHideDiscoverViewAnim.setOffset(from); | |
mHideDiscoverViewAnim.setInterpolator(new DecelerateInterpolator()); | |
mHideDiscoverViewAnim.setDuration(mMediumAnimationDuration); | |
mHideDiscoverViewAnim.setAnimationListener(mHideDiscoverViewAnimListener); | |
mListView.startAnimation(mHideDiscoverViewAnim); | |
} | |
private void animateToShowDiscoverView(int from, Animation.AnimationListener listener) { | |
mFrom = from; | |
mShowDiscoverViewAnim.reset(); | |
mShowDiscoverViewAnim.setInterpolator(new AccelerateInterpolator()); | |
mShowDiscoverViewAnim.setDuration(mMediumAnimationDuration); | |
mShowDiscoverViewAnim.setAnimationListener(mShowDiscoverViewAnimListener); | |
mListView.startAnimation(mShowDiscoverViewAnim); | |
} | |
private class HideDiscoverViewAnimation extends Animation { | |
int offset; | |
public HideDiscoverViewAnimation() { | |
super(); | |
} | |
public void setOffset(int offset) { | |
this.offset = offset; | |
} | |
@Override | |
protected void applyTransformation(float interpolatedTime, Transformation t) { | |
System.err.println("from====" + mFrom); | |
System.err.println("moriginal======" + mOriginalOffsetTop); | |
int targetTop = 0; | |
if (mFrom != mOriginalOffsetTop) { | |
targetTop = (mFrom + (int) ((mOriginalOffsetTop - mFrom) * interpolatedTime)); | |
} | |
System.err.println("targetTop====" + targetTop); | |
int offset = targetTop - mListView.getTop(); | |
setListviewOffsetTopAndBottom(offset); | |
if (mIsListviewShown) { | |
showDiscoverView(mListView.getBottom() + getPaddingBottom() - getBottom()); | |
} else { | |
showDiscoverView(mListView.getBottom() + getPaddingBottom()); | |
} | |
} | |
} | |
private class ShowDiscoverViewAnimation extends Animation { | |
@Override | |
protected void applyTransformation(float interpolatedTime, Transformation t) { | |
int targetTop = 0; | |
if (mFrom != mShowDiscoverViewOffsetTop) { | |
targetTop = mFrom + (int) ((mShowDiscoverViewOffsetTop - mFrom) * interpolatedTime); | |
} | |
int offset = targetTop - mListView.getTop(); | |
setListviewOffsetTopAndBottom(offset); | |
if (mIsListviewShown) { | |
showDiscoverView(mListView.getBottom() + getPaddingBottom() - getBottom()); | |
} else { | |
showDiscoverView(mListView.getBottom() + getPaddingBottom()); | |
} | |
} | |
} | |
/** | |
* Simple AnimationListener to avoid having to implement unneeded methods in | |
* AnimationListeners. | |
*/ | |
private class BaseAnimationListener implements Animation.AnimationListener { | |
@Override | |
public void onAnimationStart(Animation animation) { | |
} | |
@Override | |
public void onAnimationEnd(Animation animation) { | |
} | |
@Override | |
public void onAnimationRepeat(Animation animation) { | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment