Nhiều trường hợp app của chúng ta phải tải dữ liệu từ internet hoặc bộ nhớ của thiết bị. Và trong hầu hết các trường hợp, chúng ta phải đợi một lúc để tải dữ liệu. Trong khi chờ đợi, có vẻ tốt hơn nhiều nếu chúng ta hiển thị khung giao diện cho người dùng giống như load list comment của Facebook thay vì chỉ hiển thị một màn hình trắng. Người dùng sẽ không biết app đang load hay đang không làm gì cả.
Trong bài viết này, chúng ta sẽ tìm hiều cách hiển thị khung giao diện và các hiệu ứng như Facebook hoặc LinkedIn cho Layout và recyclerView trên Android bằng thư viện AndroidVeil.
Như ví dụ bên dưới
Thêm thư viện vào Project
Trước tiên, bạn thêm AndroidVeil vào file build.gradle.
1 2 3 4 | dependencies <span class="token punctuation">{</span> implementation “com<span class="token punctuation">.</span>github<span class="token punctuation">.</span>skydoves<span class="token operator">:</span>androidveil<span class="token operator">:</span><span class="token number">1.0</span><span class="token punctuation">.</span><span class="token number">8</span>” <span class="token punctuation">}</span> |
Phiên bản này có thể chưa phải phiên bản mới nhất. Nếu bạn muốn có phiên bản mới nhất, bạn có thể kiểm tra nó ở đây.
Cách dùng
Dưới đây là một ví dụ cơ bản về việc implement hiệu ứng cho View hoặc Viewgroup trong layout bằng VeilLayout.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <com.skydoves.androidveil.VeilLayout xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/veilLayout" android:layout_width="match_parent" android:layout_height="match_parent" app:veilLayout_veiled="true" // shows veils initially app:veilLayout_shimmerEnable="true" // sets shimmer enable app:veilLayout_baseColor="@android:color/holo_green_dark" // sets shimmer base color app:veilLayout_highlightColor="@android:color/holo_green_light" // sets shimmer highlight color app:veilLayout_baseAlpha="0.6" // sets shimmer base alpha value app:veilLayout_highlightAlpha="1.0" // sets shimmer highlight alpha value app:veilLayout_dropOff="0.5"// sets how quickly the shimmer`s gradient drops-off app:veilLayout_radius="6dp" // sets a corner radius of the whole veiled items > <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>TextView</span> <span class="token attr-name"><span class="token namespace">android:</span>layout_width</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>match_parent<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">android:</span>layout_height</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>wrap_content<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">android:</span>text</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>And now here is my secret, a very simple secret<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">android:</span>textColor</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>@android:color/white<span class="token punctuation">"</span></span> <span class="token attr-name"><span class="token namespace">android:</span>textSize</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>22sp<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token comment"><!-- Any Views or ViewGroups --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>com.skydoves.androidveil.VeilLayout</span><span class="token punctuation">></span></span> |
VeilLayout có thể bao bọc bất kỳ view hoặc viewgroup nào và nó sẽ tạo ra các khung giao diện dựa trên hệ thống phân cấp view và tạo ra hiệu ứng. Nguyên tắc cơ bản là VeilLayout sẽ đi qua hệ thống phân cấp view được bao bọc sau đó tạo khung dựa trên các view và kích thước width/height của view con.
Nếu bạn muốn sử dụng VeilLayout cho một layout resource, chúng ta có thể thực hiện như sau.
1 2 | veilLayout<span class="token punctuation">.</span><span class="token function">setLayout</span><span class="token punctuation">(</span>R<span class="token punctuation">.</span>layout<span class="token punctuation">.</span>layout_item_test<span class="token punctuation">)</span> |
Và chúng ta có thể thay đổi màu khung giao diện, màu hiệu ứng, alpha, drop Offer và bán kính của khung giao diện bằng cách sử dụng các thuộc tính có sẵn.
Veil và UnVeil
Nó thực sự dễ sử dụng. Chỉ cần gọi các hàm veil() và unVeil().
1 2 3 | veilLayout<span class="token punctuation">.</span><span class="token function">veil</span><span class="token punctuation">(</span><span class="token punctuation">)</span> veilLayout<span class="token punctuation">.</span><span class="token function">unVeil</span><span class="token punctuation">(</span><span class="token punctuation">)</span> |
Chúng ta có thể gọi phương thức veil() trước khi request server hoặc trước khi làm một công việc gì đó mất thời gian. Sau khi hoàn thành công việc đó, chúng ta nên gọi phương thức unVeil() để hiển thị giao diện thực tế.
Dưới đây là một ví dụ về việc sử dụng Glide và VeilLayout trong ViewHolder (RecyclerView). Trường hợp này, mọi ViewHolder items đều có imageView nên được tải bởi Glide. Và chúng ta muốn tạo hiệu ứng trước khi tải hình ảnh.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | itemView<span class="token punctuation">.</span><span class="token function">run</span> <span class="token punctuation">{</span> item_user_veilLayout<span class="token punctuation">.</span><span class="token function">veil</span><span class="token punctuation">(</span><span class="token punctuation">)</span> Glide<span class="token punctuation">.</span><span class="token function">with</span><span class="token punctuation">(</span>context<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">load</span><span class="token punctuation">(</span>githubUser<span class="token punctuation">.</span>avatar_url<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">apply</span><span class="token punctuation">(</span><span class="token function">RequestOptions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">circleCrop</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">override</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">placeholder</span><span class="token punctuation">(</span>R<span class="token punctuation">.</span>drawable<span class="token punctuation">.</span>ic_account<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">listener</span><span class="token punctuation">(</span><span class="token keyword">object</span> <span class="token operator">:</span> RequestListener<span class="token operator"><</span>Drawable<span class="token operator">></span> <span class="token punctuation">{</span> <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onLoadFailed</span><span class="token punctuation">(</span>e<span class="token operator">:</span> GlideException<span class="token operator">?</span><span class="token punctuation">,</span> model<span class="token operator">:</span> Any<span class="token operator">?</span><span class="token punctuation">,</span> target<span class="token operator">:</span> Target<span class="token operator"><</span>Drawable<span class="token operator">></span><span class="token operator">?</span><span class="token punctuation">,</span> isFirstResource<span class="token operator">:</span> Boolean<span class="token punctuation">)</span><span class="token operator">:</span> Boolean <span class="token punctuation">{</span> item_user_veilLayout<span class="token punctuation">.</span><span class="token function">unVeil</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">false</span> <span class="token punctuation">}</span> <span class="token keyword">override</span> <span class="token keyword">fun</span> <span class="token function">onResourceReady</span><span class="token punctuation">(</span>resource<span class="token operator">:</span> Drawable<span class="token operator">?</span><span class="token punctuation">,</span> model<span class="token operator">:</span> Any<span class="token operator">?</span><span class="token punctuation">,</span> target<span class="token operator">:</span> Target<span class="token operator"><</span>Drawable<span class="token operator">></span><span class="token operator">?</span><span class="token punctuation">,</span> dataSource<span class="token operator">:</span> DataSource<span class="token operator">?</span><span class="token punctuation">,</span> isFirstResource<span class="token operator">:</span> Boolean<span class="token punctuation">)</span><span class="token operator">:</span> Boolean <span class="token punctuation">{</span> item_user_veilLayout<span class="token punctuation">.</span><span class="token function">unVeil</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">false</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">into</span><span class="token punctuation">(</span>item_user_avatar<span class="token punctuation">)</span> |
Glide cung cấp listener success và failure khi tải hình ảnh. Vì vậy, chúng ta có thể sử dụng nó với VeilLayout. Chỉ cần gọi phương thức veil() ngay từ đầu trong phương thức onBindViewHolder. Và sau khi chúng ta có thể biết trạng thái của hình ảnh được tải (success hay failure), chúng ta gọi phương thức unVeil().
VeilRecyclerFrameView
Đây là cách dễ dàng hơn để thực hiện các hiệu ứng lung linh cho RecyclerView bằng VeilRecyclerFrameView. Nó gần như tương tự với việc sử dụng VeilLayout. Chúng ta nên sử dụng VeilRecyclerFameView thay vì RecyclerView trong XML file.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <com.skydoves.androidveil.VeilRecyclerFrameView android:id="@+id/veilRecyclerView" android:layout_width="match_parent" android:layout_height="match_parent" app:veilFrame_layout="@layout/item_profile" // sets to make veiling target layout app:veilFrame_veiled="true" // shows veils initially app:veilFrame_shimmerEnable="true" // sets shimmer enable app:veilFrame_baseColor="@android:color/holo_green_dark" // sets shimmer base color app:veilFrame_highlightColor="@android:color/holo_green_light" // sets shimmer highlight color app:veilFrame_baseAlpha="0.6" // sets shimmer base alpha value app:veilFrame_highlightAlpha="1.0" // sets shimmer highlight alpha value app:veilFrame_radius="8dp" // sets a corner radius of the whole veiled items /> |
Chúng ta bind RecyclerView.Adapter và LayoutManager giống như VeilRecyclerFameView bên dưới.
1 2 3 | veilRecyclerView<span class="token punctuation">.</span><span class="token function">setAdapter</span><span class="token punctuation">(</span>adapter<span class="token punctuation">)</span> <span class="token comment">// sets your own adapter</span> veilRecyclerView<span class="token punctuation">.</span><span class="token function">setLayoutManager</span><span class="token punctuation">(</span><span class="token function">LinearLayoutManager</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// sets LayoutManager</span> |
Kết quả RecyclerView của chúng ta sẽ như sau:
Shimmer
Thư viện này sử dụng shimmer-android của Facebook. Dưới đây là hướng dẫn chi tiết về shimmer-instruction hoặc chúng ta có thể tham khảo ví dụ dưới đây.
1 2 3 4 5 6 7 8 9 10 | <span class="token keyword">val</span> shimmer <span class="token operator">=</span> Shimmer<span class="token punctuation">.</span><span class="token function">ColorHighlightBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">setBaseColor</span><span class="token punctuation">(</span>ContextCompat<span class="token punctuation">.</span><span class="token function">getColor</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> R<span class="token punctuation">.</span>color<span class="token punctuation">.</span>shimmerBase0<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">setHighlightColor</span><span class="token punctuation">(</span>ContextCompat<span class="token punctuation">.</span><span class="token function">getColor</span><span class="token punctuation">(</span>context<span class="token punctuation">,</span> R<span class="token punctuation">.</span>color<span class="token punctuation">.</span>shimmerHighlight0<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">setBaseAlpha</span><span class="token punctuation">(</span><span class="token number">1f</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">setHighlightAlpha</span><span class="token punctuation">(</span><span class="token number">1f</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span> veilLayout<span class="token punctuation">.</span>shimmer <span class="token operator">=</span> shimmer <span class="token comment">// sets shimmer to VeilLayout</span> veilRecyclerView<span class="token punctuation">.</span>shimmer <span class="token operator">=</span> shimmer <span class="token comment">// sets shimmer to VeilRecyclerView</span> |