簡體   English   中英

如何制作GridView快照滾動

[英]How to make a GridView snap scroll

有沒有一種方法可以使GridView在滾動時對齊到一行?

似乎為ListView應用已知的修復程序不足以為GridView足夠的支持。

注意:此代碼已針對API 23進行了測試

注: listPaddingTop == 11 ,和listPaddingBottom == 10為我GridView 找不到設置的位置,可能是默認設置(在下面的構造函數鏈中未以Android.Resource.Attribute.GridViewStyle引用的樣式看到它(在res / values中指向Widget.GridView / Widget.AbsListView /styles.xml )。需要檢查源代碼。

注意:在構造函數中調用SetPadding(0,0,0,0)對listPaddingTop(底部)無效。

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;
        }
    }

上面提到的例外情況的示例

如果用戶從最上端向下精確地滾動到填充量,然后調用SmoothScrollBy()並使用下面計算的結果值(由於item.Top == 0 -view.ListPaddingTop item.Top == 0 ),由於某種原因,不會發生滾動(留下_bSnapScroll不一致,因為OnScrollStateChanged()隨后會觸發錯誤)。

                    //if (item.Top == 0)
                    //{
                    //    view.SetSelection(0);
                    //    return;
                    //}

                    _bSnapScroll = true;

                    //int scrollBy = item.Top > 0
                    int scrollBy = item.Top >= 0
                        ? top >= btm ? btm - view.ListPaddingTop : -(view.ListPaddingTop - top)
                        : top >= btm ? btm - view.ListPaddingTop : -(view.ListPaddingTop + top);

用法

private void GridViewAdapterLoad()
{
    int pos = ((SnapScrollGridView)_gridView).FirstVisiblePosition;

    _gridView.Adapter = new GridViewAdapter(
        Activity,
        Resource.Layout.GridItem,
        Model.GridItems);

    _gridView.SetSelection(pos);
}

在添加新項目后將網格定位到底部(到最后)

private void GridViewLoad(bool bNewItem)
{
    _controller.LoadGridItems();

    _gridView.Adapter = null;

    GridViewAdapterLoad();

    if (bNewItem)
    {
        int count = _gridView.Count;            
        int row = --count / _gridView.NumColumns; // floor not needed
        int pos = row * _gridView.NumColumns;

        ((SnapScrollGridView)_gridView).FirstVisiblePosition = pos;

        _gridView.SetSelection(pos);

        // Would be sweet to scroll from current position, but isn't.
        //_gridView.Post(() => { _gridView.SmoothScrollToPosition(pos); });
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM