025-Android自定义对话框(2)实践:版本更新Dialog

705 阅读2分钟

1.简述

如何自定义DialogFragment,请参考Android自定义弹窗:DialogFragment

DialogFragment是谷歌官方推荐的对话框,可以高度自定义,灵活方便,非常适合编写产品经理设计的任何UI。

2.需求

设计自定义检查版本更新对话框,并加入动画效果,如下图:

3.开发

3.1 布局

res/layout/xxx.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"

    android:background="@android:color/transparent">

    <LinearLayout
        android:id="@+id/center_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:background="@drawable/shape_white_radius_6_bg"
        android:layout_marginTop="65dp"
        >
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:src="@mipmap/pic_bo_lang"
            />
        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="更新"
            android:textStyle="bold"
            android:textSize="16sp"
            android:textColor="#404040"

            android:layout_marginLeft="17dp"
            android:layout_marginRight="17dp"
            />
        <TextView
            android:id="@+id/content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="1.更新内容"
            android:textSize="14sp"
            android:textColor="#666666"
            android:layout_marginTop="8dp"
            android:layout_marginBottom="25dp"
            android:layout_marginLeft="17dp"
            android:layout_marginRight="17dp"
            />

        <LinearLayout
            android:layout_width="match_parent"
            android:orientation="horizontal"
            android:layout_height="wrap_content"
            android:layout_marginLeft="17dp"
            android:layout_marginRight="17dp"
            android:layout_marginBottom="25dp"
            >
            <TextView
                android:visibility="gone"
                android:id="@+id/btn_cancel"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:paddingTop="8dp"
                android:paddingBottom="8dp"
                android:textSize="16sp"
                android:layout_marginLeft="15dp"
                android:layout_marginRight="15dp"
                android:background="@drawable/shape_gray_efefef_radius_12"
                android:gravity="center"
                android:textColor="#666666"
                android:text="  取消  "
                />
            <TextView
                android:id="@+id/btn_ok"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:paddingTop="8dp"
                android:paddingBottom="8dp"
                android:layout_marginLeft="15dp"
                android:layout_marginRight="15dp"
                android:textSize="16sp"
                android:background="@drawable/shape_btn_blue_radius_20"
                android:gravity="center"
                android:textColor="#fff"
                android:text="立即更新"
                />

        </LinearLayout>

    </LinearLayout>

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launch_rochet"
        android:maxHeight="65dp"
        android:layout_marginTop="10dp"
        />
    <View
        android:id="@+id/un_use_line"
        android:layout_width="1dp"
        android:layout_height="45dp"
        android:background="#F0EFF2"
        android:layout_centerHorizontal="true"
        android:layout_below="@id/center_layout"
        />
    <ImageView
        android:id="@+id/btn_close"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:paddingTop="0dp"
        android:paddingBottom="20dp"
        android:src="@mipmap/ic_close_black"
        android:layout_centerHorizontal="true"
        android:layout_below="@id/un_use_line"
        />


</RelativeLayout>

3.2 类编写

其他次要代码见文末

package com.cupster.versiondialog;

import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;


public class VersionOperateDialog extends DialogFragment {


    private ImageView mBtnClose;
    private TextView mTitle;
    private TextView mContent;
    private TextView mBtnOk;
    private TextView mBtnCancel;
    private View mLine ;

    OnClickListener mPositiveListener ;
    OnClickListener mNegativeListener;

    private Object mVersionBean;

    public static VersionOperateDialog Build(String title,String content,boolean closeShow) {
        VersionOperateDialog inputDialog = new VersionOperateDialog();
        Bundle bundle = new Bundle();
        bundle.putString("title" , title);
        bundle.putString("content" , content);
        bundle.putBoolean("closeShow" , closeShow);
        inputDialog.setArguments(bundle);
        return inputDialog;
    }

