最新消息:欢迎访问Android开发中文站!商务联系QQ:1304524325

Android 自定义的AlertDialog强化版

新手入门 loading 1475浏览 0评论

介绍了自定义的AlertDialog,在此基础之上,再来看下常用的自定义的AlertDialog。

ItemDialog:

首先来看下android原生的itemDialog
package com.example.yk.dialogtest;

import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.Toast;

public class ItemDialogActivity extends AppCompatActivity {
    private String[] items={"a","b","c","d","e","d","f","g","h","i","j","k","l","m"};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_item_dialog);

        AlertDialog.Builder alertDialog=new AlertDialog.Builder(this);
        alertDialog.setTitle("title");
        alertDialog.setItems(items, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {
                Toast.makeText(ItemDialogActivity.this, "点击了"+items[i], Toast.LENGTH_SHORT).show();
            }
        });

        alertDialog.show();
    }
}

效果如图:

自定义的itemDialog:
package com.example.yk.dialogtest;

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
/**
 * Created by yk on 2017/1/17.
 */

public class itemDialog extends Dialog implements AdapterView.OnItemClickListener {
    public interface OnDialogItemClickListener {
        /**
         * 点击item 事件的回调方法
         * @param requestCode 用于区分某种情况下的showDialog
         * @param position
         * @param item
         */
        void onDialogItemClick(int requestCode, int position,String item);
    }

    private String title;
    private Context context;
    private String[] items;
    private int requestCode;
    private OnDialogItemClickListener listener;

    public itemDialog(Context context, String title, String[] items, int requestCode, OnDialogItemClickListener listener) {
        super(context, R.style.MyDialog);
        this.context=context;
        this.title=title;
        this.items=items;
        this.requestCode=requestCode;
        this.listener=listener;
    }

    private TextView textView;
    private ListView listView;
    private ArrayAdapter<String> adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.item_dialog);
        textView = (TextView) findViewById(R.id.tvItemDialogTitle);
        listView = (ListView) findViewById(R.id.lvItemDialog);
        adapter = new ArrayAdapter<String>(context, R.layout.item_dialog_activity,R.id.text_view, items);

        textView.setText(title);
        listView.setAdapter(adapter);

        listView.setOnItemClickListener(this);
    }

    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
        listener.onDialogItemClick(requestCode,i, adapter.getItem(i));
        dismiss();
    }
}
item_dialog布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_margin="30dp"
        android:background="@drawable/edit_item_text_bg"
        android:layout_height="match_parent">
<TextView
android:id="@+id/tvItemDialogTitle"
        android:textColor="@color/black"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:textSize="21sp"
        android:layout_margin="15dp"
        android:text="Title" />

<ListView
android:id="@+id/lvItemDialog"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:divider="@color/gray_4"
        android:dividerHeight="1px" />

</LinearLayout>

MyDialog style:

<style name="MyDialog">
     <item name="android:windowBackground">@android:color/transparent</item>
     <item name="android:windowFrame">@null</item>
     <item name="android:windowNoTitle">true</item>
     <item name="android:windowIsFloating">true</item>
     <item name="android:windowIsTranslucent">true</item>
     <item name="android:windowContentOverlay">@null</item>
     <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
     <item name="android:backgroundDimEnabled">true</item>
</style>

item_dialog_activity布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
        android:layout_height="40dp"
        android:padding="10dp"
        android:id="@+id/text_view"
        android:gravity="center"/>

</LinearLayout>

MainActivity中代码:

package com.example.yk.dialogtest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

public class CustomItemDialog extends AppCompatActivity implements itemDialog.OnDialogItemClickListener {
    private static final int REQUEST_CODE_SECOND = 2;
    private String[] items={"a","b","c","d","e","d","f","g","h","i","j","k","l","m"};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom_item_dialog);
        itemDialog itemDialog=new itemDialog(this,"title",items,REQUEST_CODE_SECOND,this);
        itemDialog.show();
    }

    @Override
    public void onDialogItemClick(int requestCode, int position, String item) {
        if(requestCode==REQUEST_CODE_SECOND){
            Toast.makeText(this, item, Toast.LENGTH_SHORT).show();
        }
    }
}

