Android-自定義Dialog和其樣式以及自定義控件思路詳解

我們自己清楚,android的原生控件實在是不堪入目,在很多時候無法滿足項目需求,所以在項目進行的過程中,我們很多時候就需要自定義控件,繼承重寫從而實現我們的需求。并且自定義控件將體現代碼的復用,分層的架構學管理,妙用無窮。本文將詳細介紹自定義Dialog的多種思路以及給出如何進行自定義控件的指南。


文章結構(兩種思路實現):1.復用率不高的,而且在dialog進行的邏輯處理較多的情況下,建議使用將dialog封裝成一個類,繼承基本的Dialog類實現。(在這里的后面會詳細說明自定義樣式的問題喔!)2.復用率高,而且每個dialog都要求有固定的布局格式的話,建議使用一個BaseDialog類作為你實際實現dialog的父類


先上圖:
這里寫圖片描述
就是這種仿谷歌風格的自定義dialog啦??!


一、第一種思路實現的詳解:

首先當然是你想要的dialog布局,這里你自己想怎么折騰就怎么折騰隨你。由于這里使用了radiobutton的多向運用,可在此不詳細解析,欲想看明radiobutton的多向運用請看我的另一篇博客: Android之RadioButton和RadioGroup結合Dialog的多種運用詳解

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="360dp"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:layout_gravity="center"
        android:layout_marginTop="20dp"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/icon_title"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_marginLeft="18dp"
            android:gravity="center"
            android:src="@drawable/setting" />

        <TextView
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="30dp"
            android:layout_marginLeft="20dp"
            android:gravity="center_vertical"
            android:text="廣播周期設定"
            android:textSize="17sp" />
    </LinearLayout>

    <RadioGroup
        android:id="@+id/groupBroadcast"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="18dp"
        android:layout_marginTop="10dp"
        android:orientation="vertical">

        <RadioButton
            android:id="@+id/rbtn_BroadcastClose"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:button="@null"
            android:checked="true"
            android:drawableLeft="@drawable/settingbroadst_checked_style"
            android:drawablePadding="20dp"
            android:paddingLeft="18dp"
            android:text="關閉"
            android:textColor="@android:color/black"
            android:textSize="17sp" />

        <RadioButton
            android:id="@+id/rbtn_BroadcastFifteen"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_weight="1"
            android:button="@null"
            android:drawableLeft="@drawable/settingbroadst_checked_style"
            android:drawablePadding="20dp"
            android:paddingLeft="18dp"
            android:text="15秒"
            android:textColor="@android:color/black"
            android:textSize="17sp" />

        <RadioButton
            android:id="@+id/rbtn_BroadcastThirty"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_weight="1"
            android:button="@null"
            android:drawableLeft="@drawable/settingbroadst_checked_style"
            android:drawablePadding="20dp"
            android:paddingLeft="18dp"
            android:text="30秒"
            android:textColor="@android:color/black"
            android:textSize="17sp" />

        <RadioButton
            android:id="@+id/rbtn_BroadcastFourty"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_weight="1"
            android:button="@null"
            android:drawableLeft="@drawable/settingbroadst_checked_style"
            android:drawablePadding="20dp"
            android:paddingLeft="18dp"
            android:text="45秒"
            android:textColor="@android:color/black"
            android:textSize="17sp" />

        <RadioButton
            android:id="@+id/rbtn_BroadcastMinute"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:layout_marginTop="10dp"
            android:layout_weight="1"
            android:button="@null"
            android:drawableLeft="@drawable/settingbroadst_checked_style"
            android:drawablePadding="20dp"
            android:paddingLeft="18dp"
            android:text="60秒"
            android:textColor="@android:color/black"
            android:textSize="17sp" />
    </RadioGroup>
</LinearLayout>

然后就是封裝的dialog的類啦

package org.fishDroneGCS.view;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.RadioButton;
import android.widget.RadioGroup;

import org.fishDroneGCS.android.R;

/**
 * Created by 符柱成on 2016/8/7.
 */
public class RadioButtonDialog extends Dialog {

    private Context context;
    private String title;     //這里定義個title,一會可以看到是指向上面xml文件的控件title的,也就是我們可以通過這個進行動態修改title
    private AdapterView.OnItemClickListener   onItemClickListener;      //這里定義了一個監聽是為了實現內部的監聽接口處理,從而實現代碼分層管理
//可以看到兩個構造器,想自定義樣式的就用第二個啦
    public RadioButtonDialog(Context context) {
        super(context);
        this.context = context;
    }

