How to make a GridView snap scroll

时间:2017-08-30 20:58:29

标签: android xamarin.android

Is there a way to make a long_running_task snap to a row while scrolling?

It seems that applying the known fixes for a views.py does not suffice for a tasks.py.

1 个答案:

答案 0 :(得分:0)

Note: This code was tested for API 23

Note: ALTER TABLE claim ADD EXCLUDE ( claim_number WITH =, line_id WITH IS NOT DISTINCT FROM); , and ERROR: syntax error at or near "IS" for my IS NOT DISTINCT FROM. Couldn't find where this is set, may be default (didn't see it in the style referenced by listPaddingTop == 11 in the below constructor chain (which points to listPaddingBottom == 10/GridView in res/values/styles.xml). Need to check source.

Note: Calling Android.Resource.Attribute.GridViewStyle in constructor has no effect on listPaddingTop (Bottom).

Widget.GridView

Example of exception case noted above

If user scrolls down, from very top, by exactly the padding amount, and Widget.AbsListView is called with the resulting value calculated below (which is SetPadding(0,0,0,0) since public class SnapScrollGridView : GridView, //View.IOnScrollChangeListener AbsListView.IOnScrollListener { private bool _bSnapScroll; public new int FirstVisiblePosition { get; set; } // ctor chain public SnapScrollGridView(Context context) : this(context, null) { } public SnapScrollGridView(Context context, IAttributeSet attrs) : this(context, attrs, Android.Resource.Attribute.GridViewStyle) { } public SnapScrollGridView(Context context, IAttributeSet attrs, int defaultStyleAttr) : this(context, attrs, defaultStyleAttr,0) { } public SnapScrollGridView(Context context, IAttributeSet attrs, int defaultStyleAttr, int defStyleRes) : base(context, attrs, defaultStyleAttr, defStyleRes) { _bSnapScroll = false; FirstVisiblePosition = 0; //SetOnScrollChangeListener(this); SetOnScrollListener(this); // no effect on listPaddingTop (or bottom) // SetPadding(0, 0, 0, 0); } void AbsListView.IOnScrollListener.OnScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // firstVisibleItem and visibleItemCount not accurate } protected override void OnOverScrolled(int scrollX, int scrollY, bool clampedX, bool clampedY) { // - would be very useful, however is called after OnScrollStateChanged() // - may be able to refactor OnScrollStateChanged to work in conjuction with this base.OnOverScrolled(scrollX, scrollY, clampedX, clampedY); } void AbsListView.IOnScrollListener.OnScrollStateChanged(AbsListView view, [GeneratedEnum] ScrollState scrollState) { switch (scrollState) { case ScrollState.TouchScroll: case ScrollState.Fling: break; case ScrollState.Idle: if (_bSnapScroll) { _bSnapScroll = false; } else { View item = view.GetChildAt(0); int top = System.Math.Abs(item.Top); int btm = System.Math.Abs(item.Bottom); // OVERSCROLL TOP ("topping out") // - user tried scrolling up (swiping down) past top if (top == view.ListPaddingTop && view.FirstVisiblePosition == 0) { this.FirstVisiblePosition = 0; return; } // OVERSCROLL BOTTOM ("bottoming out") // - for now, user needs to hit bottom to force snap when last row wont like "normal" // - this happens for certain GridView height and item/row height combinations // - could smooth scroll in the same manner as below, but requires more code // nRows, curRow round down (floor() not needed) int nRows = view.Count / NumColumns; int curRow = view.LastVisiblePosition / NumColumns; if (curRow == nRows) { View item2 = view.GetChildAt(view.LastVisiblePosition-view.FirstVisiblePosition); int top2 = System.Math.Abs(item2.Top); int btm2 = System.Math.Abs(item2.Bottom); if (btm2 == view.Height - view.ListPaddingBottom) { //view.SetSelection(view.LastVisiblePosition); this.FirstVisiblePosition = view.LastVisiblePosition; return; } } // EXCEPTION CASE: smore info below if (item.Top == 0) { view.SetSelection(0); this.FirstVisiblePosition = 0; return; } _bSnapScroll = true; // Compensate for ListPaddingTop // - initially gives a positive offset (11 for me), // observed when attempting to scroll upward from top // (swipe downward while at very top) // (break point will show item.Top = 11) // - if scrolling down a tiny bit, item.Top lessens, // eventually becoming zero, then negative after that int scrollBy = item.Top > 0 ? top >= btm ? btm - view.ListPaddingTop : -(view.ListPaddingTop - top) : top >= btm ? btm - view.ListPaddingTop : -(view.ListPaddingTop + top); // ALTERNATIVE SYNTAX - debug friendly (less cool) //int scrollBy = 0; //if (item.Top > 0) // scrollBy = top >= btm ? btm - view.ListPaddingTop : -(view.ListPaddingTop - top); //else // scrollBy = top >= btm ? btm - view.ListPaddingTop : -(view.ListPaddingTop + top); if (scrollBy <= 0) { this.FirstVisiblePosition = view.FirstVisiblePosition; } else { this.FirstVisiblePosition = view.FirstVisiblePosition + NumColumns; } view.Post(() => { view.SmoothScrollBy(scrollBy, 1000); }); } break; default: break; } } ), no scrolling occurs for some reason (leaving _bSnapScroll inconsistent since SmoothScrollBy() subsequently misfires).

-view.ListPaddingTop

Usage

item.Top == 0

Positing grid to bottom after adding a new item (to end)

OnScrollStateChanged()