效果图:

EditDialog:

editDialog中代码:
package com.example.yk.dialogtest;

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;

/**
 * Created by yk on 2017/1/18.
 */

public class EditDialog extends Dialog implements View.OnClickListener {

    public interface OnDialogButtonClickListener{
        void onDialogButtonClick(int requestCode,boolean isPositiveBtn,String s);
    }
    private String title;
    private String strPositive;
    private String strNegative;
    private int requestCode;
    private Context context;
    private OnDialogButtonClickListener listener;

    public EditDialog(Context context,String title,String strNegative,String strPositive,int requestCode,OnDialogButtonClickListener listener) {
        super(context,R.style.MyDialog);
        this.context=context;
        this.title=title;
        this.strNegative=strNegative;
        this.strPositive=strPositive;
        this.requestCode=requestCode;
        this.listener=listener;
    }

    private TextView tvTitle,tvCancel,tvConfirm;
    private EditText etInput;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_edit_dialog);

        tvTitle= (TextView) findViewById(R.id.tv_title);
        tvCancel= (TextView) findViewById(R.id.tv_cancel);
        tvConfirm= (TextView) findViewById(R.id.tv_confirm);
        etInput= (EditText) findViewById(R.id.edit_text);

        tvTitle.setText(title);

        if(TextUtils.isEmpty(tvConfirm.getText().toString().trim())){
            tvCancel.setVisibility(View.GONE);
        }else {
            tvCancel.setVisibility(View.VISIBLE);
        }

        tvCancel.setOnClickListener(this);
        tvConfirm.setOnClickListener(this);

        tvTitle.postDelayed(new Runnable() {
            @Override
            public void run() {
                showSoftKeyBoard();//弹出输入键盘
            }
        },100);

    }

    public void showSoftKeyBoard(){
        InputMethodManager manager= (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
        manager.toggleSoftInput(0,InputMethodManager.HIDE_NOT_ALWAYS);
    }

    @Override
    public void onClick(View view) {

        switch (view.getId()){
            case R.id.tv_confirm:
//点击确定按钮
                listener.onDialogButtonClick(requestCode,true,etInput.getText().toString().trim());
                break;
            case R.id.tv_cancel:
//点击取消按钮
                listener.onDialogButtonClick(requestCode,false,null);
                break;
        }
        dismiss();
    }
}

layout_edit_dialog布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="250dp"
        android:layout_height="wrap_content"
        android:layout_margin="50dp"
        android:background="@drawable/edit_item_text_bg"
        android:orientation="vertical">

<TextView
android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="title"
        android:gravity="center"
        android:textSize="28sp"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:paddingTop="3dp"
        android:paddingBottom="3dp"
        android:textAllCaps="false"/>

<EditText
android:id="@+id/edit_text"
        android:singleLine="true"
        android:inputType="numberDecimal"
        android:textSize="25sp"
        android:paddingTop="3dp"
        android:paddingBottom="3dp"
        android:layout_marginBottom="5dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

<LinearLayout
android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

<TextView
android:id="@+id/tv_cancel"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:text="取消"
        android:background="@drawable/bg_item_to_alpha"
        android:textSize="20sp"/>

<View
android:layout_width="1dp"
        android:layout_height="match_parent"
        android:background="@color/gray_3"/>

<TextView
android:id="@+id/tv_confirm"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:text="确定"
        android:textColor="@color/black"
        android:textSize="20sp"/>
</LinearLayout>
</LinearLayout>

drawable/bg_item_to_alpha:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:drawable="@color/alpha_1" android:state_pressed="true"/>
     <item android:drawable="@color/alpha_1" android:state_focused="true"/>
</selector>
drawable/edit_item_text_bg:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
     <!--定义填充颜色-->
     <solid android:color="#ffffff"/>
     <!--定义四个角的圆角半径-->
     <corners android:radius="2dp"/>
</shape>
MianActivity中代码:
package com.example.yk.dialogtest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;