    public RadioButtonDialog(Context context, int theme) {
        super(context, theme);
        this.context = context;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        init();
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public void setOnItemClickListener(AdapterView.OnItemClickListener onItemClickListener) {
        if (onItemClickListener != null)
            this.onItemClickListener = onItemClickListener;
    }
//控件的聲明
    RadioButton rbtn_BroadcastClose;
    RadioButton rbtn_BroadcastFifteen;
    RadioButton rbtn_BroadcastThirty;
    RadioButton rbtn_BroadcastFourty;
    RadioButton rbtn_BroadcastMinute;

    private void init() {
    //以view的方式引入,然后回調activity方法,setContentView,實現自定義布局
        View view = LayoutInflater.from(context).inflate(R.layout.dialog_broadcast, null);
        setContentView(view);
        //radiobutton的初始化
        RadioGroup groupBroadcast = (RadioGroup) view.findViewById(R.id.groupBroadcast);
        rbtn_BroadcastClose = (RadioButton) view.findViewById(R.id.rbtn_BroadcastClose);
        rbtn_BroadcastFifteen = (RadioButton) view.findViewById(R.id.rbtn_BroadcastFifteen);
        rbtn_BroadcastThirty = (RadioButton) view.findViewById(R.id.rbtn_BroadcastThirty);
        rbtn_BroadcastFourty = (RadioButton) view.findViewById(R.id.rbtn_BroadcastFourty);
        rbtn_BroadcastMinute = (RadioButton) view.findViewById(R.id.rbtn_BroadcastMinute);
        groupBroadcast.setOnCheckedChangeListener(listener);
        //設置dialog大小,這里是一個小贈送,模塊好的控件大小設置
        Window dialogWindow = getWindow();
        WindowManager manager = ((Activity) context).getWindowManager();
        WindowManager.LayoutParams params = dialogWindow.getAttributes(); // 獲取對話框當前的參數值
        dialogWindow.setGravity(Gravity.CENTER);//設置對話框位置
        Display d = manager.getDefaultDisplay(); // 獲取屏幕寬、高度
        params.width = (int) (d.getWidth() * 0.8); // 寬度設置為屏幕的0.65,根據實際情況調整
        dialogWindow.setAttributes(params);

    }
    //監聽接口
    private RadioGroup.OnCheckedChangeListener listener = new RadioGroup.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            if (checkedId == rbtn_BroadcastClose.getId()) {

            } else if (checkedId == rbtn_BroadcastFifteen.getId()) {

            } else if (checkedId == rbtn_BroadcastThirty.getId()) {

            } else if (checkedId == rbtn_BroadcastFourty.getId()) {

            } else if (checkedId == rbtn_BroadcastMinute.getId()) {

            }
        }
    };
}

調用:

  RadioButtonDialog radioButtonDialog=new RadioButtonDialog(getActivity(),R.style.Dialog);
        radioButtonDialog.setTitle("廣播周期設定");
        radioButtonDialog.create();
        radioButtonDialog.show();

就是這么簡單的調用,使其代碼的簡約,邏輯分層管理的實現了。此外,大家注意到那個我們這里使用的是自定義樣式。

在style文件里面定義以下:

  <style name="Dialog" parent="android:style/Theme.Dialog">
  <!-- 第一個是dialog的背景色,當然你可以設置圖片,不攔大家 -->
        <item name="android:background">@color/white</item>
        <!-- 第二個就是彈出dialog后,下面的activity層的顏色啦-->
        <item name="android:windowBackground">@android:color/transparent</item>
        <!--這里設置為沒有標題欄,如果這里不設置的話,你會發現無論布局怎么改都會出現多一欄白色 -->
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowFrame">@null</item><!--邊框-->
    </style>

好了第一種思路的實現就是這樣啦。這里補充一些關于自定義dialog樣式的style標簽

<item name="android:windowIsFloating">true</item><!--是否浮現在activity之上-->
<item name="android:windowIsTranslucent">false</item><!--半透明-->
<item name="android:backgroundDimEnabled">false</item><!--模糊-->

二、第二種思路實現方式詳解:

首先是dialog的xml文件我們并不改變它

父類dialog的封裝:BaseDialog.java

public abstract class BaseDialog extends Dialog {

