Поиск по этому блогу

понедельник, 11 марта 2013 г.

Создание кастомного ArrayAdapter'a для ListView

Так получилось что в предыдущей статье я не совсем правильно сделал адаптер, в этой статье я хочу исправиться и написать его правильно что бы вы могли увидеть как нужно делать, а как нет. В обоих случаях он работает нормально но когда вы делаете как в первом варианте оно смотрится грязно и не аккуратно. По этому я решил переписать на более читабельный вариант.


Для начала по традиции нам нужно в манифесте прописать доступ в интернет так как мы будем скачивать картинки из интернета.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.arrayadaptersample"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <uses-permission android:name="android.permission.INTERNET"/>
    
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.arrayadaptersample.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>


Теперь нужно создать класс с сеттерами и гетерами для записи данных и чтения из массива, для этого давайте создадим класс UserFB который будет содержать конструктор в который мы будем передавать данные и сеттеры и гетеры.

UserFB
public class UserFB {

        String id;
        String name;
        String url;

        /** @param id
         * @param name
         * @param url */
        public UserFB(String id, String name, String url) {

                this.id = id;
                this.name = name;
                this.url = url;
        }

        public String getId() {

                return id;
        }

        public String getName() {

                return name;
        }

        public String getUrl() {

                return url;
        }

        public void setId(String id) {

                this.id = id;
        }

        public void setName(String name) {

                this.name = name;
        }

        public void setUrl(String url) {

                this.url = url;
        }
}


Тут все просто до безумия, есть сеттеры которые отдают данные, и есть гетеры которые их принимают, есть конструктор который будет полученные данные передавать в переменные в сеттеры для выдачи их на экран.

Теперь нам нужно создать наш адаптер который будет все это принимать, записывать, скачивать и обрабатывать.

FriendsAdapter
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.arrayadaptersample.R;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import object.UserFB;
import java.util.ArrayList;
public class FriendsAdapter extends ArrayAdapter<UserFB> { // унаследовали от нашего класса UserFB

        private final Activity activity;
        //
        private final ArrayList<UserFB> entries;

        // конструктор класса, принимает активность, листвью и массив данных
        public FriendsAdapter(final Activity a, final int textViewResourceId, final ArrayList<UserFB> entries) {

                super(a, textViewResourceId, entries);
                this.entries = entries;
                activity = a;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

                View v = convertView;
                ViewHolder holder;
                if (v == null) {
                        LayoutInflater inflater = (LayoutInflater) activity
                                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                        v = inflater.inflate(R.layout.friendlist, parent, false);
                        holder = new ViewHolder();
                        // инициализируем нашу разметку
                        holder.textView = (TextView) v.findViewById(R.id.label);
                        holder.imageView = (ImageView) v.findViewById(R.id.logo);
                        v.setTag(holder);
                } else {
                        holder = (ViewHolder) v.getTag();
                }
                UserFB userFB = entries.get(position);
                if (userFB != null) {
                        // получаем текст из массива
                        holder.textView.setText(userFB.getName());
                        // скачиваем картинки
                        ImageLoader imageLoader = ImageLoader.getInstance();
                        imageLoader.init(ImageLoaderConfiguration.createDefault(getContext()));
                        imageLoader.displayImage(userFB.getUrl(), holder.imageView);
                }
                return v;
        }

        // для быстроты вынесли в отдельный класс
        private static class ViewHolder {

                public ImageView imageView;
                public TextView textView;
        }
}


Тут мы обрабатываем полученные данные из массива, скачиваем картинки и загружаем полученный текст из массива. Целью статического внутреннего класса ViewHolder является быстродействие, если вы хотите что бы ListView подгружался быстрее вынесите определение этих объектов в отдельный класс и тогда оно будет грузиться быстрее. Так как view.findViewById тяжелый для дроида при выносе в отдельный класс он не вызывается постоянно, а единожды при создании активности.

Осталось только создать активность которая будет вводить / выводить данные из / в массив и отображать на экране.

Для начала создадим разметку, как обычно это у нас будет листвью, если вы хотите что-то другое то делайте по своему, а мне нужно было именно оно (:

activity_main.xml
<RelativeLayout 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">

    <ListView
        android:id="@+id/listView1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </ListView>
</RelativeLayout>


И для вывода кастомный список.

friendlist.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="5dp" >

    <ImageView
        android:id="@+id/logo"
        android:layout_width="50px"
        android:layout_height="50px"
        android:layout_marginLeft="5px"
        android:layout_marginRight="20px"
        android:layout_marginTop="5px" >
    </ImageView>

    <TextView
        android:id="@+id/label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30px" >
    </TextView>
</LinearLayout>


В принципе как в предыдущей статье, старался максимально приблизить к предыдущей статье. Все а теперь нам осталось в уже существующий MainActivity вписать то что мы внесем в массив и куда мы это все выведем.

MainActivity
import adapter.FriendsAdapter;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
import object.UserFB;
import java.util.ArrayList;
public class MainActivity extends Activity {

        private FriendsAdapter adapter;
        private final ArrayList<UserFB> fetch = new ArrayList<UserFB>();
        private ListView lv;

        @Override
        protected void onCreate(Bundle savedInstanceState) {

                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
                //заполняем массив данными
                UserFB one = new UserFB("1", "Парк-авеню, 666",
                                "http://torrents.kharkov.ua/torrents/images/thumb2_544700.jpg");
                UserFB two = new UserFB("2", "Викинги ",
                                "http://torrents.kharkov.ua/torrents/images/thumb2_571090.jpg");
                UserFB three = new UserFB("3", "Подозреваемый",
                                "http://torrents.kharkov.ua/torrents/images/thumb2_540790.jpg");
                //далее запоминаем их в массиве
                fetch.add(one);
                fetch.add(two);
                fetch.add(three);
                lv = (ListView) findViewById(R.id.listView1);
                //выводим в листе
                adapter = new FriendsAdapter(MainActivity.this, R.id.listView1, fetch);
                lv.setAdapter(adapter);
        }
}


Получиться у вас должно вот такое


Простите что так мало объяснений по комментариям я думаю понятно что делает код и в каком порядке.

Исходники


Скачать с GitHub || Скачать с Dropbox