public class EditDialogActivity extends AppCompatActivity implements EditDialog.OnDialogButtonClickListener {

    private static final int REQUEST_CODE_THIRD = 3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_edit_dialog);
        EditDialog editDialog=new EditDialog(this,"title","取消","确定",REQUEST_CODE_THIRD,this);
        editDialog.show();
    }

    @Override
    public void onDialogButtonClick(int requestCode, boolean isPositiveBtn, String s) {
        if(requestCode==REQUEST_CODE_THIRD){
            if(isPositiveBtn){
                Toast.makeText(this, "输入的内容:"+s, Toast.LENGTH_SHORT).show();
            }else {
                Toast.makeText(this, "点击了取消", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

效果图:

如果需要对editText输入的内容作限制,需要在EditDialog中添加如下代码:
CustomWatcher customWatcher=new CustomWatcher();
etInput.addTextChangedListener(customWatcher);

CustomWatcher:

private class CustomWatcher implements TextWatcher {
    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

    }

    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

    }

    @Override
    public void afterTextChanged(Editable editable) {
        String s = editable.toString();
/**
 * 不以小数点开头
 */
        if(s.length() ==1 && s.contains(".")){
            editable.delete(0,1);
            return;
        }

/**
 * 不能以00开头
 */
        if(s.startsWith("00")){
            editable.delete(1,2);
            return;
        }
/**
 * 整数部分最长为8位
 */
        if(!s.contains(".")){
            if(s.length() == 9){
                editable.delete(8,9);
            }
            return;
        }

/**
 * 小数部分最多有2位
 */
        if(s.contains(".")){
            int start = s.indexOf("." )+ 1;
            int end=s.length();
            if(end-start>2){
                editable.delete(start+2,s.length());
            }
            return;
        }
    }
}

效果截图:

LoadProgressDialog:

LoadProgressDialog中代码:
package com.example.yk.dialogtest;

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.widget.TextView;

/**
 * Created by yk on 2017/1/18.
 */

public class LoadProgressDialog extends Dialog{
    private String message;
    private boolean canCancel;
    public LoadProgressDialog(Context context,String message,boolean canCancel) {
        super(context);
        this.message=message;
        this.canCancel=canCancel;
    }
    private TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_load_progress_dialog);
        textView= (TextView) findViewById(R.id.tv_message);

        setCancelable(canCancel);
        textView.setText(message);
    }
}

MainActivty中代码:

package com.example.yk.dialogtest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class LoadProgressActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_load_progress);

        LoadProgressDialog dialog=new LoadProgressDialog(this,"加载中",true);
        dialog.show();
    }
}
R.layout.layout_load_progress_dialog为:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="280dp"
        android:layout_height="wrap_content"
        android:background="@drawable/edit_item_text_bg"
        android:orientation="vertical">

<TextView
android:id="@+id/tv_message"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="20dp"
        android:textSize="20sp"/>

<ProgressBar
android:id="@+id/progress_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>
</LinearLayout>

实现的效果:

在此基础之上,可以进一步添加自定义样式:
在LoadProgressDialog中改变的代码:
public LoadProgressDialog(Context context,String message,boolean canCancel) {
        super(context,R.style.easy_dialog_style);
        this.message=message;
        this.canCancel=canCancel;
}

自定义样式R.style.easy_dialog_style为:

<style name="easy_dialog_style" parent="@android:style/Theme.Dialog">
<item name="android:windowFrame">@null</item>
<!-- 边框 -->
<item name="android:windowIsFloating">true</item>
<!-- 是否浮现在activity之上 -->
<item name="android:windowIsTranslucent">true</item>
<!-- 半透明 -->
<item name="android:windowNoTitle">true</item>
<!-- 无标题 -->
<item name="android:windowBackground">@color/transparent</item>
<!-- 背景透明 -->
<item name="android:backgroundDimEnabled">true</item>
<!-- 后面的activity变暗 -->
</style>

R.layout.layout_load_progress_dialog布局为:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="280dp"
        android:layout_height="wrap_content"
        android:background="@drawable/edit_item_text_bg"
        android:orientation="vertical">

