1. 程式人生 > >手把手教你擼一個Loading

手把手教你擼一個Loading

點選上面藍色字型關注 “IT大飛說”

置頂公眾號( ID:ITBigFly)第一時間收到推送

這裡寫圖片描述

作為 Android 開發者,無奈經常會碰到各種各樣的奇葩需求,現在大多公司 UI 設計圖、標註都是按 IOS 來設計的,包括一個IOS特有的效果等,要實現和 IOS 一樣的效果,無奈 Android 只能各種仿 IOS 了,經常也是產品被懟,IOS 能實現,為什麼 Android 不能實現?好吧,今天我們就來寫一個仿 IOS 的載入 loading 效果。

1.先看效果圖

這裡寫圖片描述

效果還滿意吧?實現的思路是,在頁面上彈出一個全屏的 popupWindow,居中是一個半透明的圓角shape,中間一個 gif 圖片,下面是一個 TextView,最外層佈局背景為透明,另外把其他需外設定的屬性及引數通過建造者模式從外部進行配置,同時提供預設的屬性值,這樣可以適應各種需求的變化了,程式碼也比較簡單,我的註釋也寫的比較詳細,相信你一定能看得懂。

2.程式碼實現

/**
 * Created by x-sir on 2018/8/22 :)
 * Function:
 */
public class LoadingView {

