This is Part 2 on How To Set Images to a Custom ListView. This part follows our journey to make Android load image from URL, from the ...
This is Part 2 on How To Set Images to a Custom ListView.
This part follows our journey to make Android load image from URL, from the previous part on the basic of image loading and to use of Universal Image Loader (UIL).Written by Oum Saokosal, the Author of KosalGeek.
In the previous part of this article, I introduced the basic of image loading and the Universal Image Loader library. In this part on the other hand, I am going to mix it with FunDapter. Please read my article on FunDapter if you are not sure how it works.
1. Add Gradle Dependencies and Permissions
First thing first, before you go on to create a custom layout, do not forget to add Gradle dependencies of UIL and add permissions to your project. The first line is for FunDapter and the second one is for UIL.Gradle Dependencies
compile 'com.github.amigold.fundapter:library:1.0' compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.4'
Permisson
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
2. Create a Custom Layout
You should also have created a ListView lvPost in your main layout, which should look like this:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ListView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/lvPost" android:layout_weight="1" /> </LinearLayout>Now, create a new layout by going to app > res > layout > right click on it, choose New > XML > Layout XML File > Enter layout_post.xml. If you recall from the previous post, I wanted to make the UI look like this:
So the code should be like this:
<?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="match_parent" android:orientation="vertical" android:gravity="top"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Description" android:id="@+id/tvDesc" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:text="Favourite" android:id="@+id/tvFav" android:layout_alignParentTop="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" /> </RelativeLayout> <LinearLayout android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="top"> <ImageView android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/ivImage" android:src="@android:drawable/gallery_thumb" android:scaleType="fitCenter" android:adjustViewBounds="true" /> </LinearLayout> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearance" android:text="ImageUrl" android:id="@+id/tvImageUrl" /> </LinearLayout>
3. Create Model Class Post.java
Because we are going to work with a custom Adapter, we need a class to use as model which later on you can use to map attributes from a database table. I name it Post and it has 3 properties.public class Post { public String desc; public String imageUrl; public Integer fav; }
4. Create a Class for Sample Data - Optional
This is just for testing. It is better to make the sample data as a separate class.import java.util.ArrayList; public class SampleData { public static ArrayList<Post> postData(){ ArrayList<Post> postData = new ArrayList<Post>(); Post p1 = new Post(); p1.desc = "Pink Flowers"; p1.imageUrl = "http://img06.deviantart.net/3659/i/2004/05/2/e/pink_flower.jpg"; p1.fav = 542; postData.add(p1); Post p2 = new Post(); p2.desc = "Cupcakes"; p2.imageUrl = "http://graphicslava.com/wp-content/uploads/2013/01/cupcakes65.jpg"; p2.fav = 2432; postData.add(p2); Post p3 = new Post(); p3.desc = "Model"; p3.imageUrl = "http://crizaze.com/wp-content/uploads/2014/12/modeling-agency.jpg"; p3.fav = 632; postData.add(p3); Post p4 = new Post(); p4.desc = "Waterfall View"; p4.imageUrl = "http://i.telegraph.co.uk/multimedia/archive/03176/waterfall-kanchana_3176020k.jpg"; p4.fav = 975; postData.add(p4); Post p5 = new Post(); p5.desc = "Dogs"; p5.imageUrl = "http://4hdwall.com/wp-content/uploads/2013/03/Small_Dogs_Picture.jpg"; p5.fav = 542; postData.add(p5); Post p6 = new Post(); p6.desc = "Sunset"; p6.imageUrl = "http://i.telegraph.co.uk/multimedia/archive/02465/arpita_patra_2465947k.jpg"; p6.fav = 2432; postData.add(p6); Post p7 = new Post(); p7.desc = "Lion and His Son"; p7.imageUrl = "https://melisa4b.files.wordpress.com/2015/03/picture-of-the-day-real-life-simba-and-mufasa-caught-on-camera-in-tanzania-392687-2.jpg"; p7.fav = 632; postData.add(p7); Post p8 = new Post(); p8.desc = "Cave"; p8.imageUrl = "http://sites.psu.edu/whatarttaughtme/wp-content/uploads/sites/16284/2014/09/Impressive-Picture-of-Some-Marble-Caves-Taken-in-Chile.jpg"; p8.fav = 975; postData.add(p8); Post p9 = new Post(); p9.desc = "London"; p9.imageUrl = "http://i.telegraph.co.uk/multimedia/archive/02146/oliver-dixon_2146615i.jpg"; p9.fav = 542; postData.add(p9); Post p10 = new Post(); p10.desc = "Pretty Pink Cupcakes On A Cake Stand"; p10.imageUrl = "http://graphicslava.com/wp-content/uploads/2013/01/cupcakes65.jpg"; p10.fav = 2432; postData.add(p10); Post p11 = new Post(); p11.desc = "Handsome Dog"; p11.imageUrl = "http://i2.dailyrecord.co.uk/incoming/article1432237.ece/ALTERNATES/s1023/AP-DO-NOT-USE-Picture-Editors-Gallery-7.jpg"; p11.fav = 632; postData.add(p11); Post p12 = new Post(); p12.desc = "Pefect Picture"; p12.imageUrl = "https://jumpingpolarbear.files.wordpress.com/2012/11/picture-perfect.jpg"; p12.fav = 975; postData.add(p12); Post p13 = new Post(); p13.desc = "Cute Kitten"; p13.imageUrl = "http://i.telegraph.co.uk/multimedia/archive/03290/kitten_potd_3290498k.jpg"; p13.fav = 542; postData.add(p13); Post p14 = new Post(); p14.desc = "Innocent"; p14.imageUrl = "http://images6.fanpop.com/image/photos/34100000/beautiful-picture-beautiful-pictures-34167733-352-500.jpg"; p14.fav = 2432; postData.add(p14); Post p15 = new Post(); p15.desc = "The Wolverine: Movie"; p15.imageUrl = "http://nerdist.com/wp-content/uploads/2013/07/wolverine3-1024x640.jpg"; p15.fav = 632; postData.add(p15); Post p16 = new Post(); p16.desc = "Style"; p16.imageUrl = "http://bloote.com/wp-content/uploads/2015/07/street-style-Olivia-Palermo.jpg"; p16.fav = 975; postData.add(p16); return postData; } }
5. Add Configuration Code for UIL
UIL needs a suitable configuration to make an image fill up the screen size. Because the code is a bit messy, I create it as a private method. Here is the code:private ImageLoaderConfiguration UILConfig(){ DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder() .cacheInMemory(true) .cacheOnDisk(true) .showImageOnLoading(android.R.drawable.stat_sys_download) .showImageForEmptyUri(android.R.drawable.ic_dialog_alert) .showImageOnFail(android.R.drawable.stat_notify_error) .considerExifParams(true) .bitmapConfig(Bitmap.Config.RGB_565) .imageScaleType(ImageScaleType.EXACTLY_STRETCHED) .build(); ImageLoaderConfiguration config = new ImageLoaderConfiguration .Builder(getApplicationContext()) .threadPriority(Thread.NORM_PRIORITY - 2) .denyCacheImageMultipleSizesInMemory() .diskCacheFileNameGenerator(new Md5FileNameGenerator()) .tasksProcessingOrder(QueueProcessingType.LIFO) .defaultDisplayImageOptions(defaultOptions) .build(); return config; }
Then you need to initiate the ImageLoader with the configuration. Add the bellowed line right after super.setContentView(R.layout.activity_main):
ImageLoader.getInstance().init(UILConfig());
6. Use BindDictionary to Bind Image
The BindDictionary class is part of the FunDapter library. Here, it is used to bind data from the SampleData.java into an ArrayList of Post.java.ArrayList<Post> posts = SampleData.postData(); BindDictionary<Post> dict = new BindDictionary<Post>(); dict.addStringField(R.id.tvDesc, new StringExtractor<Post>() { @Override public String getStringValue(Post post, int i) { return post.desc; } } ); dict.addStringField(R.id.tvImageUrl, new StringExtractor<Post>() { @Override public String getStringValue(Post post, int i) { return post.imageUrl.toString(); } } ); dict.addStringField(R.id.tvFav, new StringExtractor<Post>() { @Override public String getStringValue(Post post, int i) { return post.fav.toString() + " likes"; } } ); dict.addDynamicImageField(R.id.ivImage, new StringExtractor<Post>() { @Override public String getStringValue(Post post, int i) { return post.imageUrl; } }, new DynamicImageLoader() { @Override public void loadImage(String imageUrl, ImageView imageView) { ImageLoader.getInstance().displayImage(imageUrl, imageView); } } );Please note that in the DynamicImageLoader inner class. It is where you can use any library to display an image. Here, I call UIL's ImageLoader.getInstance().displayImage to display an image from a URL to an ImageView.
7. Use FunDapter to Create ListView Adapter
Finally, the FunDapter is used to mix up all the ingredients to satisfy a ListView. The code is as simple as this:FunDapter adapter = new FunDapter(this, posts, R.layout.layout_post, dict); ListView lvPost = (ListView)findViewById(R.id.lvPost); lvPost.setAdapter(adapter);After running, you should have this: