private void SendFakeEvent(MotionEvent e, MotionEventActions forcedAction) { var fake_event = MotionEvent.ObtainNoHistory(e); fake_event.Action = forcedAction; ContentView.ForceHandleTouchEvent(fake_event); fake_event.Recycle(); }
private bool HandleUpEvent(MotionEvent e) { last_touch_y = -1; if (refresh_state == PullToRefresharpRefreshState.ReleaseToRefresh) { UpdateRefreshState(PullToRefresharpRefreshState.Refreshing); } if (current_scroll_y < 0) { Post(StartSnapback); ContentView.IgnoreTouchEvents = false; } if (did_steal_event_stream && current_scroll_y >= 0) { did_steal_event_stream = false; ContentView.ForceHandleTouchEvent(e); } if (should_cancel_before_up) { // This means we revealed the ptr header and should cancel the event // so the content view doesn't register a click on up. should_cancel_before_up = false; SendFakeEvent(e, MotionEventActions.Cancel); } else if (should_send_down_before_up) { should_send_down_before_up = false; SendFakeEvent(e, MotionEventActions.Down); } return(false); }
public override bool OnTouchEvent(MotionEvent e) { if (!IsPullEnabled) { return(base.OnTouchEvent(e)); } if (null == ContentView) { return(base.OnTouchEvent(e)); } if (ContentView is AbsListView && ((AbsListView)ContentView).FastScrollEnabled) { // An adimittedly crude way to determine if touch is in fast scroll, but // should accomplish the goal of not displaying ptr header. // This is crude because there is not a definitive way to determine // a) if the fast scroller is visible or // b) the width of the scroller if (Resources.DisplayMetrics.WidthPixels - e.RawX < fastscroll_thumb_width) { return(false); // let the list view handle this } } switch (e.ActionMasked) { case MotionEventActions.Down: last_touch_y = ContentView.IsAtTop ? (int)e.RawY : -1; if (!ContentView.IsAtTop) { send_down_event = false; // because this event will reach the ContentView } else { should_send_down_before_up = true; } return(ContentView.IsAtTop); case MotionEventActions.Move: if (did_steal_event_stream && current_scroll_y >= 0) { if (send_down_event) { did_steal_event_stream = false; send_down_event = false; ContentView.IgnoreTouchEvents = false; SendFakeEvent(e, MotionEventActions.Down); } return(true); } if (last_touch_y == -1) { last_touch_y = (int)e.RawY; return(true); } var y_delta = last_touch_y - (int)e.RawY; last_touch_y = (int)e.RawY; bool isMovingUp = y_delta > 0; if (isMovingUp && current_scroll_y >= 0 || !ContentView.IsAtTop) { should_send_down_before_up = false; ContentView.ForceHandleTouchEvent(e); return(true); } if (ContentView.IsAtTop) { var new_scroll_to = isMovingUp ? (int)y_delta : (int)(y_delta * PullDownTensionFactor); // see if this will fully hide the header if (current_scroll_y < 0 && current_scroll_y + new_scroll_to > 0) { // only scroll enough to hide the header new_scroll_to = -current_scroll_y; } current_scroll_y += new_scroll_to; Header.OffsetTopAndBottom(-new_scroll_to); ((View)ContentView).OffsetTopAndBottom(-new_scroll_to); ViewCompat.PostInvalidateOnAnimation(this); if (current_scroll_y == 0) { ContentView.IgnoreTouchEvents = false; return(true); } else { should_cancel_before_up = true; should_send_down_before_up = false; } if (Math.Abs(current_scroll_y) >= header_measured_height) { if (refresh_state != PullToRefresharpRefreshState.Refreshing) { SetPullDownIconProgress(1); UpdateRefreshState(PullToRefresharpRefreshState.ReleaseToRefresh); } } else { // Don't update anything if we are refreshing. if (refresh_state != PullToRefresharpRefreshState.Refreshing) { SetPullDownIconProgress((float)Math.Abs(current_scroll_y) / (float)header_measured_height); UpdateRefreshState(PullToRefresharpRefreshState.PullToRefresh); } } return(true); } return(false); case MotionEventActions.Up: return(HandleUpEvent(e)); } return(base.OnTouchEvent(e)); }