For Beginners

Thư viện ảnh Android sử dùng PlaceHolderView nâng cao

Giới thiệu

Kiến thức liên quan: Json, Image Url Loading, nested image views and PlaceHolderView.

  • Mục tiêu của hướng dẫn:
  1. Xây dựng danh sách ảnh với hai kiểu view. Một kiểu trên top với một danh sách ảnh nằm ngang. Một kiểu là danh sách dọc, phía dưới kiểu 1. Và sử dụng các animations để hiển thị ảnh như ảnh gif ở trên.
  2. Ảnh sẽ được load từ url bằng thư viện Glide
  3. Link ảnh sẽ được định nghĩa trong một file json. File json này sẽ được để trong thư mục assets .
  4. Dữ liệu Json sẽ được convert thông qua thư viện Gson.
  5. Cấu trúc này cũng sẽ tương thích với việc lấy dữ liệu ảnh từ trên server.

Các bước thực hiện

  • Bước 1: Create một ứng dụng mới và cấu hình file build.gradle như sau:
android {
    ...
    sourceSets {
        main {
            assets.srcDirs = ['src/main/assets', 'src/main/assets/']
            res.srcDirs = ['src/main/res', 'src/main/res/drawable']
        }
    }
}

dependencies {
    ...
    compile 'com.mindorks:placeholderview:0.7.1'
    compile 'com.android.support:cardview-v7:25.3.1'
    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'com.google.code.gson:gson:2.7'
}
  • Lưu ý:
  1. Thêm một folder assets vào main directory và trỏ đến nó trong lớp gradle assets.srcDirs
  2. CardView sẽ được sử dụng để hiển thị các hình ảnh.
  3. Thêm permision internet:
<uses-permission android:name="android.permission.INTERNET"/>
  • Bước 2: Tạo file activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <com.mindorks.placeholderview.PlaceHolderView
        android:id="@+id/galleryView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="vertical"/>
</LinearLayout>
  • Bước 3: Tạo file activity_item_big.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        app:cardCornerRadius="6dp"
        app:cardElevation="4dp">
        <ImageView
            android:id="@+id/imageView"
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:scaleType="centerCrop"
            android:src="@android:color/holo_orange_dark"/>
    </android.support.v7.widget.CardView>
</LinearLayout>
  • Bước 4

Tạo file activity_item_small.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <android.support.v7.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        app:cardElevation="3dp"
        app:cardCornerRadius="6dp">
        <ImageView
            android:id="@+id/imageView"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:scaleType="centerCrop"
            android:src="@android:color/holo_orange_dark"/>
    </android.support.v7.widget.CardView>
</LinearLayout>
  • Bước 5:

Tạo file activity_item_small_list.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <com.mindorks.placeholderview.PlaceHolderView
        android:id="@+id/placeholderview"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="vertical"/>
</LinearLayout>
  • Bước 6: Đặt file json vào thư mục assets. File json có cấu trúc như sau:
[
    {
        "url" : "http://www.allbesttop10.com/wp-content/uploads/2015/01/Venezuela-Beautiful-Girls.jpg"
    },
    {
        "url" : "http://hdwallpaperbackgrounds.net/wp-content/uploads/2015/10/Most-Beautiful-Girls-In-The-World-Wallpapers-1024x683.jpg"
    },
    {
        "url" : "http://photographyinspired.com/media/2014/01/Beautiful-Girl-Wallpapers.jpg"
    },
    {
        "url" : "http://img1.rnkr-static.com/list_img_v2/8192/1228192/C520/famous-men-you-d-want-to-have-a-beer-with-u2.jpg"
    },
    {
        "url" : "https://files.brightside.me/files/news/part_14/145555/1519055-650-1461578948-1.jpg"
    },
    {
        "url" : "http://fashion.lilithezine.com/images/Supermodel-Paris-Hilton.jpg"
    },
    {
        "url" : "http://tutzone.org/wp-content/uploads/2013/04/flirting-middle-shool.jpg"
    },
    {
        "url" : "http://photographyinspired.com/media/2014/01/Top-15-Portraits-of-Beautiful-Girls2.jpg"
    },
    {
        "url" : "http://cdn.playbuzz.com/cdn/67f930d0-8371-46d2-8867-08ade74e7ca0/518055f4-f558-4282-944f-1d30a86de875_560_420.jpg"
    },
    {
        "url" : "http://unbelievable.com/wp-content/uploads/2015/12/IMG_2583.jpg"
    },
    {
        "url" : "http://img2.izismile.com/img/img5/20120210/640/there_are_beautiful_girls_here_640_08.jpg"
    },
    {
        "url" : "http://3.bp.blogspot.com/-ZyV0-iKl24k/Tl9lB0p2U8I/AAAAAAAANTk/JaY0YbP0FWI/s1600/Super+Guns+HD+Wallpapers++%25285%2529.jpg"
    },
    {
        "url" : "https://s-media-cache-ak0.pinimg.com/736x/92/ba/b8/92bab89e660ac4f1a7b27cff4882ffe2.jpg"
    },
    {
        "url" : "http://cdn8.staztic.com/app/a/2552/2552630/hot-guns-super-hd-2-2-s-307x512.jpg"
    },
    {
        "url" : "http://www.nirapadnews.com/english/wp-content/uploads/2015/03/miranda-kerr-wonderbra-lingerie-2015-photos4-710x470.jpg"
    },
    {
        "url" : "https://cdn2.wtvox.com/wp-content/uploads/human-robots-e1433163724309.jpg"
    },
    {
        "url" : "http://s6.favim.com/610/151023/pretty-inspiration-inspirations-beautiful-Favim.com-3466352.jpg"
    },
    {
        "url" : "https://cnet4.cbsistatic.com/hub/i/2011/10/27/a66dfbb7-fdc7-11e2-8c7c-d4ae52e62bcc/android-wallpaper5_2560x1600_1.jpg"
    },
    {
        "url" : "http://pixel.nymag.com/imgs/fashion/daily/2016/01/20/20-clueless-male-read.w529.h352.jpg"
    },
    {
        "url" : "http://g01.a.alicdn.com/kf/HTB1f3DYHFXXXXarapXXq6xXFXXXH/European-And-American-Brands-Nb-Bra-Underwear-Lace-Sexy-Girls-Gather-Lady-Adjustable-Bra-Set.jpg"
    },
    {
        "url" : "http://1mhowto.com/wp-content/uploads/2014/12/Android.jpg"
    },
    {
        "url" : "https://lh4.googleusercontent.com/-9vNpxw3oiR8/UTBfHmBxKVI/AAAAAAAAAPw/Pi0j4ofE3mw/w800-h800/photo.jpg"
    }
]
  • Bước 7: Tạo file Utils.java:
public class Utils {

    private static final String TAG = "Utils";

    public static List<Image> loadImages(Context context){
        try{
            GsonBuilder builder = new GsonBuilder();
            Gson gson = builder.create();
            JSONArray array = new JSONArray(loadJSONFromAsset(context, "images.json"));
            List<Image> imageList = new ArrayList<>();
            for(int i=0;i<array.length();i++){
                Image image = gson.fromJson(array.getString(i), Image.class);
                imageList.add(image);
            }
            return imageList;
        }catch (Exception e){
            Log.d(TAG,"seedGames parseException " + e);
            e.printStackTrace();
            return null;
        }
    }

    private static String loadJSONFromAsset(Context context, String jsonFileName) {
        String json = null;
        InputStream is=null;
        try {
            AssetManager manager = context.getAssets();
            Log.d(TAG,"path "+jsonFileName);
            is = manager.open(jsonFileName);
            int size = is.available();
            byte[] buffer = new byte[size];
            is.read(buffer);
            is.close();
            json = new String(buffer, "UTF-8");
        } catch (IOException ex) {
            ex.printStackTrace();
            return null;
        }
        return json;
    }
}
  • Chú ý: File Utils có chứa những phương thức để convert dữ liệu từ file json sang java object.

  • Bước 8: Tạo file data Image.java.

public class Image {

    @SerializedName("url")
    @Expose
    private String imageUrl;

    public String getImageUrl() {
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }
}
  • Bước 9:

Viết một file java ImageTypeBig.java có nhiệm vụ convert dữ liệu và đổ dữ liệu vào các ViewItem

@Animate(Animation.ENTER_LEFT_DESC)
@NonReusable
@Layout(R.layout.gallery_item_big)
public class ImageTypeBig {

    @View(R.id.imageView)
    private ImageView imageView;

