c# - 如何处理卡片 View 中图像按钮内的点击事件以打开弹出菜单

标签 c# android xamarin popup android-recyclerview

我想实现一个集成了 CardView 网格的 RecyclerView。 在 cardView 内部有一个简单的图像按钮,单击它会打开一个弹出菜单。问题是,在我多次滚动整个 recyclerview 并尝试单击图像按钮后,它显示了多个弹出窗口。似乎我在几个 CardView 中单击了图像按钮,但事实并非如此,因为我只在一个 cardview 中单击了一个按钮。我认为问题出在图像按钮内的点击监听器(在 recyclerView 代码中),但我不明白我哪里错了。在这个video你可以看到失败。 预先感谢您的帮助。

这是我的 cardView 示例 (FotoCardView.axml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/foto_cardView"
        android:background="?attr/selectableItemBackground"
        android:foreground="?android:attr/selectableItemBackground"
        card_view:cardBackgroundColor="@android:color/transparent"
        card_view:cardElevation="1dp"
        card_view:cardPreventCornerOverlap="false"
        card_view:cardUseCompatPadding="true"
        card_view:cardCornerRadius="0dp">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/foto_img"
            android:scaleType="centerCrop" />
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom"
            android:background="@android:color/black"
            android:paddingLeft="5dp"
            android:paddingRight="5dp"
            android:paddingTop="7dp"
            android:paddingBottom="8dp"
            android:alpha="0.6">
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:visibility="invisible"
                android:textSize="15sp"
                android:id="@+id/foto_caption"
                android:textColor="@android:color/white"
                android:text="#"
                android:alpha="1" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:textSize="15sp"
                android:id="@+id/foto_caption2"
                android:textColor="@android:color/white"
                android:text="left"
                android:alpha="1" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_below="@+id/foto_caption2"
                android:id="@+id/foto_caption3"
                android:text="IMG_data_foto.jpg"
                android:textSize="12sp"
                android:textColor="@android:color/white"
                android:alpha="1" />
            <ImageButton
                android:id="@+id/card_options"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/ic_more_vert_white_24dp"
                android:alpha="1"
                android:layout_alignParentRight="true"
                android:layout_alignParentTop="true"
                android:background="?attr/selectableItemBackgroundBorderless" />
        </RelativeLayout>
    </android.support.v7.widget.CardView>
</LinearLayout>

CardFotoAdapter.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.V7.Widget;
using Showroom.XamarinItemTouchHelper;
using ViewHolder = Android.Support.V7.Widget.RecyclerView.ViewHolder;
using Android.Graphics;
using Android.Support.Design.Widget;
using Showroom.ORM;
using SQLite;
using Square.Picasso; // Es. la utilizza la Snackbar

namespace Showroom.Adapters
{
    public class CardFotoAdapter : RecyclerView.Adapter, IItemTouchHelperAdapter
    {
        public IList<Foto> foto;
        Context context;
        private IOnStartDragListener dragStartListener;
        public event EventHandler<int> itemClick;

        // Costruttore della classe adapter
        public CardFotoAdapter(IList<Foto> foto, Context context, IOnStartDragListener dragStartListener)
        {
            this.foto = foto;
            this.context = context;
            this.dragStartListener = dragStartListener;
        }

        // Metodo che inizializza il ViewHolder associando il layout al recyclerview
        public override ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
        {
            View fotoView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.FotoCardView, parent, false);
            ViewHolderFoto vh = new ViewHolderFoto(fotoView, OnClick);
            return vh;
        }

        // Metodo che specifica il contenuto del ViewHolder (effettua il bind dei dati)
        public override void OnBindViewHolder(ViewHolder holder, int position)
        {
            ViewHolderFoto vh = holder as ViewHolderFoto;
            // Controllo che la foto abbia una didascalia
            if (foto[position].descr != null)
            {
                vh.txtFotoCaption.Text = foto[position].descr;
            }
            // Controllo che esista un URL della foto
            if (foto[position].url != null)
            {
                Picasso.With(vh.imgFoto.Context)
                    .Load(Utils.urlImageToThumb("file://" + foto[position].url))
                    .Into(vh.imgFoto);
                //BitmapFactory.Options options = new BitmapFactory.Options();
                //options.InSampleSize = 1;
                //Bitmap myBitmap = BitmapFactory.DecodeFile(Utils.urlImageToThumb(foto[position].url), options);
                //vh.imgFoto.SetImageBitmap(myBitmap);
                ////vh.imgFoto.SetOnTouchListener(new TouchListenerHelper(vh, dragStartListener));
                //myBitmap.Dispose();
            }

            vh.imgFotoOptions.Click += (sender1, args1) =>
                {
                    Toast.MakeText(context, "test Modifica" + position.ToString(), ToastLength.Short).Show();
                    //Toast.MakeText(context, "test Modifica " + position.ToString(), ToastLength.Short).Show();
                    Android.Widget.PopupMenu popup = new Android.Widget.PopupMenu(vh.imgFotoOptions.Context, vh.imgFotoOptions);
                    popup.Inflate(Resource.Menu.CardMenu);
                    popup.MenuItemClick += (s, args) =>
                        {
                            switch (args.Item.ItemId)
                            {
                                case Resource.Id.delete:
                                    Toast.MakeText(context, "FOTO ELIMINATA", ToastLength.Short).Show();
                                    DBRepository dbr = new DBRepository();
                                    var path = dbr.pathDB();
                                    var db = new SQLiteConnection(path);
                                    db.Delete(foto[position]);
                                    db.Close();
                                    foto.RemoveAt(position);
                                    NotifyItemRemoved(position);
                                    break;
                                case Resource.Id.edit:
                                    Toast.MakeText(context, "edit " + position.ToString(), ToastLength.Short).Show();
                                    break;
                            }
                        };
                    popup.Show();
                };
            vh.txtFotoCaption2.Text = "descrizione1";
            vh.txtFotoCaption3.Text = System.IO.Path.GetFileNameWithoutExtension(foto[position].url);
        }

        void OnClick(int position)
        {
            if (itemClick != null)
                itemClick(this, position);
        }

        public override int ItemCount
        {
            get { return foto.Count; }
        }

        public void OnItemDismiss(int position, RecyclerView rv)
        {
            Snackbar
                .Make(rv, "Test snackbar", Snackbar.LengthShort)
                .Show();
            DBRepository dbr = new DBRepository();
            var path = dbr.pathDB();
            var db = new SQLiteConnection(path);
            db.Delete(foto[position]);
            db.Close();
            foto.RemoveAt(position);
            NotifyItemRemoved(position);
        }

        public bool OnItemMove(int fromPosition, int toPosition)
        {
            // Abilitare l'ordinamento
            NotifyItemMoved(fromPosition, toPosition);
            return true;
        }

        public class ViewHolderFoto : ViewHolder, IItemTouchHelperViewHolder
        {
            public View mainView { get; private set; }
            public CardView cardView { get; private set; }
            public TextView txtFotoCaption { get; private set; }
            public TextView txtFotoCaption2 { get; private set; }
            public TextView txtFotoCaption3 { get; private set; }
            public ImageView imgFoto { get; private set; }
            public ImageButton imgFotoOptions { get; private set; }

            public ViewHolderFoto(View fotoView, Action<int> listener)
                : base(fotoView)
            {
                mainView = fotoView;
                cardView = (CardView)fotoView.FindViewById<CardView>(Resource.Id.foto_cardView);
                txtFotoCaption = (TextView)fotoView.FindViewById<TextView>(Resource.Id.foto_caption);
                txtFotoCaption2 = (TextView)fotoView.FindViewById<TextView>(Resource.Id.foto_caption2);
                txtFotoCaption3 = (TextView)fotoView.FindViewById<TextView>(Resource.Id.foto_caption3);
                imgFoto = (ImageView)fotoView.FindViewById<ImageView>(Resource.Id.foto_img);
                imgFotoOptions = (ImageButton)fotoView.FindViewById<ImageButton>(Resource.Id.card_options);
                fotoView.Click += (sender, e) => listener(base.Position);
            }

            public void OnItemSelected()
            {
                //mainView.SetBackgroundColor(Color.LightGray);
                //cardView.SetCardBackgroundColor(Color.LightGray);

            }

            public void OnItemClear()
            {
                //mainView.SetBackgroundColor(Color.White);
                cardView.SetCardBackgroundColor(Color.Transparent);
            }
        }

    }
}

