Skip to content

Instantly share code, notes, and snippets.

@ixiyang
Last active August 29, 2015 14:05
Show Gist options
  • Save ixiyang/7f0292dd1055adc15392 to your computer and use it in GitHub Desktop.
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.
<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>
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