ItemSelected事件未在使用ListView适配器 - Xamarin Android填充的ListView上触发

时间:2017-08-29 19:04:39

标签: c# android listview xamarin.android listadapter

扩展标题:

  

“问题是我在ListView中的ImageButton。它   正在窃取焦点并消耗触摸事件。“

LilMoke的解决方案是在他希望触发"Focusable = false" //on any element in the row 事件的行中设置每个元素的以下属性:

ItemSelected

似乎很好,这导致了后来的建议:

imageButton.Focusable = false;
imageButton.FocusableInTouchMode = false;
imageButton.Clickable = true;

imageButton.Click += (sender, args) => Console.WriteLine("ImageButton {0} clicked", position);
假设您的RecycleView的根元素是LinearLayout

,则在您的LinearLayout中

因为Android不允许任何项目在android:descendantFocusability="blocksDescendants" 中具有焦点。一个更简洁的版本,可以防止行项获得焦点。问题是在实现这个之后,我仍然无法触发ListView事件。

我尝试过一个凌乱的解决方法:

1) 我尝试从ItemSelected模板的声明中抓取并设置每个元素的FocusableClickable属性,但这很麻烦,不允许我访问StartActivity函数,它是一部分任何直接从Activity继承的类。 因为这是一个适配器,它继承自BaseAdapter<>代替。

我以前的问题一直被嘲笑,但在阅读完this之后,我正试图改变我的邪恶方式。

以下是与我所描述的相关的代码,应该更好地说明情况:

row.axml

RecyclerView

listContacts.axml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="60dp"
    android:weightSum="100"
    android:descendantFocusability="blocksDescendants"
    android:background="#F1F1F1">
    <ImageView
        android:id="@+id/imgPic"
        android:src="@drawable/ic_action_person"
        android:layout_width="0dp"
        android:layout_weight="25"
        android:layout_height="wrap_content"
        android:background="#3B5998"
        android:adjustViewBounds="true"
        android:scaleType="centerCrop" />
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="0dp"
        android:layout_height="match_parent"
        android:layout_weight="65">
        <TextView
            android:id="@+id/txtName"
            android:text="Contact Name"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="65"
            android:gravity="center"
            android:textSize="18sp"
            android:textColor="#000" />
        <TextView
            android:id="@+id/txtNumber"
            android:text="(555)-444-2222"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="65"
            android:gravity="center"
            android:textSize="18sp"
            android:textColor="#000" />
    </LinearLayout>
    <ImageButton
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        android:src="@drawable/xiconsmall"
        android:id="@+id/btnDeleteAlbum" />
</LinearLayout>

ListContacts.cs

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:minWidth="25px"
        android:minHeight="25px">
        <ListView
            android:layout_width="match_parent"
            android:layout_height="500dp"
            android:visibility="visible"
            android:id="@+id/listView"
            android:fastScrollAlwaysVisible="true"
            android:fastScrollEnabled="true"
            android:smoothScrollbar="true"
            android:clickable="true" />
        <Button
        android:text="Button"
        android:visibility="visible"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/btnAdd" />
    </LinearLayout>
</ScrollView>

ContactListAdapter.cs

namespace MainMobileDevProject
{
    [Activity(Label = "Display row items", MainLauncher = true, Icon = "@drawable/xs")]    
    //public class ListContacts: AppCompatActivity
    public class ListContacts : Activity
    {
        private ListView mListView;
        private BaseAdapter<Contact> mAdapter;
        private List<Contact> mContacts;
        private ImageView mSelectedPic;        
        private Button mBtnAddPics, button;
        public List<byte[]> imagesByteList = new List<byte[]>();
        public List<string> imagesTagsList = new List<string>();
        Bitmap myBitmap;


        private ImageView _imageView;

        public static class App
        {
            public static File _file;
            public static File _dir;
            public static Bitmap bitmap;
        }

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

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.listContacts);

            string text = Intent.GetStringExtra("MyData") ?? "Data not available";
            System.Diagnostics.Debug.Write("DATA WE PASSED HERE IS : " + text);