    private String mText;
    private int mTextSize;
    private int mGifWidth;
    private int mGifHeight;
    private int mDrawableId;
    private View mPopupView;
    private Context mContext;
    private
String mTextColor; private int mCornerRadius; private int mLoadingWidth; private int mLoadingHeight; private int mTextMarginTop; private boolean mIsFocusable; private String mLoadingBgColor; private PopupWindow mPopupWindow; private WeakReference<View> mView; private
OnLoadingListener mListener; private static final String DEFAULT_TEXT = "載入中..."; // default text private static final int DEFAULT_TEXT_SIZE = 12; // default text size private static final int DEFAULT_TEXT_MARGIN_TOP = 6; // default text margin top private static final String DEFAULT_TEXT_COLOR = "#FFFFFF"; // default text color private static final int DEFAULT_CORNER_RADIUS = 4; // default loading background radius size private static final String DEFAULT_LOADING_BG_COLOR = "#CC000000"; // default loading background color private static final int DEFAULT_DRAWABLE_ID = R.drawable.loading1; // default loading drawable private static final int DEFAULT_GIF_WIDTH = 30; // default gif width private static final int DEFAULT_GIF_HEIGHT = 30; // default gif height /** * Constructor. * * @param builder */ public LoadingView(Builder builder) { this.mText = builder.text; this.mView = builder.view; this.mListener = builder.listener; this.mTextSize = builder.textSize; this.mTextColor = builder.textColor; this.mCornerRadius = builder.cornerRadius; this.mContext = builder.applicationContext; this.mLoadingBgColor = builder.loadingBgColor; this.mDrawableId = builder.drawableId; this.mGifWidth = builder.gifWidth; this.mGifHeight = builder.gifHeight; this.mLoadingWidth = builder.loadingWidth; this.mLoadingHeight = builder.loadingHeight; this.mTextMarginTop = builder.textMarginTop; this.mIsFocusable = builder.isFocusable; initView(); } /** * Initialize view parameters. */ private void initView() { if (mPopupView == null) { mPopupView = View.inflate(mContext, R.layout.popupwindow_loading, null); } if (mPopupWindow == null) { mPopupWindow = new PopupWindow(mPopupView, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT); } mPopupWindow.setOnDismissListener(() -> { if (mListener != null) { mListener.onDismiss(); } }); mPopupWindow.setBackgroundDrawable(new BitmapDrawable()); // 當 mIsFocusable 為 true 時,響應返回鍵消失,為 false 時響應 activity 返回操作,預設為 false mPopupWindow.setFocusable(mIsFocusable); LinearLayout llLoadingBg = (LinearLayout) mPopupView.findViewById(R.id.llLoadingBg); ImageView ivLoading = (ImageView) mPopupView.findViewById(R.id.ivLoading); TextView tvContent = (TextView) mPopupView.findViewById(R.id.tvContent); RelativeLayout.LayoutParams rlParams = (RelativeLayout.LayoutParams) llLoadingBg.getLayoutParams(); if (mLoadingWidth != -1 && mLoadingHeight != -1) { rlParams.width = dp2px(mLoadingWidth); rlParams.height = dp2px(mLoadingHeight); } else { rlParams.width = RelativeLayout.LayoutParams.WRAP_CONTENT; rlParams.height = RelativeLayout.LayoutParams.WRAP_CONTENT; } llLoadingBg.setLayoutParams(rlParams); GradientDrawable mGroupDrawable = new GradientDrawable(); /*設定 Drawable 的形狀為矩形*/ mGroupDrawable.setShape(GradientDrawable.RECTANGLE); /*設定背景顏色*/ mGroupDrawable.setColor(Color.parseColor(mLoadingBgColor)); /*設定圓角大小*/ mGroupDrawable.setCornerRadius(dp2px(mCornerRadius)); llLoadingBg.setBackground(mGroupDrawable); LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) tvContent.getLayoutParams(); params.topMargin = dp2px(mTextMarginTop); tvContent.setLayoutParams(params); /*設定顯示文字*/ tvContent.setText(mText); /*設定文字大小(以 SP 為單位)*/ tvContent.setTextSize(TypedValue.COMPLEX_UNIT_SP, mTextSize); /*設定文字顏色*/ tvContent.setTextColor(Color.parseColor(mTextColor)); LinearLayout.LayoutParams llParams = (LinearLayout.LayoutParams) ivLoading.getLayoutParams(); llParams.width = dp2px(mGifWidth); llParams.height = dp2px(mGifHeight); ivLoading.setLayoutParams(llParams); /*載入 GIF 圖片*/ Glide.with(mContext).load(mDrawableId) .diskCacheStrategy(DiskCacheStrategy.SOURCE) .into(ivLoading); } /** * Show popupWindow. */ public void show() { dismiss(); if (mPopupWindow != null) { // 必須要 post runnable,如果在onCreate中呼叫則會拋:android.view.WindowManager$BadTokenException: Unable to add window -- token mView.get().post(() -> mPopupWindow.showAtLocation(mView.get(), Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 0)); } } /** * Cancel popupWindow showing. */ public void dismiss() { if (mPopupWindow != null && mPopupWindow.isShowing()) { mPopupWindow.dismiss(); } } /** * Invoke on Activity onDestroy() method. */ public void dispose() { if (mPopupWindow != null && mPopupWindow.isShowing()) { mPopupWindow.dismiss(); } mPopupWindow = null; if (mView != null) { mView.clear(); mView = null; } } /** * PopupWindow is or not showing. * * @return */ public boolean isShowing() { return mPopupWindow != null && mPopupWindow.isShowing(); } /** * Builder inner class. */ public static final class Builder { private String text; private String textColor; private int textSize = -1; private int gifWidth = -1; private int gifHeight = -1; private int drawableId = -1; private String loadingBgColor; private int cornerRadius = -1; private int loadingWidth = -1; private int loadingHeight = -1; private int textMarginTop = -1; private boolean isFocusable = false; private WeakReference<View> view; private OnLoadingListener listener; private Context applicationContext; /** * Constructor */ public Builder(Context context) { this.applicationContext = context.getApplicationContext(); } /** * Set content text. * * @param text * @return */ public Builder setText(String text) { this.text = text; return this; } /** * Set text size. * * @param textSize * @return */ public Builder setTextSize(int textSize) { this.textSize = textSize; return this; } /** * Set text margin top dimen. * * @param textMarginTop * @return */ public Builder setTextMarginTop(int textMarginTop) { this.textMarginTop = textMarginTop; return this; } /** * Set popupWindow's focusable. * * @param isFocusable * @return */ public Builder setFocusable(boolean isFocusable) { this.isFocusable = isFocusable; return this; } /** * Set gif imageView width. * * @param gifWidth * @return */ public Builder setGifWidth(int gifWidth) { this.gifWidth = gifWidth; return this; } /** * Set gif imageView height. * * @param gifHeight * @return */ public Builder setGifHeight(int gifHeight) { this.gifHeight = gifHeight; return this; } /** * Set gif loadingView width. * * @param loadingWidth * @return */ public Builder setLoadingWidth(int loadingWidth) { this.loadingWidth = loadingWidth; return this; } /** * Set gif loadingView height. * * @param loadingHeight * @return */ public Builder setLoadingHeight(int loadingHeight) { this.loadingHeight = loadingHeight; return this; } /** * Set text color. * * @param textColor * @return */ public Builder setTextColor(String textColor) { this.textColor = textColor; return this; } /** * Set loadingView corner radius. * * @param cornerRadius * @return */ public Builder setCornerRadius(int cornerRadius) { this.cornerRadius = cornerRadius; return this; } /** * Set loadingView background color. * * @param loadingBgColor * @return */ public Builder setLoadingBgColor(String loadingBgColor) { this.loadingBgColor = loadingBgColor; return this; } /** * Set gif drawable resource. * * @param drawableId * @return */ public Builder setGifDrawable(int drawableId) { this.drawableId = drawableId; return this; } /** * Set location at parent view, because popupWindow must be dependency activity. * * @param view * @return */ public Builder setDropView(View view) { if (view != null) { this.view = new WeakReference<>(view); } else { throw new IllegalArgumentException("must be point parent view!"); } return this; } /** * set on popupWindow dismiss listener. * * @param listener * @return */ public Builder setListener(OnLoadingListener listener) { this.listener = listener; return this; } public LoadingView build() { if (TextUtils.isEmpty(text)) { text = DEFAULT_TEXT; } if (textSize == -1) { textSize = DEFAULT_TEXT_SIZE; } if (textMarginTop == -1) { textMarginTop = DEFAULT_TEXT_MARGIN_TOP; } if (TextUtils.isEmpty(textColor)) { textColor = DEFAULT_TEXT_COLOR; } if (TextUtils.isEmpty(loadingBgColor)) { loadingBgColor = DEFAULT_LOADING_BG_COLOR; } if (cornerRadius == -1) { cornerRadius = DEFAULT_CORNER_RADIUS; } if (view == null) { throw new IllegalArgumentException("must be point parent view!"); } if (drawableId == -1) { drawableId = DEFAULT_DRAWABLE_ID; } if (gifWidth == -1) { gifWidth = DEFAULT_GIF_WIDTH; } if (gifHeight == -1) { gifHeight = DEFAULT_GIF_HEIGHT; } return new LoadingView(this); } } /** * dp convert to px. * * @param dpValue * @return */ private int dp2px(float dpValue) { float scale = mContext.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * Define popupWindow dismiss listener. */ interface OnLoadingListener { void onDismiss(); } }

3.用法

3.1初始化Loading

1.最基本的用法:

        // 因為 PopupWindow 依賴於Activity,所以必須要呼叫 setDropView 方法設定要掛載的 View,
        // 一般是 Activity 或 Fragment 的根 View,其他引數可根據需求進行設定。
        mLoadingView = new LoadingView.Builder(this)
                .setDropView(activity_main)
                .build();

2.自定義設定各種引數:

        mLoadingView = new LoadingView.Builder(this)
                .setText("拼命載入中...") // 設定文案
                .setTextSize(12) // 設定字型大小(sp)
                .setTextColor("#FFFFFF") // 設定字型顏色(#RGB & #ARGB)
                .setTextMarginTop(10) // 設定文字距上的距離(dp)
                .setCornerRadius(4) // 設定圓角半徑(dp)
                .setLoadingBgColor("#CC000000") // 設定背景顏色(#RGB & #ARGB)
                .setLoadingWidth(120) // 設定 loading 的寬(dp)
                .setLoadingHeight(100) // 設定 loading 的高(dp)
                .setListener(listener) // 設定監聽
                .setDropView(activity_main) // 設定要掛載的 View(必須要設定),一般是 Activity 或 Fragment 的根 View
                .setGifDrawable(R.drawable.loading4) // 設定 gif 資源
                .setFocusable(false) // 為 true 時,響應返回鍵消失,為 false 時響應 activity 返回操作,預設為 false
                .setGifWidth(16) // 設定 gif 的寬(dp)
                .setGifHeight(16) // 設定 gif 的高(dp)
                .build();

3.2 顯示Loading

mLoadingView.show();

3.3 取消Loading

mLoadingView.dismiss();

4.支援的自定義設定

  • 支援設定字型文案、及顏色和字型的大小;
  • 支援設定文字距上的邊距;
  • 支援設定Loading的寬高;
  • 支援設定Loading的圓角半徑及背景顏色;
  • 支援設定Loading的監聽;
  • 支援設定載入其他gif資源;
  • 支援設定gif圖片顯示的寬高;
  • 支援設定Loading的焦點;

好了,今天的分享就到這裡,需要下載 Demo 的請點選 「閱讀原文」!

猜你喜歡:
深入淺出Retrofit2.x(一)
深入淺出Retrofit2.x(二)
不得不會的10點Java基礎知識
Android 最全 Intent 傳遞資料姿勢


歡迎掃碼關注我的公眾號