GalleryCardActivity.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Support.V7.App;
using Showroom.XamarinItemTouchHelper;
using Toolbar = Android.Support.V7.Widget.Toolbar;
using Android.Support.V7.Widget;
using Showroom.ORM;
using SQLite;
using Showroom.Adapters;
using Android.Support.V7.Widget.Helper; // ItemTouchHelper.Callback

namespace Showroom.Activities
{
    [Activity(Label = "GalleryCardActivity")]
    public class GalleryCardActivity : AppCompatActivity, IOnStartDragListener
    {
        private IList<Foto> fotoVariante = new List<Foto>();
        private ItemTouchHelper itemTouchHelper;

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);

            // Create your application here
            SetContentView(Resource.Layout.GalleryGrid2);
            var toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
            SetSupportActionBar(toolbar);
            SupportActionBar.Title = "Griglia Foto";

            // Collego il linear layout manager
            int columns = Resources.GetInteger(Resource.Integer.grid_colums);  // Il numero delle colonne cambia in base all'orientamento
            GridLayoutManager glm = new GridLayoutManager(this, columns);

            // Collego il layout manager all'adapter
            RecyclerView rv = FindViewById<RecyclerView>(Resource.Id.rvFoto);
            rv.SetLayoutManager(glm);

            int idItem = Convert.ToInt32(Intent.GetStringExtra("idItem"));