            mListView = FindViewById<ListView>(Resource.Id.listView);
            mContacts = new List<Contact>();
            mBtnAddPics = FindViewById<Button>(Resource.Id.btnAdd);

            //mAdapter = new ContactListAdapter(this, Resource.Layout.pager_item, mContacts, action);
            mAdapter = new ContactListAdapter(this, Resource.Layout.row_contact, mContacts);




            //having an issue with my list adapter
            //none of my event items such as click or itemselected will fire
            //debug log aren't even firing, the proposed solution is to set each row's child elements to have a value of
            //false for "focusable", and a better solution again is to set the root of the row's layout to have 
            // an attribute of android:descendantFocusability="blocksDescendants". this can be seen in row_contact.axml
            //the problem though is that now the row's contents can be accessed, but not from this module, but only in the adapter, which makes things messy of course, but I haven't been able to start a new activity
            //    due to my adapter(ContactListAdapter.cs) inheriting from the BaseAdapter class


            mListView.ItemClick += lv_ItemClick;

            void lv_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
            {
                //not firing
                System.Diagnostics.Debug.Write("LISTVIEW CLICKED AT  : " + e.Position);
            }


                mListView.Adapter = mAdapter;
                //mListView.NotifyDataSetChanged();


            mListView.ItemSelected += (sender, e) =>
            {
                System.Diagnostics.Debug.Write("LISTVIEW CLICKED AT  : " + e.Position);
            };

            mListView.ItemClick += (sender, e) =>
            {
                System.Diagnostics.Debug.Write("LISTVIEW CLICKED AT  : " + e.Position);
            };

