package hk.hku.cs.srli.widget; import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.MotionEvent; import android.widget.ScrollView; import hk.hku.cs.srli.widget.util.EdgeEffectHelper; import hk.hku.cs.srli.widget.util.HoverHandler; public class HoverScrollView extends ScrollView { private HoverHandler hover; private EdgeEffectHelper edge; public static enum ScrollState {TOP, MIDDLE, BOTTOM, NOT_SCROLLABLE} // to change this, use changeState(newState) private ScrollState state; public HoverScrollView(Context context) { super(context); init(null, 0); } public HoverScrollView(Context context, AttributeSet attrs) { super(context, attrs); init(attrs, 0); } public HoverScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(attrs, defStyle); } private void init(AttributeSet attrs, int defStyle) { hover = new HoverHandler(this); edge = new EdgeEffectHelper(this); hover.setOnHoverMoveListener(edge); state = ScrollState.NOT_SCROLLABLE; edge.setEdgeGlow(false, false, false, false); setWillNotDraw(false); } @Override public void onHoverChanged(boolean hovered) { super.onHoverChanged(hovered); edge.onHoverChanged(hovered); } @Override public boolean onInterceptHoverEvent(MotionEvent event) { // get all hover events from here hover.onHoverEvent(event); // don't interference with children return false; } @Override public boolean onHoverEvent(MotionEvent event) { // already handled above return false; } @Override public void draw(Canvas canvas) { super.draw(canvas); final int restoreCount = canvas.save(); canvas.translate(0, getScrollY()); edge.draw(canvas); canvas.restoreToCount(restoreCount); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); updateScrollState(); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); updateScrollState(); } private void updateScrollState() { if (getChildCount() <= 0) { changeState(ScrollState.NOT_SCROLLABLE); return; } // find the last child (should be the only child) float childHeight = getChildAt(getChildCount() - 1).getMeasuredHeight(); if (getScrollY() <= 0) { if(childHeight <= getHeight()) changeState(ScrollState.NOT_SCROLLABLE); else changeState(ScrollState.TOP); } else if(childHeight <= getHeight() + getScrollY()){ // the bottom has been reached changeState(ScrollState.BOTTOM); } else { changeState(ScrollState.MIDDLE); } } private void changeState(ScrollState newState) { if (newState == state) return; state = newState; switch(state) { case NOT_SCROLLABLE: edge.setVerticalScrollable(false, false); return; case TOP: edge.setVerticalScrollable(false, true); return; case BOTTOM: edge.setVerticalScrollable(true, false); return; case MIDDLE: edge.setVerticalScrollable(true, true); return; } } }