package com.tiger.quicknews.wedget.discrollview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ScrollView;
/**
* Layout container for a View hierarchy that can discrollved (ie
* Discrollvable). For each discrollvables, if it's possible (ie enough space to
* scroll the whole view), the discrollvable starts to be discrollved when its
* center reaches the center of the DiscrollView; else, the discrollvables
* starts to be discrollved when its top reaches the bottom of the DiscrollView
*
* @see com.flavienlaurent.discrollview.lib.Discrollvable
* @see com.flavienlaurent.discrollview.lib.DiscrollViewContent
*/
public class DiscrollView extends ScrollView {
private DiscrollViewContent mContent;
public DiscrollView(Context context) {
super(context);
}
public DiscrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DiscrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
setupFirstView();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (getChildCount() != 1) {
throw new IllegalStateException("Discrollview must host one child.");
}
View content = getChildAt(0);
if (!(content instanceof DiscrollViewContent)) {
throw new IllegalStateException("Discrollview must host a DiscrollViewContent.");
}
mContent = (DiscrollViewContent) content;
if (mContent.getChildCount() < 2) {
throw new IllegalStateException("Discrollview must have at least 2 children.");
}
}
private void setupFirstView() {
// first first take all the parent height
View first = mContent.getChildAt(0);
if (first != null) {
first.getLayoutParams().height = getHeight();
}
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
onScrollChanged(t);
}
public static float clamp(float value, float max, float min) {
return Math.max(Math.min(value, min), max);
}
private int getAbsoluteBottom() {
View last = getChildAt(getChildCount() - 1);
if (last == null) {
return 0;
}
return last.getBottom();
}
private void onScrollChanged(int top) {
int scrollViewHeight = getHeight();
int scrollViewBottom = getAbsoluteBottom();
int scrollViewHalfHeight = scrollViewHeight / 2;
// starts at 1 because the first View is a static non Discrollvable
// view.
for (int index = 1; index < mContent.getChildCount(); index++) {
View child = mContent.getChildAt(index);
if (!(child instanceof Discrollvable)) {
// it's a static view, doesn't care about
continue;
}
Discrollvable discrollvable = (Discrollvable) child;
int discrollvableTop = child.getTop();
int discrollvableHeight = child.getHeight();
int discrollvableAbsoluteTop = discrollvableTop - top;
// the Discrollvable is too big to be discrollved when its center is
// reached
// the Discrollvable center. Discrollve it by its top.
if (scrollViewBottom - child.getBottom() < discrollvableHeight + scrollViewHalfHeight) {
// the Discrollvable top reaches the DiscrollView bottom
if (discrollvableAbsoluteTop <= scrollViewHeight) {
int visibleGap = scrollViewHeight - discrollvableAbsoluteTop;
discrollvable.onDiscrollve(clamp(visibleGap / (float) discrollvableHeight,
0.0f, 1.0f));
} else {
discrollvable.onResetDiscrollve();
}
} else {
if (discrollvableAbsoluteTop <= scrollViewHalfHeight) {
// the Discrollvable center reaches the DiscrollView center
int visibleGap = scrollViewHalfHeight - discrollvableAbsoluteTop;
discrollvable.onDiscrollve(clamp(visibleGap / (float) discrollvableHeight,
0.0f, 1.0f));
} else {
discrollvable.onResetDiscrollve();
}
}
}
}
}