<TextView
android:id="@+id/tv_message"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="20dp"
        android:textSize="20sp"/>

<ProgressBar
android:id="@+id/progress_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingBottom="10dp"
        android:layout_gravity="center"
        android:indeterminateDrawable="@drawable/custom_progress_style"/>
</LinearLayout>

drawable/custom_progress_style:

<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@mipmap/load_dialog"
        android:pivotX="50%"
        android:pivotY="50%"
        />

效果:

控制LoadProgressDialog显示与不显示的工具类:

LoadProgressActivity中代码:
package com.example.yk.dialogtest;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class LoadProgressActivity extends AppCompatActivity {

    private LoadProgressDialog dialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_load_progress);

//        dialog = new LoadProgressDialog(this,"加载中",true);
//        dialog.show();
        LoadProgressUtil.showLoadProgressDialog(this,"加载中",true);
    }
}

LoadProgressUtil中代码:

package com.example.yk.dialogtest;

import android.content.Context;
import android.util.Log;

/**
 * Created by yk on 2017/1/18.
 */

public class LoadProgressUtil {
    private static LoadProgressDialog loadProgressDialog;

    public static void showLoadProgressDialog(Context context,String title, boolean canCancel){
        if(loadProgressDialog == null){
            loadProgressDialog=new LoadProgressDialog(context,title,canCancel);
        }else {
            if(loadProgressDialog.isShowing()){
                return;
            }
        }
//        Log.e("context",context.toString());
//        Log.e("loadProgressDialog",loadProgressDialog.getContext().toString());
        loadProgressDialog.show();

    }

    public static void cancelProgressDialog(){
        if(loadProgressDialog==null){
            return;
        }else {
            if(loadProgressDialog.isShowing()){
                loadProgressDialog.dismiss();
            }else {
                return;
            }
        }
    }

    public static void progressDialogIsShow(){
        loadProgressDialog.isShowing();
    }
}

如果像上面这样写的话,会发现,在第一次取消progressDialog,并且退出当前progressDialog所在的Activity,当第二次进入该progressDialog所在的Activity时是会报错的,错误原因:

Caused by: android.view.WindowManager$BadTokenException: Unable to add window -- token android.os.BinderProxy@3d4e7354 is not valid; is your activity running?</div>

查阅资料发现,对于AlertDialog来说,是需要依赖一个View,而View是对应于Activity的。那么为什么会报错呢,这里涉及到一个生命周期的问题了。静态变量private static LoadProgressDialog loadProgressDialog;需要等到系统GC的时候才会回收,第二次进入该activity时,此时的context是新的地址,而此时的progress Dialog的context还是上次的activity的,见下图:

解决的办法是:
package com.example.yk.dialogtest;

import android.content.Context;
import android.util.Log;

/**
 * Created by yk on 2017/1/18.
 */

public class LoadProgressUtil {
    private static LoadProgressDialog loadProgressDialog;

    public static void showLoadProgressDialog(Context context,String title, boolean canCancel){
        if(loadProgressDialog == null){
            loadProgressDialog=new LoadProgressDialog(context,title,canCancel);
        }else if(loadProgressDialog.getContext() !=context){
            cancelProgressDialog();
            loadProgressDialog=new LoadProgressDialog(context,title,canCancel);
        }
//        Log.e("context",context.toString());
//        Log.e("loadProgressDialog",loadProgressDialog.getContext().toString());
        loadProgressDialog.show();

    }

    public static void cancelProgressDialog(){
        if(loadProgressDialog==null){
            return;
        }else {
            if(loadProgressDialog.isShowing()){
                loadProgressDialog.dismiss();
                loadProgressDialog=null;
            }
        }
    }

    public static boolean progressDialogIsShow(){
        return (loadProgressDialog !=null && loadProgressDialog.isShowing());
    }
}

完整的项目源码:http://download.csdn.net/detail/qq_33748378/9740725

包含的内容:

转载请注明:Android开发中文站 » Android 自定义的AlertDialog强化版

您必须 登录 才能发表评论!