    View mView;
    int mWidth, mHeight;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        if (mView == null) {
            mView = inflater.inflate(R.layout.dialog_version_operate, container, false);
        }
        setStyle(STYLE_NORMAL, R.style.InputDialogStyle);
        getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        return mView;
    }


    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        mTitle = mView.findViewById(R.id.title);
        mContent = mView.findViewById(R.id.content);
        mLine = mView.findViewById(R.id.un_use_line);

        mBtnOk= mView.findViewById(R.id.btn_ok);
        mBtnOk.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mPositiveListener != null) {
                    mPositiveListener.onClick(v);
                }
                dismiss();
            }
        });

        mBtnCancel= mView.findViewById(R.id.btn_cancel);
        mBtnCancel.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mNegativeListener != null) {
                    mNegativeListener.onClick(v);
                }
                dismiss();
            }
        });
        mBtnClose = mView.findViewById(R.id.btn_close);
        mBtnClose.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mNegativeListener != null) {
                    mNegativeListener.onClick(v);
                }
                dismiss();
            }
        });

        initData();
    }

    private void initData() {
        if (getArguments() != null){
            boolean closeShow = getArguments().getBoolean("closeShow");
            if (!closeShow){
                mLine.setVisibility(View.GONE);
                mBtnCancel.setVisibility(View.GONE);
                mBtnClose.setVisibility(View.GONE);
            }

            String title = getArguments().getString("title");
            if (!TextUtils.isEmpty(title)){
                mTitle.setText(title);
            }

            String content = getArguments().getString("content");
            if (!TextUtils.isEmpty(content)){
                mContent.setText(content);
            }
        }
    }


    @Override
    public void onStart() {
        super.onStart();
        //在DialogFragment的onstart里面设置,可以将对话框外部的背景设为透明
//        Window window = getDialog().getWindow();
//        WindowManager.LayoutParams windowParams = window.getAttributes();
//        windowParams.dimAmount = 0.0f;
//        window.setAttributes(windowParams);
        //======================= ↑ 有效   ================================

        //======================= ↓ 有效   ================================
        Window window = getDialog().getWindow();
        window.setDimAmount(0.2f);//设置亮度
        window.setGravity(Gravity.CENTER);
        window.setWindowAnimations(R.style.CenterPopupAnimation);
        //全占宽、适配高
//        window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT);
        //自定义比例
        WindowManager.LayoutParams layoutParams = window.getAttributes();
//        if (mWidth > 0 && mHeight > 0) {
//            layoutParams.height = mHeight;
//            layoutParams.width = mWidth;
//        } else {
//            layoutParams.height = deviceHeight(getContext()) ;
        layoutParams.width = (int) (0.7*deviceWidth(getContext()) );
//        }
        window.setLayout(layoutParams.width, layoutParams.height);
        window.setBackgroundDrawableResource(android.R.color.transparent);
    }

    public void  setObj(Object obj){
        mVersionBean = obj;
    }
    public Object getObj (){
        return mVersionBean;
    }

    public void setCancelListener(OnClickListener listener) {
        mNegativeListener = listener;
    }


    public void setOkListener(OnClickListener mPositiveListener) {
        this.mPositiveListener = mPositiveListener;
    }

    /**
     * 获取设备宽度(px)
     *
     * @param context
     * @return
     */
    public static int deviceWidth(Context context) {
        return context.getResources().getDisplayMetrics().widthPixels;
    }

    /**
     * 获取设备高度(px)
     *
     * @param context
     * @return
     */
    public static int deviceHeight(Context context) {
        return context.getResources().getDisplayMetrics().heightPixels;
    }



    /**
     * dp 转化为 px
     *
     * @param context
     * @param dpValue
     * @return
     */
    public static int dp2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    /**
     * px 转化为 dp
     *
     * @param context
     * @param pxValue
     * @return
     */
    public static int px2dp(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }
}

3.3 使用

package com.cupster.versiondialog;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                VersionOperateDialog dialog = VersionOperateDialog.Build("更新内容", "1.更新首页;\n2.更新导航布局;\n3.修复问题", true);
                dialog.show(getSupportFragmentManager(), "version");
                dialog.setOkListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //下载安装包,更新APP
                        Toast.makeText(MainActivity.this ,"下载中...",Toast.LENGTH_SHORT).show();
                    }
                });
            }
        });
    }
}

3.4 动画

res/anim/xxx.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <scale
        android:duration="200"
        android:pivotX="50%p"
        android:pivotY="50%p"
        android:fromXScale="0.0"
        android:fromYScale="0.0"
        android:toXScale="1.2"
        android:toYScale="1.2"/>
</set>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <scale
        android:duration="200"
        android:pivotX="0%p"
        android:pivotY="0%p"
        android:fromXScale="1.0"
        android:fromYScale="1.0"
        android:toXScale="0.0"
        android:toYScale="0.0"/>
</set>

3.5其他次要代码

1.shape_btn_blue_radius_20.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="20dp"/>
    <gradient android:startColor="#508EF9"
        android:endColor="#5577fb"
        android:angle="135"
        />
</shape>

shape_gray_efefef_radius_12.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="20dp"/>
    <solid android:color="#efefef"/>
</shape>

shape_white_radius_6_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    >
    <solid android:color="#fff" />
   <corners android:radius="10dp"/>
</shape>

res/values/styles.xml 新增style

<resources>
    <style name="InputDialogStyle" parent="android:Theme.Holo.Light.Dialog">
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowBackground">@null</item>
    </style>
    <!-- 弹出窗体的动画 从中间浮出弹出 -->
    <style name="CenterPopupAnimation" parent="@android:style/Animation">
        <!-- 边框 -->
        <item name="android:windowFrame">@null</item>
        <!-- 设置dialog的背景 -->
        <item name="android:windowBackground">@android:color/transparent</item>
        <!-- 是否浮现在activity之上 -->
        <item name="android:windowIsFloating">true</item>
        <!-- 半透明 -->
        <item name="android:windowIsTranslucent">false</item>
        <!-- 无标题 -->
        <item name="android:windowNoTitle">true</item>
        <!-- 模糊 -->
        <item name="android:backgroundDimEnabled">true</item>
        <item name="android:windowEnterAnimation">@anim/popup_alpha_in</item>
        <item name="android:windowExitAnimation">@anim/popup_alpha_out</item>
    </style>
</resources>