如何在 Xamarin Android 的 AlertDialog 中创建带有自定义适配器的列表视图

Posted

技术标签:

【中文标题】如何在 Xamarin Android 的 AlertDialog 中创建带有自定义适配器的列表视图【英文标题】:How can I create a listview with custom adapter inside a AlertDialog in Xamarin Android 【发布时间】:2021-10-14 05:27:34 【问题描述】:

我正在尝试在 Xamarin android 的 AllertDialog 中创建一个 ListView。

我已经搜索并找到了一些示例,但我没有找到任何使用 C# 在 AlertDialog 中使用 ListView 和自定义适配器的示例。

我找到的最接近的样本是下面的示例 (Thanks to Macoratti)。这个没有AlertDialog。 我已经尝试适应,但我得到 System.NullReferenceException: 'Object reference not set to an instance of an object.'.

主要活动:

namespace App.CustomAdapterListView

    [Activity(Label = "App.CustomAdapterListView", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    
        protected override void OnCreate(Bundle bundle)
        

            base.OnCreate(bundle);
            SetContentView(Resource.Layout.Main);

         /*  Original
            var filmesListView = FindViewById<ListView>(Resource.Id.filmeslistView);
            filmesListView.FastScrollEnabled = true;
            filmesListView.ItemClick += FilmesListView_ItemClick;
            var filmesAdapter = new FilmeAdapter(this, FilmesRepositorio.Filmes);
            filmesListView.Adapter = filmesAdapter;
         */


         var ViewAD = LayoutInflater.Inflate(Resource.Layout.Filmes, null);
         
         AlertDialog alertDialog;

         using (var dialog = new AlertDialog.Builder(this))
         
            dialog.SetView(ViewAD);
            dialog.SetNegativeButton("Cancel", (s, a) =>  );
            alertDialog = dialog.Create();
         

         var adapter = new FilmeAdapter(this, FilmesRepositorio.Filmes);

// Here I get - System.NullReferenceException: 'Object reference not set to an instance of an object.'
         ViewAD.FindViewById<ListView>(Resource.Id.filmeslistView).Adapter = adapter; 

         alertDialog.Show();

        

        private void FilmesListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
        
            Toast.MakeText(this, FilmesRepositorio.Filmes[e.Position].ToString(), ToastLength.Long).Show();
        

    


适配器类:

namespace App.CustomAdapterListView

    public class Filme
    
        public int Id  get; set; 
        public string Titulo  get; set; 
        public string Diretor  get; set; 
        public DateTime DataLancamento  get; set; 

        public override string ToString()
        
            return Titulo + " por " + Diretor;
        
    

适配器:

namespace App.CustomAdapterListView

     public class FilmeAdapter : BaseAdapter<Filme>
    
        private readonly Activity context;
        private readonly List<Filme> filmes;

        public FilmeAdapter(Activity context, List<Filme> filmes)
        
            this.context = context;
            this.filmes = filmes;
        

        public override Filme this[int position]
        
            get
            
                return filmes[position];
            
        

        public override int Count
        
            get
            
                return filmes.Count;
            
        

        public override long GetItemId(int position)
        
            return filmes[position].Id;
        

        public override View GetView(int position, View convertView, ViewGroup parent)
        
            var view = convertView ?? context.LayoutInflater.Inflate(Resource.Layout.Filmes, parent, false);

            var txtTitulo = view.FindViewById<TextView>(Resource.Id.tituloTextView);
            var txtDiretor = view.FindViewById<TextView>(Resource.Id.diretorTextView);
            var txtLancamento = view.FindViewById<TextView>(Resource.Id.dataLancamentoTextView);

            txtTitulo.Text = filmes[position].Titulo;
            txtDiretor.Text = "Dirigido por: " + filmes[position].Diretor;
            txtLancamento.Text = "Lançado em : " + filmes[position].DataLancamento.ToShortDateString();

            return view;
        
    

数据库:

namespace App.CustomAdapterListView

    public static class FilmesRepositorio
    
        public static List<Filme> Filmes  get; private set; 

        static FilmesRepositorio()
        
            Filmes = new List<Filme>();
            for (int i = 0; i < 10; i++)
            
                AddFilmes();
            

        

        private static void AddFilmes()
        
            Filmes.Add(new Filme
            
                Id = 1,
                Titulo = "A New Hope",
                Diretor = "George Lucas",
                DataLancamento = new DateTime(1977, 05, 25)
            );

            Filmes.Add(new Filme
            
                Id = 2,
                Titulo = "The Empire Strikes Back",
                Diretor = "George Lucas",
                DataLancamento = new DateTime(1980, 05, 17)
            );

            Filmes.Add(new Filme
            
                Id = 3,
                Titulo = "O Reterono de Jedi",
                Diretor = "George Lucas",
                DataLancamento = new DateTime(1983, 05, 25)
            );

            Filmes.Add(new Filme
            
                Id = 4,
                Titulo = "A ameaça fantasma",
                Diretor = "George Lucas",
                DataLancamento = new DateTime(1999, 05, 19)
            );

            Filmes.Add(new Filme
            
                Id = 5,
                Titulo = "A vingança dos Sith",
                Diretor = "George Lucas",
                DataLancamento = new DateTime(2005, 05, 19)
            );

            Filmes.Add(new Filme
            
                Titulo = "Marte",
                Diretor = "J.J. Abrams",
                DataLancamento = new DateTime(2015, 12, 11)
            );
        
    


主布局 axml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_
    android:layout_
    android:minWidth="25px"
    android:minHeight="25px">
    <ListView
        android:minWidth="25px"
        android:minHeight="25px"
        android:background="#eee5d5"
        android:layout_
        android:layout_
        android:id="@+id/filmeslistView" />
</LinearLayout>

ListView的自定义布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_
    android:layout_
    android:padding="8dp">
    <TextView
        android:id="@+id/tituloTextView"
        android:layout_
        android:layout_
        android:textColor="#000000"
        android:textSize="20dp"
        android:textStyle="bold"
        android:paddingLeft="5dp" />
    <TextView
        android:id="@+id/diretorTextView"
        android:layout_
        android:layout_
        android:textColor="#00A14B"
        android:paddingLeft="5dp" />
    <TextView
        android:id="@+id/dataLancamentoTextView"
        android:layout_
        android:layout_
        android:textColor="#7F3F97"
        android:paddingLeft="5dp" />
</LinearLayout>

对不起,菜鸟问题。 我将不胜感激。

谢谢

【问题讨论】:

Resource.Layout.Filmes 是否包含Resource.Id.filmeslistView 我不确定哪个是哪个,但是您为AlertDialog 的内容和Adapter 中的各个行添加了相同的布局:Resource.Layout.Filmes 【参考方案1】:

您应该为包含ListView 的视图创建一个xml (dialogview.xml),并为列表视图的每个项目创建一个xml (itemview.xml)。

例如:

创建一个dialogview.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_
  android:layout_
  android:minWidth="25px"
  android:minHeight="25px">
  <ListView
      android:minWidth="25px"
      android:minHeight="25px"
      android:background="#eee5d5"
      android:layout_
      android:layout_
      android:id="@+id/filmeslistView" />
</LinearLayout>

创建一个itemview.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_
  android:layout_
  android:padding="8dp">
  <TextView
    android:id="@+id/tituloTextView"
    android:layout_
    android:layout_
    android:textColor="#000000"
    android:textSize="20dp"
    android:textStyle="bold"
    android:paddingLeft="5dp" />
  <TextView
    android:id="@+id/diretorTextView"
    android:layout_
    android:layout_
    android:textColor="#00A14B"
    android:paddingLeft="5dp" />
  <TextView
    android:id="@+id/dataLancamentoTextView"
    android:layout_
    android:layout_
    android:textColor="#7F3F97"
    android:paddingLeft="5dp" />
</LinearLayout>
  

在您的 MainActivity 中:

 protected override void OnCreate(Bundle bundle)
    

        base.OnCreate(bundle);
        SetContentView(Resource.Layout.Main);

        var ViewAD = LayoutInflater.Inflate(Resource.Layout.dialogview, null);
        var adapter = new FilmeAdapter(this, FilmesRepositorio.Filmes);
        ViewAD.FindViewById<ListView>(Resource.Id.filmeslistView).Adapter = adapter; 
       AlertDialog alertDialog;

       using (var dialog = new AlertDialog.Builder(this))
        
        dialog.SetView(ViewAD);
        dialog.SetNegativeButton("Cancel", (s, a) =>  );
        alertDialog = dialog.Create();
       

       alertDialog.Show();

    

在你的适配器中:

namespace App.CustomAdapterListView

 public class FilmeAdapter : BaseAdapter<Filme>
 
    private readonly Activity context;
    private readonly List<Filme> filmes;

    public FilmeAdapter(Activity context, List<Filme> filmes)
    
        this.context = context;
        this.filmes = filmes;
    

    public override Filme this[int position]
    
        get
        
            return filmes[position];
        
    

    public override int Count
    
        get
        
            return filmes.Count;
        
    

    public override long GetItemId(int position)
    
        return filmes[position].Id;
    

    public override View GetView(int position, View convertView, ViewGroup parent)
    
        var view = convertView ?? context.LayoutInflater.Inflate(Resource.Layout.itemview, parent, false);// inflate the xml for each item

        var txtTitulo = view.FindViewById<TextView>(Resource.Id.tituloTextView);
        var txtDiretor = view.FindViewById<TextView>(Resource.Id.diretorTextView);
        var txtLancamento = view.FindViewById<TextView>(Resource.Id.dataLancamentoTextView);

        txtTitulo.Text = filmes[position].Titulo;
        txtDiretor.Text = "Dirigido por: " + filmes[position].Diretor;
        txtLancamento.Text = "Lançado em : " + filmes[position].DataLancamento.ToShortDateString();

        return view;
    
  

更新

 var ViewAD = LayoutInflater.Inflate(Resource.Layout.dialogview, null);
 var adapter = new FilmeAdapter(this, FilmesRepositorio.Filmes);
 ListView listview =  ViewAD.FindViewById<ListView>(Resource.Id.filmeslistView);
 listview.Adapter = adapter; 
 listView.ItemClick += ListView_ItemClick;
 ...


 private void ListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
 
      //you could get the select data
 

【讨论】:

非常感谢 Leo,它有效。可悲的是,我还不能在你的回答中投票。如何将选定的值传递给 main,关闭警报对话框? @nmend 你可以在列表视图中添加一个点击事件。我在上面更新它。 太完美了!你太棒了!

以上是关于如何在 Xamarin Android 的 AlertDialog 中创建带有自定义适配器的列表视图的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Xamarin.Android 中实现 RewardedAdLoadCallback?

如何使用 Xamarin 在 Android 中同步获取 GPS 位置更新?

如何在 Xamarin.Android 中获取指南针方向

Xamarin.android如何添加snackbar回调

如何在Xamarin中快速集成Android版认证服务-邮箱地址篇

如何在 Xamarin 中使用 SetAction