Sunday, February 9, 2014

ListView Using ActivityListItem Style & Image w/ onListItemClick Event


In this post we'll modify the ListView to use the ActivityListItem style.  ActivityListItem is another built-in view which will display an image and a single line of text for each row.

The People class will now have a property added that provides the image name to be displayed.

  class People 
    {
        public string FirstName { get; set; }
        public string LastName { get; set;}
        public string ImgURL { get; set; }
    }



The helper method which provides the data will populate a List of People objects with the values we want to display. (In a later post, we'll modify this to pull the data from a web service rather than hard-coding it).

        private List<People> PopulatePeopleData() {
            // this is just done in this demo for simplicity to create the People objects
            return new List<People> ()
            {

                new People { FirstName = "Anita", LastName = "Drink" , ImgURL = "images/anita.jpg"},
                new People { FirstName = "Amanda", LastName = "Reconwith", ImgURL = "images/amanda.jpg" },
                new People { FirstName = "Warren", LastName = "Peace", ImgURL = "images/Warren.jpg" },
                new People { FirstName = "Rhonda", LastName = "Corner" , ImgURL = "images/Rhonda.jpg"},
                new People { FirstName = "Karen", LastName = "Feeding" , ImgURL = "images/Karen.jpg"},
                new People { FirstName = "Rufus Lee", LastName = "King", ImgURL = "images/Rufus.jpg" },
                new People { FirstName = "Winston", LastName = "Payne" , ImgURL = "images/Winston.jpg"},
                new People { FirstName = "Marian", LastName = "Haste" , ImgURL = "images/Marian.jpg"},
                new People { FirstName = "Augusta", LastName = "Wind", ImgURL = "images/Augusta.jpg" },
                new People { FirstName = "Ben", LastName = "Dover", ImgURL = "images/Ben.jpg" },
                new People { FirstName = "Dan", LastName = "Druff", ImgURL = "images/Dan.jpg" },
                new People { FirstName = "Dick", LastName = "Tator", ImgURL = "images/Dick.jpg" },
                new People { FirstName = "Marty", LastName = "Graw", ImgURL = "images/Marty.jpg" },
                new People { FirstName = "Lauren", LastName = "Order", ImgURL = "images/Lauren.jpg" },
                new People { FirstName = "Les", LastName = "More", ImgURL = "images/Les.jpg" },
                new People { FirstName = "Molly", LastName = "Keull", ImgURL = "images/Molly.jpg" },
                new People { FirstName = "Rhoda", LastName = "Booke", ImgURL = "images/Rhoda.jpg" },
                new People { FirstName = "Rich", LastName = "Feller", ImgURL = "images/Rich.jpg" },
                new People { FirstName = "Holly", LastName = "Day", ImgURL = "images/Holly.jpg" },
                new People { FirstName = "Polly", LastName = "Ester", ImgURL = "images/Polly.jpg" },
                new People { FirstName = "Paige", LastName = "Turner", ImgURL = "images/Paige.jpg" },
                new People { FirstName = "Neil", LastName = "Down", ImgURL = "images/Neil.jpg" },
                new People { FirstName = "Jack", LastName = "Pott", ImgURL = "images/Jack.jpg" },
                new People { FirstName = "Miles", LastName = "Long", ImgURL = "images/Miles.jpg" },
                new People { FirstName = "Joy", LastName = "Kil", ImgURL = "images/Joy.jpg" }

            };
        }




The images are stored in the images folder under the Assets folder in the project.  Make sure to use a lower case "i"on the images folder or Android may not be able to locate it.  Also make sure that any images in the folder are set to build action: AndroidAsset by right-clicking on the image or the compiler will throw an error.  AndroidAssets will be included in the package when it is compiled.




In the data adapter PeopleAdapter.cs, layout style is set to ActivityListItem.  In this style, only Text1 will have data, so we won't need the Text2 used in the previous examples.  


        public override View GetView (int position, View rowView, ViewGroup parent)
        {

            // the rowView that is being filled may, or may not exist.  If not, inflate a new one, 
            //  otherwiser reuse the one passed in.
            var view = rowView;
            if (view == null) {
                // ListActivities have built in listviews that fill the whole screen.  There is no need for an AXML Layout
                // SimpleListItem2 is a predefined style with 2 text views, the first being bolder than the second
                //   no special AXML is required if this style is adequate
                view = context.LayoutInflater.Inflate (Android.Resource.Layout.ActivityListItem, null);
            }

            var people = data [position];  //get the people object that corresponds to this position

            // Only the first Text1 TextView can be used on an ActivityListItem
            view.FindViewById<TextView> (Android.Resource.Id.Text1).Text = people.LastName;
//            view.FindViewById<TextView> (Android.Resource.Id.Text2).Text = people.FirstName;

            // Get a reference to the built-in Icon ImageView 
            ImageView img = view.FindViewById<ImageView> (Android.Resource.Id.Icon);
            // set the image using the SetImageDrawable method. We'll use a helper function in a static class
            // to return the image based on the the ImgURL from the people object
            img.SetImageDrawable(GetImage.GetImageFromURL(people.ImgURL, context));

            return view;  // return the formatted view

        }


GetImage.GetImageFromURL will be called from a static class to retrieve the drawable image from the assets and return it to be inserted in the row view.  This method will also be used later to display the image in a full screen view so the calling Activity is passed in as the context.



    static class GetImage
    {

        public static Drawable GetImageFromURL(string url, Activity context) 
        {

            Drawable headshotDrawable = null;
            try 
            {
                headshotDrawable = Drawable.CreateFromStream(context.Assets.Open(url), null);
            }
            catch (Exception ex) 
            {         
                     headshotDrawable = Drawable.CreateFromStream(context.Assets.Open("images/photo.png"), null);
            }
            return headshotDrawable;
        }
    }



To activate the onClick event when the user clicks on one of the rows, we'll override OnListItemClick
in MainActivity.cs.  A list of strings from the people object that corresponds to the position that was clicked will be added to the list to be passed in the intent to a new activity will will display a full screen of information.  The data adapter PeopleAdapter instance people used by the MainActivity will return the corresponding people object when passed the position on the screen

public class MainActivity : ListActivity
    {
        PeopleAdapter people; 

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

            // create a new instance of the PeopleAdapter and pass a reference to this activity so that the adapter
            // can inflate new rows in the in the built-in ListView that comes with a ListActivity class
            people = new PeopleAdapter (this);
            ListView.Adapter = people;
        }

    protected override void OnListItemClick(ListView l, View u, int position, long id)
        {             
            List<string> pList = new List<string>();
            pList.Add(people[position].FirstName);
            pList.Add(people[position].LastName);
            pList.Add(people[position].ImgURL);

            var intent = new Intent (this, typeof(NewActivity));

            intent.PutStringArrayListExtra ("People", pList);
            StartActivity (intent);
        }



The new activity will retrieve the list of strings passed in the intent and populate a new AXML layout.  It will also use the GetImage.GetImageFromURL created above to retrieve the image from the Assets/images folder.


    [Activity (Label = "NewActivity",Theme = "@android:style/Theme.NoTitleBar")]            
    public class NewActivity : Activity
    {
        protected override void OnCreate (Bundle bundle)
        {
            base.OnCreate (bundle);

            SetContentView (Resource.Layout.People);

            var pList = Intent.Extras.GetStringArrayList ("People") ?? new string[0];

            TextView fn = FindViewById<TextView> (Resource.Id.FirstName);
            TextView ln = FindViewById<TextView> (Resource.Id.LastName);
            fn.Text = pList [0];
            ln.Text = pList [1];
            string pic = pList [2];

            ImageView img = FindViewById<ImageView> (Resource.Id.Picture);
            img.SetImageDrawable(GetImage.GetImageFromURL(pic, this));

        }
    }



The following screen is displayed by the NewActivity when the corresponding row is clicked by the user.


No comments:

Post a Comment