            mAdapter.NotifyDataSetChanged();

        }

        private void MListView_ItemClick(object sender, ItemClickEventArgs e)
        {
            System.Diagnostics.Debug.Write("myBitmap row id : " + e.Id);
            System.Diagnostics.Debug.Write("myBitmap row parent is : " + e.Parent);
            System.Diagnostics.Debug.Write("myBitmap row position : " + e.Position);
            System.Diagnostics.Debug.Write("myBitmap row view : " + e.View);
        }



        private void MBtnAddPics_Click(object sender, EventArgs e)
        {
            MySqlConnection con = new MySqlConnection("Server=someawsconstring.something.eu-west-1.rds.amazonaws.com;Port=3307;database=ichangedthis;User Id=ichangedthis;Password=ichangedthis;charset=utf8");
            //List<string> imageslist = new List<string>();
            //List<byte[]> imageslist = new List<byte[]>();

            try
            {
                if (con.State == ConnectionState.Closed)
                {
                    con.Open();
                    System.Diagnostics.Debug.Write("CONN OPEN");
                    //string query = "SELECT * FROM tblUserAlbumPhoto HAVING UserID = '" + Intent.GetStringExtra("UsersID") + "' AND AlbumID = '" + Intent.GetStringExtra("UsersID") +"'";                    
                    string query = "SELECT * FROM tblUserAlbumPhoto HAVING UserID = '" + 1 + "' AND AlbumID = '" + 1 +"'";
                    MySqlCommand cmd = new MySqlCommand(query, con);

                    System.Diagnostics.Debug.Write("TRYING TO READ");
                    MySqlDataReader dataReader = cmd.ExecuteReader();

                    while (dataReader.Read())
                    {                        
                        imagesByteList.Add(Convert.FromBase64String(dataReader.GetString(4)));
                        imagesTagsList.Add(dataReader.GetString(5));
                        //System.Diagnostics.Debug.Write("image still as base64 string is : " + dataReader.GetString(1));
                        //System.Diagnostics.Debug.Write("image converted from base64 found is : " + Convert.FromBase64String(dataReader.GetString(1)));
                    }
                    System.Diagnostics.Debug.Write("image ID found is : " + imagesByteList[0]);
                    System.Diagnostics.Debug.Write("image ID found is : " + imagesByteList[1]);
                }

            }
            catch (MySqlException ex)
            {

            }
            finally
            {
                con.Close();
                System.Diagnostics.Debug.Write("CONN CLOSED");
                System.Diagnostics.Debug.Write("image ID count found is : " + imagesByteList.Count);
            }

            CountImagesList();
            if (imagesByteList.Count > 0) //just a test
            {
                CreateImgFromBytes(imagesByteList, imagesTagsList);
            }
        }

        private void CreateImgFromBytes(List<byte[]> imageslist, List<string> tags)
        {
            //foreach(byte[] ba in imageslist)
            for(int y=0;y<imagesByteList.Count;y++)
            {
                mContacts.Add(new Contact() { Name = tags[y], Image = imageslist[y] });
            }
            //mContacts.Add(new Contact() { Name = "abc", Number = "def", Image = imageslist[0] });
            System.Diagnostics.Debug.Write("imageslist lentth is: " + imageslist.Count);
            mAdapter.NotifyDataSetChanged();

            //Decode with InJustDecodeBounds = true to check dimensions
            //Stream stream = ContentResolver.OpenInputStream(data);
            //BitmapFactory.Options options = new BitmapFactory.Options();
            //options.InJustDecodeBounds = true;
            //BitmapFactory.DecodeStream(stream);

            ////Calculate InSamplesize
            //options.InSampleSize = CalculateInSampleSize(options, requestedWidth, requestedHeight);

            ////Decode bitmap with InSampleSize set
            //stream = ContentResolver.OpenInputStream(data); //Must read again
            //options.InJustDecodeBounds = false;
            //Bitmap bitmap = BitmapFactory.DecodeStream(stream, null, options);
            //return bitmap;
        }

        public void CountImagesList()
        {
            System.Diagnostics.Debug.Write("imageslist lentth is: " + imagesByteList.Count);
        }

        private void PicSelected(ImageView selectedPic)
        {
            mSelectedPic = selectedPic;
            Intent intent = new Intent();
            intent.SetType("image/*");
            intent.SetAction(Intent.ActionGetContent);
            this.StartActivityForResult(Intent.CreateChooser(intent, "Selecte a Photo"), 0);
        }

        protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
        {
            base.OnActivityResult(requestCode, resultCode, data);

            //if (resultCode == Result.Ok)
            //{
            //    Stream stream = ContentResolver.OpenInputStream(data.Data);
            //    mSelectedPic.SetImageBitmap(DecodeBitmapFromStream(data.Data, 150, 150));
            //}

            Intent mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);

            Uri contentUri = Uri.FromFile(App._file);
            mediaScanIntent.SetData(contentUri);
            SendBroadcast(mediaScanIntent);

            // Display in ImageView. We will resize the bitmap to fit the display.
            // Loading the full sized image will consume to much memory
            // and cause the application to crash.

            int height = Resources.DisplayMetrics.HeightPixels;
            int width = _imageView.Height;
            App.bitmap = App._file.Path.LoadAndResizeBitmap(width, height);
            System.Diagnostics.Debug.Write("APP . BITMAP IS :: " + App.bitmap);
            if (App.bitmap != null)
            {
                _imageView.SetImageBitmap(App.bitmap);
                myBitmap = App.bitmap;
                //App.bitmap = null;
            }

            // Dispose of the Java side bitmap.
            GC.Collect();
        }

        private void CreateDirectoryForPictures()
        {
            App._dir = new File(
                Environment.GetExternalStoragePublicDirectory(
                    Environment.DirectoryPictures), "Base64Attempt");
            if (!App._dir.Exists())
            {
                App._dir.Mkdirs();
            }
        }

        private bool IsThereAnAppToTakePictures()
        {
            Intent intent = new Intent(MediaStore.ActionImageCapture);
            IList<ResolveInfo> availableActivities =
                PackageManager.QueryIntentActivities(intent, PackageInfoFlags.MatchDefaultOnly);
            return availableActivities != null && availableActivities.Count > 0;
        }

        private void TakeAPicture(object sender, EventArgs eventArgs)
        {
            Intent intent = new Intent(MediaStore.ActionImageCapture);
            App._file = new File(App._dir, String.Format("myPhoto_{0}.jpg", Guid.NewGuid()));
            intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(App._file));
            StartActivityForResult(intent, 0);
        }

        private Bitmap DecodeBitmapFromStream(Android.Net.Uri data, int requestedWidth, int requestedHeight)
        {
            //Decode with InJustDecodeBounds = true to check dimensions
            System.IO.Stream stream = ContentResolver.OpenInputStream(data);
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.InJustDecodeBounds = true;
            BitmapFactory.DecodeStream(stream);

            //Calculate InSamplesize
            options.InSampleSize = CalculateInSampleSize(options, requestedWidth, requestedHeight);

            //Decode bitmap with InSampleSize set
            stream = ContentResolver.OpenInputStream(data); //Must read again
            options.InJustDecodeBounds = false;
            Bitmap bitmap = BitmapFactory.DecodeStream(stream, null, options);
            return bitmap;
        }

        private int CalculateInSampleSize(BitmapFactory.Options options, int requestedWidth, int requestedHeight)
        {
            //Raw height and widht of image
            int height = options.OutHeight;
            int width = options.OutWidth;
            int inSampleSize = 1;

            if (height > requestedHeight || width > requestedWidth)
            {
                //the image is bigger than we want it to be
                int halfHeight = height / 2;
                int halfWidth = width / 2;

                while ((halfHeight / inSampleSize) > requestedHeight && (halfWidth / inSampleSize) > requestedWidth)
                {
                    inSampleSize *= 2;
                }

            }

            return inSampleSize;
        }

        public override bool OnCreateOptionsMenu(IMenu menu)
        {
            MenuInflater.Inflate(Resource.Menu.actionbar_home, menu);
            return base.OnCreateOptionsMenu(menu);
        }

        public override bool OnOptionsItemSelected(IMenuItem item)
        {
            switch (item.ItemId)
            {
                case Resource.Id.add:

                    CreateContactDialog dialog = new CreateContactDialog();
                    FragmentTransaction transaction = FragmentManager.BeginTransaction();

                    //Subscribe to event
                    dialog.OnCreateContact += dialog_OnCreateContact;
                    dialog.Show(transaction, "create contact");
                    return true;

                default:
                    return base.OnOptionsItemSelected(item);
            }

        }

        void dialog_OnCreateContact(object sender, CreateContactEventArgs e)
        {
            mContacts.Add(new Contact() { Name = e.Name, Number = e.Number });
            mAdapter.NotifyDataSetChanged();
        }
    }

    /*
    public static class BitmapHelpers
    {
        public static Bitmap LoadAndResizeBitmap(this string fileName, int width, int height)
        {
            // First we get the the dimensions of the file on disk
            BitmapFactory.Options options = new BitmapFactory.Options { InJustDecodeBounds = true };
            BitmapFactory.DecodeFile(fileName, options);

            // Next we calculate the ratio that we need to resize the image by
            // in order to fit the requested dimensions.
            int outHeight = options.OutHeight;
            int outWidth = options.OutWidth;
            int inSampleSize = 1;

            if (outHeight > height || outWidth > width)
            {
                inSampleSize = outWidth > outHeight
                                   ? outHeight / height
                                   : outWidth / width;
            }

            // Now we will load the image and have BitmapFactory resize it for us.
            options.InSampleSize = inSampleSize;
            options.InJustDecodeBounds = false;
            Bitmap resizedBitmap = BitmapFactory.DecodeFile(fileName, options);

            return resizedBitmap;
        }
    }
    */
}

