自定義dialog當然已經被寫爛咯,本文的重點是很方便地獲取二次元動漫動圖。自帶的progress dialog看膩了嗎?來換個和bilibili一樣的動漫二次元加載吧!
一、動畫來源獲取
1.1 來源簡介
先來預覽下效果咯:
很萌很萌吧?。?!loading動畫當然還是幀動畫咯,由于是二次元,pixiv(俗稱p站)可謂是動漫圖片最多的站點了,上面有數以億計的動漫圖片和動圖。
pixiv :新興的日本同人畫、插畫作品分享站點。
采用了web2.0的方式,每個參與者都有自己的主頁并可以對作品評價打分。
但是由于版權的保護性政策,動圖是無法直接下載到gif的,所以我們必須通過一些非常規手段獲取,巧合的是,獲取到的是動畫幀的圖片壓縮包,所以可以直接拿來當做安卓開發的幀動畫使用!
1.2 動畫幀獲取
p站如今支持中文,所以閱讀上沒有了障礙,大家可以搜索自己喜歡主題的動圖,或者直接去每日排行榜獲取高人氣動圖,我們以此鏈接 為例。
-
使用chrome內核的瀏覽器,右鍵選擇檢查:
image.png
- 進入開發者工具界面后,按下
Ctrl+F
(Command+F
)搜索關鍵詞zip
,其實已經可以看到我們要的下載鏈接了,但是不能直接復制,必須選中整個段落后,右鍵copy到文本編輯器中。
image.png
-
在文本編輯器中,刪除所有的轉義字符
\
后,復制名字里帶有600x600的那個zip鏈接,然后粘貼到瀏覽器或者迅雷中下載。
image.png -
解壓后即可獲得動畫幀圖片,順序為名稱。
image.png
警告:pixiv站點所有圖片擁有版權??,商用請聯系原作者,下載僅僅是個人學習參考之用。
二、幀動畫xml文件的建立
怕是沒有人不會吧,直接貼代碼了,具體的duration根據實際情況自己調節:
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false"
>
<item
android:drawable="@drawable/loading_1"
android:duration="100"
/>
<item
android:drawable="@drawable/loading_2"
android:duration="100"
/>
<item
android:drawable="@drawable/loading_3"
android:duration="100"
/>
<item
android:drawable="@drawable/loading_4"
android:duration="100"
/>
<item
android:drawable="@drawable/loading_5"
android:duration="100"
/>
<item
android:drawable="@drawable/loading_6"
android:duration="100"
/>
<item
android:drawable="@drawable/loading_7"
android:duration="100"
/>
<item
android:drawable="@drawable/loading_8"
android:duration="100"
/>
</animation-list>
三、自定義dialog的建立
3.1 Dialog概念
dialog的官方定義:
A dialog is a small window that prompts the user to make a decision or enter additional information. A dialog does not fill the screen and is normally used for modal events that require users to take an action before they can proceed.
先來了解下什么是Window:
Window表示窗口的概念,它實際上是View的直接管理者,包括View的視圖創建,事件分發機制都必須先經過Window。
自定義Dialog,要先明確Dialog的地位。
-
View
是android中視圖的呈現方式,但是View不能單獨存在,必須依附在Window
窗口這個抽象概念上,而Android中提供視圖的地方有Activity,Dialog,Toast。 - 所以某種程度上來說,Dialog是和活動平起平坐的,Dialog的
Window
創建過程與Activity類似(幾乎沒區別),所以Dialog也有setContentView
方法。具體的創建過程可以參考《Android開發藝術探索》這本書。
所以我們在后面想要管理Dialog的對話框大小就必須使用WindowManager類,而不是去設置父布局的params。
3.2 建立dialog布局文件
直接上代碼了,注意,我直接在布局最外層設定了固定的大小,且使用了一個圓角半透明矩形shape作為背景。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_gravity="center_horizontal"
android:background="@drawable/shape_dialog_bg"
android:layout_centerInParent="true"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp">
<ImageView
android:id="@+id/loading_view"
android:layout_width="85dp"
android:layout_height="85dp"
android:scaleType="fitCenter"
android:layout_centerInParent="true"
android:src="@drawable/loading_data_anim"
/>
</RelativeLayout>
<TextView
android:id="@+id/tv_load_dialog"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="讀取中……"
android:layout_marginTop="5dp"
android:textColor="@color/color_666666"
android:textSize="12sp"/>
</LinearLayout>
效果圖:
3.3 自定義dialog的建立
我們新建一個類LoadingDialog
繼承自Dialog
,初始化布局參數:
private void initView() {
setContentView(R.layout.dialog_loading_layout);
imageView = (ImageView) findViewById(R.id.loading_view);
//啟動我們的二次元幀動畫
AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable();
animationDrawable.start();
//獲取WindowManager.LayoutParams來管理dialog最外部window的大小,理由在3.1 節中已經說明。其實這里不用設置,因為我們在布局最外層指定了居中,且設為固定大小 后對話框最外層布局會自適應(但是android5.0以上默認最外布局match_parent)。
WindowManager.LayoutParams params = getWindow().getAttributes();
params.gravity = Gravity.CENTER;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
getWindow().setAttributes(params);
}
但是坑來了,盡管我們設定了最外層布局為WRAP_CONTENT,但是它是默認白色的背景,所以我們的圓角矩形效果就失效了,借@青蛙要fly的一張圖,如果設定background為黑色則效果更加直觀:
解決的辦法很簡單,直接覆蓋重寫dialog style里的透明屬性即可,另外,使用兼容包的dialog樣式默認沒有Title了,但是這里還是覆寫一下:
<style name="dialog_no_title" parent="Theme.AppCompat.Dialog">
<item name="android:windowNoTitle">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
</style>
在構造函數中傳入我們的新style(dialog提供了這個構造方法):
public LoadingDialog(Context context) {
super(context,R.style.LoadingDialog);
mContext=context;
}
最后我們的自定義dialog就已經完成了,貼上完整代碼:
public class LoadingDialog extends Dialog {
private Context mContext;
ImageView imageView;
public LoadingDialog(Context context) {
super(context,R.style.LoadingDialog);
mContext=context;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initView();
}
private void initView() {
setContentView(R.layout.dialog_loading_layout);
imageView = (ImageView) findViewById(R.id.loading_view);
AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable();
animationDrawable.start();
WindowManager.LayoutParams params = getWindow().getAttributes();
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
getWindow().setAttributes(params);
}
@Override
public void dismiss() {
super.dismiss();
}
}
四、封裝構建Dialog管理類
為了效率和復用性,我們使用單例模式封裝一個線程安全的DialogManger
類:
public class DialogManager {
private static DialogManager mInstnce = null;
private ProgressDialog mDialog;
public static DialogManager getInstnce() {
if (mInstnce == null) {
//線程安全模式
synchronized (DialogManager.class) {
if (mInstnce == null) {
mInstnce = new DialogManager();
}
}
}
return mInstnce;
}
public void showProgressDialog(Context context) {
if (mDialog == null) {
mDialog = new ProgressDialog(context);
//設置點擊dialog外部,不會自動退出dialog
mDialog.setCanceledOnTouchOutside(false);
}
mDialog.show();
}
public void dismissProgressDialog() {
if (mDialog != null) {
mDialog.dismiss();
}
mDialog = null;
}
}
這樣,我們就可以一句話調出和取消讀取界面了:
//顯示
DialogManager.getInstnce().showProgressDialog(this);
//取消顯示
DialogManager.getInstnce().dismissProgressDialog();
五、總結
其實整個過程非常簡單,就是理解window類,然后自定義一個dialog,然后在dialog中啟動幀動畫,有些老生常談的坑需要注意罷了。再來看一眼我們萌萌的loading動畫吧: