+1

Hướng dẫn sử dụng thư viện Glide Image

Tải một hình ảnh từ Internet là khá dễ dàng bằng cách sử dụng thư viện Volley. Nhưng tôi sẽ giới thiệu một giải pháp tốt hơn nhiều so với thư viện hình ảnh Glide của volley. Khi so sánh với Volley, Glide thể hiện tốt hơn trong nhiều trường hợp về hiệu suất và khả năng sử dụng. Dưới đây là những ưu điểm của Glide so với Volley

Hỗ trợ tìm nạp, giải mã, và hiển thị ảnh tĩnh, hình ảnh, và GIF động

Trình giữ chỗ có thể được thêm vào trước khi tải phương tiện

Tải hình thu nhỏ đầu tiên (mờ) trước rồi tải hình ảnh có độ phân giải cao như trong WhatsApp hoặc Facebook.

Tác động qua lại giữa các phương tiện truyền thông

Hỗ trợ chuyển đổi hình ảnh tùy ý như tải hình ảnh trong hình tròn hoặc bất kỳ hình dạng khác.

Bộ nhớ và cơ chế lưu trữ trên đĩa

Hoạt động tốt với cả hai thư viện Volley và OkHttp

VIDEO DEMO

Sử dụng Glide Image bằng cách nào

Trước tiên thêm glide dependency vào build.gradle của bạn.

build.gradle
dependencies {
    // glide
    compile 'com.github.bumptech.glide:glide:3.7.0'
}

Thứ hai tải hình ảnh vào ImageView sử dụng đoạn mã dưới đây.

String imgUrl = "http://api.androidhive.info/images/glide/medium/deadpool.jpg";
 
ImageView imageView = (ImageView) view.findViewById(R.id.thumbnail);
 
Glide.with(mContext).load(imgUrl)
                .thumbnail(0.5f)
                .crossFade()
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into(imageView);

Mẫu JSon

Để xây dựng ứng dụng thư viện, chúng ta sử dụng một mẫu JSON chứa url hình ảnh được yêu cầu. Mỗi hình ảnh được nén và thay đổi kích cỡ ở ba độ phân giải khác nhau, cao, trung bình và nhỏ. Để hiển thị dạng grid, chúng ta tải hình ảnh có độ phân giải trung bình và với việc hiển thị hình ảnh toàn màn hình, chúng ta tải hình ảnh có độ phân giải cao hơn.

Liên kết JSON: http://api.androidhive.info/json/glide.json

[{
    "name": "Deadpool",
    "url": {
        "small": "http://api.androidhive.info/images/glide/small/deadpool.jpg",
        "medium": "http://api.androidhive.info/images/glide/medium/deadpool.jpg",
        "large": "http://api.androidhive.info/images/glide/large/deadpool.jpg"
    },
    "timestamp": "February 12, 2016"
},
{
    "name": "Batman vs Superman",
    "url": {
        "small": "http://api.androidhive.info/images/glide/small/bvs.png",
        "medium": "http://api.androidhive.info/images/glide/medium/bvs.png",
        "large": "http://api.androidhive.info/images/glide/large/bvs.png"
    },
    "timestamp": "March 25, 2016"
}]

Xây dựng ứng dụng Image Gallery

Bước 1

Tạo một dự án mới trong Android Studio từ File ⇒ New Project. Sau đó chọn Activity default, sau đó chọn Next

Bước 2

Mở build.gradle và thêm Glide, Volley và RecyclerView dependencies. Volley được sử dụng để tải json thư viện bằng cách thực hiện gọi HTTP. RecyclerView được sử dụng để hiển thị hình ảnh thư viện trong một mô hình dạng Grid

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.1'
    compile 'com.android.support:design:23.2.1'
    compile 'com.android.support:support-v4:23.2.1'
 
    // RecyclerView
    compile 'com.android.support:recyclerview-v7:23.1.1'
 
    // volley
    compile 'com.android.volley:volley:1.0.0'
 
    // Glide
    compile 'com.github.bumptech.glide:glide:3.7.0'
}

Bước 3

Tạo thêm packages có tên là activity, adapter, app, model and helper giúp tổ chức cho dự án.

Bước 4

Tạo một lớp có tên AppController.java trong packages app. Đây là một lớp singleton, trong đó chúng ta khởi tạo các đối tượng cốt lõi của volley.

AppController.java
package info.androidhive.glide.app;
 
import android.app.Application;
import android.text.TextUtils;
 
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.Volley;
 
public class AppController extends Application {
 
    public static final String TAG = AppController.class
            .getSimpleName();
 
    private RequestQueue mRequestQueue;
 