这是我上面描述的凌乱的解决方法,无法继续使用它

namespace MainMobileDevProject
{
    class ContactListAdapter : BaseAdapter<Contact>
    {
        private Context mContext;
        private int mLayout;
        private List<Contact> mContacts;
        private Action<ImageView> mActionPicSelected;

        public ContactListAdapter(Context context, int layout, List<Contact> contacts, Action<ImageView> picSelected)
        {
            mContext = context;
            mLayout = layout;
            mContacts = contacts;
            mActionPicSelected = picSelected;
        }

        public ContactListAdapter(Context context, int layout, List<Contact> contacts)
        {
            mContext = context;
            mLayout = layout;
            mContacts = contacts;

        }

        public override Contact this[int position]
        {
            get { return mContacts[position]; }
        }

        public override int Count
        {
            get { return mContacts.Count; }
        }

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

        public override View GetView(int position, View convertView, ViewGroup parent)
        {
            View row = convertView;
            //row.notif
            if (row == null)
            {
                row = LayoutInflater.From(mContext).Inflate(mLayout, parent, false);
            }

            row.FindViewById<TextView>(Resource.Id.txtName).Text = mContacts[position].Name;
            row.FindViewById<TextView>(Resource.Id.txtNumber).Text = mContacts[position].Number;

            ImageView pic = row.FindViewById<ImageView>(Resource.Id.imgPic);
            row.Clickable = true;

            if (mContacts[position].Image != null)
            {
                pic.SetImageBitmap(BitmapFactory.DecodeByteArray(mContacts[position].Image, 0, mContacts[position].Image.Length));
            }

            if (mContacts[position].Image == null)
            {
                //here we should replace mcontacts[position] with imageslist[position], then it'll at least pull
                //the 2 byte[] images we have
                //pic.SetImageBitmap(BitmapFactory.DecodeByteArray(mContacts[position].Image, 0, mContacts[position].Image.Length));
                //pic.SetImageBitmap(BitmapFactory.DecodeByteArray(mContacts[position].Image, 0, mContacts[position].Image.Length));
            }
  • 为了澄清,我们提供了一些相关的代码,显示在点击按钮后填充来自MySql数据库的 //var imageButton = row.FindViewById<ImageView>(Resource.Id.imgPic); //imageButton.Focusable = false; //imageButton.FocusableInTouchMode = false; //imageButton.Clickable = true; var removeButton = row.FindViewById<ImageButton>(Resource.Id.btnDeleteAlbum); removeButton.Focusable = false; removeButton.FocusableInTouchMode = false; removeButton.Clickable = true; //imageButton.Click += (sender, args) => //{ // System.Diagnostics.Debug.Write("myBitmap row id :AAAAAAAAAAAAAAAAAAAA "); // Console.WriteLine("ImageButton {0} clicked", position); //}; removeButton.Click += (sender, args) => { System.Diagnostics.Debug.Write("myBitmap row id :AAAAAAAAAAAAAAAAAAAA "); Console.WriteLine("RemoveButton {0} clicked", position); }; //pic.Click -= pic_Click; pic.Click += (object sender, EventArgs e) => { MySqlConnection con = new MySqlConnection("Server=db4free.net;Port=3307;database=ofsligodb;User Id=ofoley1;Password=pinecone;charset=utf8"); try { if (con.State == ConnectionState.Closed) { con.Open(); System.Diagnostics.Debug.WriteLine("CONNECTION OPEN*****: "); MySqlCommand Readcmd = new MySqlCommand("DELETE FROM tblUserAlbumPhoto WHERE UserID = '" + 1 + "' AND " + "AlbumID = '" + 1 + "' and ID = '" + position + "'"); Readcmd.Connection = con; Readcmd.ExecuteNonQuery(); System.Diagnostics.Debug.WriteLine("DELETE SHOULD HAVE HAPPENED*****: "); } } catch (MySqlException ex) { //mTxtImgChoiceInfo.Text = ex.ToString(); } finally { con.Close(); System.Diagnostics.Debug.WriteLine("CONN CLOSED*****: "); } }; return row; } void pic_Click(object sender, EventArgs e) { //Picture has been clicked System.Diagnostics.Debug.Write("YOU CLICKED ME AND THE ROW INDEX WAS : " + e.position); } } }
  • 显示了一些代码,用于将加载的位图调整为缩略图,也没有任何问题。 所有与数据库相关的和图像重新调整大小的代码都可以正常工作,但我认为无论如何要包含其他人的理解是非常重要的。如果它阻碍人们抓住整个项目的情况,请告知我,我将删除。

任何含糊不清/混淆请告诉我。 如果重复请请解释原因,谢谢。

1 个答案:

答案 0 :(得分:0)

据我了解,您需要在适配器的每个row添加OnClick。