带有自定义适配器的Listview显示重复网格项,如果使用Fragment

时间:2017-02-06 17:17:07

标签: c# android android-fragments gridview xamarin

Xamarin.Android来自C#。

问题是如果在Fragment代码中使用了适配器,则自定义适配器在ListView中显示太多项目。如果我将从MainActivity中使用它,它将正常工作。

我需要在ListView元素中显示动态自定义信息,该元素位于Tab( Fragment )中。 ListView的每一行应在一行中逐个包含动态数量的文本框。为此,自定义适配器使用 TextView 元素生成GridLayout 。行数也是动态的,这就是使用 List<> 的原因。我试图尽可能简化我的代码。在现实生活中,数据类更复杂,使用了很多Tabs等等。

输入: 1. 某些数据的简单类

public class MyData
{
    internal int ID;
    internal string Nick;

    public MyData(int _id, string _nick)
    {
        ID = _id;
        Nick = _nick;
    }
}     

2。 Tab1.axml 是我们需要显示的Tab的布局。它只包含ListView元素,其中Adapter应放置数据

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
    android:minWidth="25px"
    android:minHeight="25px"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/listView1" />

3. Grid.axml 是布局,它代表ListView的每一行。它将包含GridView

中动态数量的TextView元素
<GridLayout xmlns:p1="http://schemas.android.com/apk/res/android"
p1:minWidth="25px"
p1:minHeight="25px"
p1:layout_width="match_parent"
p1:layout_height="match_parent"
p1:id="@+id/gridLayout1"
p1:columnCount="2" />

4。 Main.axml 是包含标签的主要布局(本例仅为1)。 fragmentContainer是Tab的容器。 listViewMain是listview,用于检查适配器是否正常工作。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/linearLayout1">
<FrameLayout
    android:minWidth="25px"
    android:minHeight="25px"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/fragmentContainer" />
<ListView
    android:minWidth="25px"
    android:minHeight="25px"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/listViewMain" />

5. MainActivity.cs 包含所有代码

 protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        SetContentView(Resource.Layout.Main);

        //creating one main tab
        ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
        AddTab("Tab 1", new SampleTabFragment1());

        /* //to test if Adapter works properly From MainActivtity instead of Fragment
        List<MyData> listOfData = new List<MyData>();
        MyData item = new MyData(1, "Nick#1");
        listOfData.Add(item);

        item = new MyData(2, "Nick#2");
        listOfData.Add(item);

        ListView table = this.FindViewById<ListView>(Resource.Id.listViewMain);
        table.Adapter = new MyDataAdapter(this, listOfData);*/
    }

创建标签的标准功能:

void AddTab(string tabText, Fragment view)
    {
        var tab = this.ActionBar.NewTab();
        tab.SetText(tabText);

        // must set event handler before adding Tab
        tab.TabSelected += delegate (object sender, ActionBar.TabEventArgs e)
        {
            var fragment = this.FragmentManager.FindFragmentById(Resource.Id.fragmentContainer);
            if (fragment != null)
                e.FragmentTransaction.Remove(fragment);
            e.FragmentTransaction.Add(Resource.Id.fragmentContainer, view);
        };
        tab.TabUnselected += delegate (object sender, ActionBar.TabEventArgs e)
        {
            e.FragmentTransaction.Remove(view);
        };

        this.ActionBar.AddTab(tab);
    }

我们将自定义适配器绑定到listview的Tab的片段:

class SampleTabFragment1 : Fragment
    {
        public override void OnDestroyView()
        {
            base.OnDestroyView();
        }            
        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            base.OnCreateView(inflater, container, savedInstanceState);
            var view = inflater.Inflate(Resource.Layout.Tab1, container, false);

            //Creating our data
            List <MyData> listOfData = new List<MyData>();                
            MyData item = new MyData(1, "Nick#1");
            listOfData.Add(item);

            item = new MyData(2, "Nick#2");
            listOfData.Add(item);

            //Find listview from Tab1.axml which is actually our Tab Fragment
            ListView table = view.FindViewById<ListView>(Resource.Id.listView1);
            //Binding listview with custom adapter
            table.Adapter = new MyDataAdapter(this.Activity, listOfData);

            return view;
        }
    }

最后,适用于我们的自定义数据:

public class MyDataAdapter : BaseAdapter<MyData>
    {
        Activity context;
        List<MyData> list;
        public MyDataAdapter(Activity _context, List<MyData> _list)
        {
            context = _context;
            list = _list;
        }
        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            View view = convertView;

            // re-use an existing view, if one is available
            // otherwise create a new one
            if (view == null)
                view = context.LayoutInflater.Inflate(Resource.Layout.Grid, parent, false);

            //find GridView from Grid.axml and set columns count to 2 (only ID and Nick)
            GridLayout tableView = view.FindViewById<GridLayout>(Resource.Id.gridLayout1);
            tableView.ColumnCount = 2;

            //Creating TextView to show ID, place position is 0 - first
            TextView textCaption = new TextView(view.Context);
            textCaption.SetText(list[position].ID.ToString(), TextView.BufferType.Normal);
            tableView.AddView(textCaption, 0);

            //Creating TextView to show ID, place position is 1 - second in a row of Grid
            textCaption = new TextView(view.Context);
            textCaption.SetText(list[position].Nick, TextView.BufferType.Normal);
            tableView.AddView(textCaption, 1);

            return view;
        }
        public override int Count
        {
            get { return list.Count; }
        }
        public override long GetItemId(int position)
        {
            return position;
        }

        public override MyData this[int index]
        {
            get { return list[index]; }
        }            
    }

所有这些都应向最终用户显示两行ListView。第一行包含带有两个TextView元素的GridView&#34; 1&#34;和#34;尼克#1&#34;在一排。第二行应包含GridView with&#34; 2&#34;和#34;尼克#2&#34;像这样的一行: calling from MainActivity

...而是每个2个ListView行包含大量带有数据的GridView行: calling from Fragment

如果您要通过评论来停用标签

        //ActionBar.NavigationMode = ActionBarNavigationMode.Tabs;
        //AddTab("Tab 1", new SampleTabFragment1());

并取消注释MainActivity.cs的代码区域

//to test if Adapter works properly without Fragment

它将使用与Fragment SampleTabFragment1()调用中使用的完全相同的自定义适配器和布局结构来显示正确的结果。 看起来有一些关于将Fragments与自定义适配器和\或布局一起使用的技巧,你怎么看?

1 个答案:

答案 0 :(得分:0)

面对这个问题后,我决定改用Java Android而不是使用C#。在学习Java(和Android开发)后的几周内,我试图重写我的程序并面临同样的问题!这次我尝试通过<Directory /project1/private/>的自定义适配器在其中动态创建TableRows TextViews

第一行仍然有重复的元素!但解决方案很容易。如果适配器的当前ListView未创建(等于null),则应在运行时 期间创建新视图。 (当然,如果你不动态地创建任何视图,而是使用XML布局它已经可以正常工作)这个解决方案适用于我的Java程序,它对我来说应该是这样的旧的C#代码:

view