    private static AppController mInstance;
 
    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;
    }
 
    public static synchronized AppController getInstance() {
        return mInstance;
    }
 
    public RequestQueue getRequestQueue() {
        if (mRequestQueue == null) {
            mRequestQueue = Volley.newRequestQueue(getApplicationContext());
        }
 
        return mRequestQueue;
    }
 
    public <T> void addToRequestQueue(Request<T> req, String tag) {
        // set the default tag if tag is empty
        req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        getRequestQueue().add(req);
    }
 
    public <T> void addToRequestQueue(Request<T> req) {
        req.setTag(TAG);
        getRequestQueue().add(req);
    }
 
    public void cancelPendingRequests(Object tag) {
        if (mRequestQueue != null) {
            mRequestQueue.cancelAll(tag);
        }
    }
}

Bước 5

Mở AndroidManifest.xml và thêm thẻ AppController vào <application>. Thêm quyền INTERNET vì chúng ta cần phải thực hiện gọi HTTP.

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.androidhive.glide">
 
    <uses-permission android:name="android.permission.INTERNET" />
 
    <application
        android:name=".app.AppController"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".activity.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
 
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
 
</manifest>

Chúng ta hãy bắt đầu thêm gallery vào trước.

Thêm Grid Gallery View vào ứng dụng

Bước 6

Mở file lâyout của main activity và thêm RecyclinglerView. Đối với main activity, có hai file layout activity_main.xml và content_main.xml

Activity_main.xml chứa AppBar và Toolbar.

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".activity.MainActivity">
 
    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">
 
        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />
 
    </android.support.design.widget.AppBarLayout>
 
    <include layout="@layout/content_main" />
 
</android.support.design.widget.CoordinatorLayout>

Content_main.xml có chứa các recyclerView để tải các hình ảnh trong grid.

content_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="info.androidhive.glide.activity.MainActivity"
    tools:showIn="@layout/activity_main">
 
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="vertical" />
 
</RelativeLayout>

Bước 7

Trong package helper, tạo một lớp có tên SquareLayout.java. Lớp này giúp các hình ảnh để hiển thị trong tỷ lệ vuông trong grid view.

SquareLayout.java
package info.androidhive.glide.helper;
 
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.widget.RelativeLayout;
 
/**
 * Created by Lincoln on 05/04/16.
 */
class SquareLayout extends RelativeLayout {
 
    public SquareLayout(Context context) {
        super(context);
    }
 
    public SquareLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
 
    public SquareLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
 
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public SquareLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }
 
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // Set a square layout.
        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
    }
}

Bước 8

Trong res ⇒ layout, tạo ra một layout có tên là gallery_thumbnail.xml. Layout này chứa ImageView để hiển thị hình thu nhỏ trong chế độ xem qua.

gallery_thumbnail.xml
<?xml version="1.0" encoding="utf-8"?>
<info.androidhive.glide.helper.SquareLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
 
    <ImageView
        android:id="@+id/thumbnail"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:adjustViewBounds="true"
        android:scaleType="centerCrop" />
</info.androidhive.glide.helper.SquareLayout>

Bước 9

Trong package adapter, tạo một lớp có tên GalleryAdapter.java Đây là một lớp adapter, nó inflates gallery_thumbnail.xml và hiển thị các hình ảnh trong recyclerView.

GalleryAdapter.java
package info.androidhive.glide.adapter;
 
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
 
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
 
import java.util.List;
 
import info.androidhive.glide.R;
import info.androidhive.glide.model.Image;
 
/**
 * Created by Lincoln on 31/03/16.
 */
 
public class GalleryAdapter extends RecyclerView.Adapter<GalleryAdapter.MyViewHolder> {
 
    private List<Image> images;
    private Context mContext;
 
    public class MyViewHolder extends RecyclerView.ViewHolder {
        public ImageView thumbnail;
 
