首页 > 解决方案 > 滚动索引方法没有持续触发

问题描述

在 Xamarin.Forms 和 Xamarin.Android 项目中,我为 ListView 创建了一个自定义呈现器和适配器。适配器实现 BaseAdapter 和 ISectionIndexer。此控件的自定义呈现使用 FastScroll 功能,在 Android 中,当您点击此滚动时,会出现一个带有索引字母的气泡。这很好用,但我的想法是有一种方法可以在释放滚动后捕获所选索引并且滚动“气泡”消失。我认为使用以下类(在 GetSectionForPosition 方法中)可以实现:

public class ListViewconIndexAdapter : BaseAdapter<string>, ISectionIndexer
    {
        string[] items;
        Activity context;

        string[] sections;
        Java.Lang.Object[] sectionsObjects;
        Dictionary<string, int> alphaIndex;

        public ListViewconIndexAdapter(Activity context, string[] items) : base()
        {
            this.context = context;
            this.items = items;

            alphaIndex = new Dictionary<string, int>();
            for (int i = 0; i < items.Length; i++)
            {
                var key = items[i][0].ToString();
                if (!alphaIndex.ContainsKey(key))
                    alphaIndex.Add(key, i);
            }
            sections = new string[alphaIndex.Keys.Count];
            alphaIndex.Keys.CopyTo(sections, 0);
            sectionsObjects = new Java.Lang.Object[sections.Length];
            for (int i = 0; i < sections.Length; i++)
            {
                sectionsObjects[i] = new Java.Lang.String(sections[i]);
            }

        }


        public override Java.Lang.Object GetItem(int position)
        {
            return position;
        }

        public override long GetItemId(int position)
        {
            return position;
        }

        public override string this[int position]
        {
            get { return items[position]; }
        }

        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            View view = convertView;
            if (view == null)
                view = context.LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem1, null);
            view.FindViewById<TextView>(Android.Resource.Id.Text1).Text = items[position];
            return view;
        }

        //Fill in cound here, currently 0
        public override int Count
        {
            get { return items.Length; }
        }

        // -- ISectionIndexer --
        public int GetPositionForSection(int section)
        {
            return alphaIndex[sections[section]];
        }

        public int GetSectionForPosition(int position)
        {      // this method isn't called in this example, but code is provided for completeness
            int prevSection = 0;

            for (int i = 0; i < sections.Length; i++)
            {
                if (GetPositionForSection(i) > position)
                {
                    break;
                }

                prevSection = i;
            }

            Console.WriteLine(prevSection);
            Console.WriteLine(sections[prevSection]);

            //Toast.MakeText(context, sections[prevSection], ToastLength.Short).Show();
            Xamarin.Forms.MessagingCenter.Send<object,string>(this, "CambioSeccion", sections[prevSection]);
            return prevSection;
        }

    }

我将那些 Console.writeline 用于检查索引字母,而 Message send 是一种将其发送回 PCL/NET Standard 代码(以显示 DisplayAlert 或其他内容)的方式。 但问题是方法触发不一致,例如,有时您快速向下滚动到“C”,但控制台在将其释放后不打印任何内容,但在您离开它的地方再次触摸它后,它会触发。但有时它像我想要的那样工作,它在选定索引处释放滚动后打印。

标签: xamarinxamarin.android

解决方案


ListView有两个不同的滚动监听器,AbsListView.IOnScrollListener并且AbsListView.IOnScrollChangeListener(这个是在 API 23 中添加的)和一个触摸监听器(AbsListView.IOnTouchListener

我认为根据您的用例,您正在寻找OnScrollStateChanged并且当它进入空闲状态并且您没有触摸列表视图时,做一些事情(反之亦然)。

示例(当然根据您的需要进行调整):

    public class MyScrollListener : Java.Lang.Object, AbsListView.IOnTouchListener, AbsListView.IOnScrollListener, AbsListView.IOnScrollChangeListener //(API23)
    {
        bool touching;
        bool scrolling;

        public void OnScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
        {
        }

        public void OnScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)
        {
        }

        public void OnScrollStateChanged(AbsListView view, [GeneratedEnum] ScrollState scrollState)
        {
            switch(scrollState)
            {
                case ScrollState.Idle:
                    if (!touching)
                    {
                        scrolling = false;
                        GetSelection();
                    }
                    break;
                default:
                    scrolling = true;
                    break;
            }
        }

        public bool OnTouch(View v, MotionEvent e)
        {
            switch (e.Action)
            {
                case MotionEventActions.Up:
                    touching = false;
                    if (!scrolling)
                        GetSelection();
                    break;
                default:
                    touching = true;
                    break;
            }
            return true;
        }

        void GetSelection()
        {
            // touch and srolling is done, do something
        }
    }

用法:

var scrollListener = new MyScrollListener();
listView.SetOnTouchListener(scrollListener);
listView.SetOnScrollListener(scrollListener);
listView.SetOnScrollChangeListener(scrollListener); // API23

推荐阅读