    private Context context;    //下面三個定義的跟上面講得就是一樣的啦
    private String title;   
    private OnItemCheckListener onItemCheckListener;
    protected View view;    //看到這里我們定義的就清楚,我們也是借用view這個父類來引入布局的

    public BaseDialog(Context context) {
        super(context);
    }

    public BaseDialog(Context context, int themeResId) {
        super(context, themeResId);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        init();
    }


    public void setTitle(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public void setOnItemCheckListener(OnItemCheckListener onItemCheckListener) {
        if (onItemCheckListener != null)
            this.onItemCheckListener = onItemCheckListener;
    }


    protected void init() {
    //以view來引入布局
        View view = LayoutInflater.from(context).inflate(getLayoutId(), null);
        this.view=view;
        setContentView(view);
        //設置dialog大小
        Window dialogWindow = getWindow();
        WindowManager manager = ((Activity) context).getWindowManager();
        WindowManager.LayoutParams params = dialogWindow.getAttributes(); // 獲取對話框當前的參數值
        dialogWindow.setGravity(Gravity.CENTER);
        Display d = manager.getDefaultDisplay(); // 獲取屏幕寬、高度
        params.width = (int) (d.getWidth() * 0.8); // 寬度設置為屏幕的0.65,根據實際情況調整
        dialogWindow.setAttributes(params);
    }


//可以看到這里定義了一個抽象方法,這個將交由子類去實現
    public abstract int getLayoutId();
//為了邏輯分層管理,接口的管理實現方式
    public interface OnItemCheckListener {
        void onItemCheck(int checkedId);
    }
}

然后就是到了我們具體的dialog子類啦。

public class RadioButtonDialog extends BaseDialog {

    private Context context;
    private String title;
    private OnItemCheckListener onItemCheckListener;

    public RadioButtonDialog(Context context) {
        super(context);
        this.context = context;
    }

    public RadioButtonDialog(Context context, int theme) {
        super(context, theme);
    }
//回調這個方法啦
    @Override
    public int getLayoutId() {
        return 0;
    }
//也回調了父類的init,利用getLayoutId傳入了布局的id
    @Override
    protected void init() {
        super.init();

        RadioGroup groupBroadcast = (RadioGroup) view.findViewById(R.id.groupBroadcast);
        groupBroadcast.setOnCheckedChangeListener(listener);
    }

    private RadioGroup.OnCheckedChangeListener listener = new RadioGroup.OnCheckedChangeListener() {

        @Override
        public void onCheckedChanged(RadioGroup group, int checkedId) {
            onItemCheckListener.onItemCheck(checkedId);
        }
    };

    public interface OnItemCheckListener {
        void onItemCheck(int checkedId);
    }

}

實現的時候new出子類,然后用getLayoutId來set上布局id,就可以完成啦?。?!


這里給出繼承父類dialog的布局格式的思路:

比如:標題和確定鍵以及取消鍵都要求固定格式,實現:

1.子類要設置布局,所以要在父類留一個設置內容的方法,就像上面父類那樣,寫一個抽象方法,然后dialog中間布局就寫一個布局并且附上id,在父類方法addView,像getLayoutId那樣,然后子類回調這個方法,在addView里面,set上我們自定義的dialog內容布局就可以實現啦?。?!

好了,這個就是實現自定義dialog的兩種思路,以及如何進行自己的自定義控件的思路詳解啦!??!代碼里面都有詳細解析,就此結束啦??!

歡迎在下方指出錯誤,共同學習!

轉載請表明【JackFrost的博客】

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,335評論 25 708
  • ¥開啟¥ 【iAPP實現進入界面執行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,523評論 0 17
  • 遙想想我的高中時代,不得不提起的一個人,他單名一個錕字。 看《大魚海棠》時,開篇第一句“北冥有魚,其名為鯤。鯤之大...
    窗外陽光閱讀 838評論 17 23
  • /小雨文圖 月亮淺淺還在天上 大地之上已是鳥鳴蟲唱 輕嗅一朵花的香 一縷清風蕩漾 萬物竟綠,滿目蒼翠 喜歡這樣的生...
    小雨飄飄閱讀 660評論 13 17
  • 也許大家覺得被分手很丟人,可是為啥我不會呢,大概是因為我愛得沒那么深吧。我想了很久,心里也在糾結要不要說出來,但是...
    嘆嘆嘆息閱讀 265評論 0 1