    private String mUlr;
    private Context mContext;
    private PlaceHolderView mPlaceHolderView;

    public ImageTypeBig(Context context, PlaceHolderView placeHolderView, String ulr) {
        mContext = context;
        mPlaceHolderView = placeHolderView;
        mUlr = ulr;
    }

    @Resolve
    private void onResolved() {
        Glide.with(mContext).load(mUlr).into(imageView);
    }

    @LongClick(R.id.imageView)
    private void onLongClick(){
        mPlaceHolderView.removeView(this);
    }
}
  • Lưu ý:
  1. @NonReusable là một annotation trong PlaceHolderView, được sử dụng trong trường hợp chúng ta muốn release tất cả các tài nguyên và tham chiếu nếu bị xóa khỏi danh sách và không được sử dụng cùng một object trong phương thức addView () của PlaceHolderView.
  2. @layout là annotation được sử dụng để bind layout với class này.
  3. @View được sử dụng để bind các view trong layout.
  4. @Resolve được sử dụng để vận hành trên các reference từ @View, nói ngắn gọn nếu chúng ta muốn xác định bất kỳ thao tác nào trên view thì nên đặt trong một phương thức và thêm annotation @Resolve.
  5. @Animate () được sử dụng để định nghĩa các animations được xác định trong lớp Animation.
  • Bước 10: Tạo file ImageTypeSmall.java
@Animate(Animation.CARD_TOP_IN_DESC)
@NonReusable
@Layout(R.layout.gallery_item_small)
public class ImageTypeSmall {

    @View(R.id.imageView)
    private ImageView imageView;

    private String mUlr;
    private Context mContext;
    private PlaceHolderView mPlaceHolderView;

    public ImageTypeSmall(Context context, PlaceHolderView placeHolderView, String ulr) {
        mContext = context;
        mPlaceHolderView = placeHolderView;
        mUlr = ulr;
    }

    @Resolve
    private void onResolved() {
        Glide.with(mContext).load(mUlr).into(imageView);
    }

    @LongClick(R.id.imageView)
    private void onLongClick(){
        mPlaceHolderView.removeView(this);
    }
}
  • Bước 11:
@Animate(Animation.CARD_TOP_IN_DESC)
@NonReusable
@Layout(R.layout.gallery_item_small_list)
public class ImageTypeSmallList {

    @View(R.id.placeholderview)
    private PlaceHolderView mPlaceHolderView;

    private Context mContext;
    private List<Image> mImageList;

    public ImageTypeSmallList(Context context, List<Image> imageList) {
        mContext = context;
        mImageList = imageList;
    }

    @Resolve
    private void onResolved() {
        mPlaceHolderView.getBuilder()
                .setHasFixedSize(false)
                .setItemViewCacheSize(10)
                .setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false));

        for(Image image : mImageList) {
            mPlaceHolderView.addView(new ImageTypeSmall(mContext, mPlaceHolderView, image.getImageUrl()));
        }
    }
}
  • Lưu ý:
  1. Class này là bắt buộc để tạo chế độ xem danh sách lồng nhau
  2. Việc Nesting được thực hiện bằng cách sử dụng PlaceHolderView trong mainView
  • Cuối cùng là file MainActivity.java
public class MainActivity extends AppCompatActivity {

    private PlaceHolderView mGalleryView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mGalleryView = (PlaceHolderView)findViewById(R.id.galleryView);
        setupGallery();
    }

    private void setupGallery(){

        List<Image> imageList = Utils.loadImages(this.getApplicationContext());
        List<Image> newImageList = new ArrayList<>();
        for (int i = 0; i <  (imageList.size() > 10 ? 10 : imageList.size()); i++) {
            newImageList.add(imageList.get(i));
        }
        mGalleryView.addView(new ImageTypeSmallList(this.getApplicationContext(), newImageList));

        for (int i = imageList.size() - 1; i >= 0; i--) {
            mGalleryView.addView(new ImageTypeBig(this.getApplicationContext(), mGalleryView, imageList.get(i).getImageUrl()));
        }
    }
}

Nguồn tham khảo: https://blog.mindorks.com/android-advance-image-gallery-example

Registration Login
Sign in with social account
or
Lost your Password?
Registration Login
Sign in with social account
or
A password will be send on your post
Registration Login
Registration