        public MyViewHolder(View view) {
            super(view);
            thumbnail = (ImageView) view.findViewById(R.id.thumbnail);
        }
    }
 
 
    public GalleryAdapter(Context context, List<Image> images) {
        mContext = context;
        this.images = images;
    }
 
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.gallery_thumbnail, parent, false);
 
        return new MyViewHolder(itemView);
    }
 
    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        Image image = images.get(position);
 
        Glide.with(mContext).load(image.getMedium())
                .thumbnail(0.5f)
                .crossFade()
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into(holder.thumbnail);
    }
 
    @Override
    public int getItemCount() {
        return images.size();
    }
 
    public interface ClickListener {
        void onClick(View view, int position);
 
        void onLongClick(View view, int position);
    }
 
    public static class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
 
        private GestureDetector gestureDetector;
        private GalleryAdapter.ClickListener clickListener;
 
        public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final GalleryAdapter.ClickListener clickListener) {
            this.clickListener = clickListener;
            gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
                @Override
                public boolean onSingleTapUp(MotionEvent e) {
                    return true;
                }
 
                @Override
                public void onLongPress(MotionEvent e) {
                    View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
                    if (child != null && clickListener != null) {
                        clickListener.onLongClick(child, recyclerView.getChildPosition(child));
                    }
                }
            });
        }
 
        @Override
        public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
 
            View child = rv.findChildViewUnder(e.getX(), e.getY());
            if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
                clickListener.onClick(child, rv.getChildPosition(child));
            }
            return false;
        }
 
        @Override
        public void onTouchEvent(RecyclerView rv, MotionEvent e) {
        }
 
        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
 
        }
    }
}

Bước 10

Cuối cùng mở MainActivity.java và thực hiện các thay đổi dưới đây

Tải xuống json bằng cách yêu cầu http volley. FetchImages () được sử dụng với mục đích này

Parse json và thêm models vào array list.

Đưa danh sách mảng vào lớp adapter adapter của recyclerView.

MainActivity.java
package info.androidhive.glide.activity;
 
import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
 
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
 
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
 
import java.util.ArrayList;
 
import info.androidhive.glide.R;
import info.androidhive.glide.adapter.GalleryAdapter;
import info.androidhive.glide.app.AppController;
import info.androidhive.glide.model.Image;
 
public class MainActivity extends AppCompatActivity {
 
    private String TAG = MainActivity.class.getSimpleName();
    private static final String endpoint = "http://api.androidhive.info/json/glide.json";
    private ArrayList<Image> images;
    private ProgressDialog pDialog;
    private GalleryAdapter mAdapter;
    private RecyclerView recyclerView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
 
        recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
 
        pDialog = new ProgressDialog(this);
        images = new ArrayList<>();
        mAdapter = new GalleryAdapter(getApplicationContext(), images);
 
        RecyclerView.LayoutManager mLayoutManager = new GridLayoutManager(getApplicationContext(), 2);
        recyclerView.setLayoutManager(mLayoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.setAdapter(mAdapter);
 
        /* recyclerView.addOnItemTouchListener(new GalleryAdapter.RecyclerTouchListener(getApplicationContext(), recyclerView, new GalleryAdapter.ClickListener() {
            @Override
            public void onClick(View view, int position) {
                Bundle bundle = new Bundle();
                bundle.putSerializable("images", images);
                bundle.putInt("position", position);
 
                FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
                SlideshowDialogFragment newFragment = SlideshowDialogFragment.newInstance();
                newFragment.setArguments(bundle);
                newFragment.show(ft, "slideshow");
            }
 
            @Override
            public void onLongClick(View view, int position) {
 
            }
        }));*/
 
        fetchImages();
    }
 
    private void fetchImages() {
 
        pDialog.setMessage("Downloading json...");
        pDialog.show();
 
        JsonArrayRequest req = new JsonArrayRequest(endpoint,
                new Response.Listener<JSONArray>() {
                    @Override
                    public void onResponse(JSONArray response) {
                        Log.d(TAG, response.toString());
                        pDialog.hide();
 
                        images.clear();
                        for (int i = 0; i < response.length(); i++) {
                            try {
                                JSONObject object = response.getJSONObject(i);
                                Image image = new Image();
                                image.setName(object.getString("name"));
 
                                JSONObject url = object.getJSONObject("url");
                                image.setSmall(url.getString("small"));
                                image.setMedium(url.getString("medium"));
                                image.setLarge(url.getString("large"));
                                image.setTimestamp(object.getString("timestamp"));
 
                                images.add(image);
 
                            } catch (JSONException e) {
                                Log.e(TAG, "Json parsing error: " + e.getMessage());
                            }
                        }
 
                        mAdapter.notifyDataSetChanged();
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e(TAG, "Error: " + error.getMessage());
                pDialog.hide();
            }
        });
 
        // Adding request to request queue
        AppController.getInstance().addToRequestQueue(req);
    }
}

Nếu bạn chạy ứng dụng, bạn có thể xem các hình ảnh được hiển thị theo kiểu lưới. Hãy chắc chắn rằng thiết bị của bạn được kết nối với internet.

Fullscreen Image Slideshow

Bước 11

Tạo một layout có tên image_fullscreen_preview.xml theo định dạng res ⇒. layout, nó được sử dụng để hiển thị hình ảnh trong chế độ xem toàn màn hình.