            // Imposto i dati da visualizzare
            DBRepository dbr = new DBRepository();
            fotoVariante = dbr.fotoVariante(idItem);
            CardFotoAdapter fotoAdapter = new CardFotoAdapter(fotoVariante, this, this);
            fotoAdapter.itemClick += OnItemClick;
            rv.SetAdapter(fotoAdapter);
            ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(fotoAdapter, rv);
            itemTouchHelper = new ItemTouchHelper(callback);
            itemTouchHelper.AttachToRecyclerView(rv);
        }

        void OnItemClick(object sender, int position)
        {
            Foto foto = fotoVariante.ElementAt(position);
            var uri = Android.Net.Uri.Parse("file://" + foto.url);
            Intent i = new Intent(Intent.ActionView);
            i.SetDataAndType(uri, "image/*");
            StartActivity(i);
        }

        public void OnStartDrag(RecyclerView.ViewHolder viewHolder)
        {
            itemTouchHelper.StartDrag(viewHolder);
        }

    }
}

最佳答案

解决方法很简单,因为我犯了一个简单的错误! 我必须将点击事件放在“OnCreateViewHolder”方法内,而不是“OnBindViewHolder”内。 所以它看起来类似于这个 fragment

        // Metodo che inizializza il ViewHolder
    public override ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
    {
        View itemView = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.VarianteCardView, parent, false);
        ViewHolderCard vh = new ViewHolderCard(itemView, OnClick);
        // Gestisco il click del pulsante opzioni di ciascuna CardView
        vh.imgCardOptions.Click += (o, e) =>
        {
            Toast.MakeText(context, "ciao " + vh.AdapterPosition.ToString(), ToastLength.Short).Show();
            PopupMenu popup = new PopupMenu(context, vh.imgCardOptions);
            popup.Inflate(Resource.Menu.CardMenu);
            popup.MenuItemClick += (s, args) =>
            {
                switch (args.Item.ItemId)
                {
                    case Resource.Id.delete:
                        Toast.MakeText(context, "delete " + vh.AdapterPosition.ToString(), ToastLength.Short).Show();
                        break;
                    case Resource.Id.edit:
                        Toast.MakeText(context, "edit " + vh.AdapterPosition.ToString(), ToastLength.Short).Show();
                        break;
                }
            };
            popup.Show();
        };
        return vh;
    }
        // Metodo che specifica il contenuto del ViewHolder (effettua il bind dei dati)
    public override void OnBindViewHolder(ViewHolder holder, int position)
    {


        ViewHolderCard vh = holder as ViewHolderCard;
        vh.txtVarianteId.Text = varianti[position].ID.ToString();
        vh.txtVarianteModello.Text = varianti[position].codiceModello;
        vh.txtVarianteBrand.Text = varianti[position].brand;

        if (varianti[position].fotoUrl != null)
        {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.InSampleSize = 1;
            Bitmap myBitmap = BitmapFactory.DecodeFile(Utils.urlImageToThumb(varianti[position].fotoUrl), options);
            vh.imgVariantePhoto.SetImageBitmap(myBitmap);
            //vh.imgVariantePhoto.SetOnTouchListener(new TouchListenerHelper(vh, mDragStartListener)); // Rimosso perchè altrimenti il drag avviene senza long click (basta fare lo swipe sull'immagine ad avviene il drag)
            myBitmap.Dispose();
        }
    }

关于c# - 如何处理卡片 View 中图像按钮内的点击事件以打开弹出菜单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37409839/

相关文章:

android - getErrorDialog 已贬值。更新后的功能是什么,我该如何使用它?

c# - 打电话 ios xamarin

c# - 我应该在哪里启动 DirectX 以便在 C# 中简单使用?

c# - Java 中 Calendar.get() 方法的 C# 等效项是什么?

javascript - 必填字段验证器在回发之前不起作用

java - api 29 的源代码无法下载?

android - 如何使Android应用程序私有(private)

c# - Xamarin 表单添加对 Web 服务的引用

ios - Xamarin 表单 - IOS : How to detect the UIView size changed

c# - 如何在 Blazor 中创建通用 TreeView 组件?