image_fullscreen_preview.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/RelativeLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black">
 
    <ImageView
        android:id="@+id/image_preview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_centerInParent="true"
        android:scaleType="fitCenter" />
 
</RelativeLayout>

Bước 12

Trong package activity, tạo một lớp có tên SlideshowDialogFragment.java. Đây là một lớp fragment kế thừa từ DialogFragment.

DialogFragment.java
package info.androidhive.glide.activity;
 
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
 
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
 
import java.util.ArrayList;
 
import info.androidhive.glide.R;
import info.androidhive.glide.model.Image;
 
 
public class SlideshowDialogFragment extends DialogFragment {
    private String TAG = SlideshowDialogFragment.class.getSimpleName();
    private ArrayList<Image> images;
    private ViewPager viewPager;
    private MyViewPagerAdapter myViewPagerAdapter;
    private TextView lblCount, lblTitle, lblDate;
    private int selectedPosition = 0;
 
    static SlideshowDialogFragment newInstance() {
        SlideshowDialogFragment f = new SlideshowDialogFragment();
        return f;
    }
 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_image_slider, container, false);
        viewPager = (ViewPager) v.findViewById(R.id.viewpager);
        lblCount = (TextView) v.findViewById(R.id.lbl_count);
        lblTitle = (TextView) v.findViewById(R.id.title);
        lblDate = (TextView) v.findViewById(R.id.date);
 
        images = (ArrayList<Image>) getArguments().getSerializable("images");
        selectedPosition = getArguments().getInt("position");
 
        Log.e(TAG, "position: " + selectedPosition);
        Log.e(TAG, "images size: " + images.size());
 
        myViewPagerAdapter = new MyViewPagerAdapter();
        viewPager.setAdapter(myViewPagerAdapter);
        viewPager.addOnPageChangeListener(viewPagerPageChangeListener);
 
        setCurrentItem(selectedPosition);
 
        return v;
    }
 
    private void setCurrentItem(int position) {
        viewPager.setCurrentItem(position, false);
        displayMetaInfo(selectedPosition);
    }
 
    //  page change listener
    ViewPager.OnPageChangeListener viewPagerPageChangeListener = new ViewPager.OnPageChangeListener() {
 
        @Override
        public void onPageSelected(int position) {
            displayMetaInfo(position);
        }
 
        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
 
        }
 
        @Override
        public void onPageScrollStateChanged(int arg0) {
 
        }
    };
 
    private void displayMetaInfo(int position) {
        lblCount.setText((position + 1) + " of " + images.size());
 
        Image image = images.get(position);
        lblTitle.setText(image.getName());
        lblDate.setText(image.getTimestamp());
    }
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Black_NoTitleBar_Fullscreen);
    }
 
    //  adapter
    public class MyViewPagerAdapter extends PagerAdapter {
 
        private LayoutInflater layoutInflater;
 
        public MyViewPagerAdapter() {
        }
 
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
 
            layoutInflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View view = layoutInflater.inflate(R.layout.image_fullscreen_preview, container, false);
 
            ImageView imageViewPreview = (ImageView) view.findViewById(R.id.image_preview);
 
            Image image = images.get(position);
 
            Glide.with(getActivity()).load(image.getLarge())
                    .thumbnail(0.5f)
                    .crossFade()
                    .diskCacheStrategy(DiskCacheStrategy.ALL)
                    .into(imageViewPreview);
 
            container.addView(view);
 
            return view;
        }
 
        @Override
        public int getCount() {
            return images.size();
        }
 
        @Override
        public boolean isViewFromObject(View view, Object obj) {
            return view == ((View) obj);
        }
 
 
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }
    }
}

Bước 13

Mở MainActivity.java và thêm các sự kiện click để recyclerView trong onCreate () .

MainActivity.java
recyclerView.addOnItemTouchListener(new GalleryAdapter.RecyclerTouchListener(getApplicationContext(), recyclerView, new GalleryAdapter.ClickListener() {
    @Override
    public void onClick(View view, int position) {
        Bundle bundle = new Bundle();
        bundle.putSerializable("images", images);
        bundle.putInt("position", position);
 
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        SlideshowDialogFragment newFragment = SlideshowDialogFragment.newInstance();
        newFragment.setArguments(bundle);
        newFragment.show(ft, "slideshow");
    }
 
    @Override
    public void onLongClick(View view, int position) {
 
    }
}));

Chạy ứng dụng một lần nữa và thử nhấn vào hình thu nhỏ. Bạn sẽ thấy thanh trượt hình ảnh toàn màn hình có bật chức năng swiping.

Source code Source


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí