Android AlertDialog对话框自定义风格的另类实现

一、引子

学过Android的同学都知道,对话框的重要程度非常高,任何一款 app几乎都离不开对话框,值得庆幸的是,对话框的运用在Android中还是相对比较容易的。虽然很简单,但我在项目中还是碰到些问题,比如,如何实现自定义的对话框NegativeButton的点击效果、如何改变标题的字体大小和颜色等。

二、分析和实现

下面来看一下下面那张效果图,微信长按通讯录时弹出的对话框。

我相信,只要是有了一定Android基础的同学都能实现此功能,就算一时忘记了,稍微google下也是能做出来的;根据效果图可以看到,系统自带的alertDialog肯定无法实现这样的效果,所以得通过自定义xml来实现布局,并在AlertDialog.Builder中调用AlertDialog.Builder.setView(View view)把自定义的布局文件塞进去,代码也很简单,直接贴出来。

1、wechat_dialog.xml

<?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"
    android:background="@color/white">
    <TextView
        android:id="@+id/id_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:text="曾文明"
        android:textColor="@color/bigColor"
        android:padding="20dp"/>
    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/lineColor"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="修改备注"
        android:padding="18dp"
        android:textSize="14sp"
        android:textColor="@color/txtColor"/>
</LinearLayout>

在MainActivity中调用

public static void showWeChatTitleDialog(Context context){
        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context) ;
        dialogBuilder.create() ;
        LayoutInflater inflater = LayoutInflater.from(context) ;
        View view = inflater.inflate(R.layout.wechat_dialog, null) ;
       dialogBuilder.setView(view) ;
       dialogBuilder.show() ;
}

运行效果就是上图的效果。到这里为止,不能说明任何问题,最多只能说明AlertDialog使用起来并不复杂,接下来才是重点;还是先来看一张效果图

也许你会说,这个也很简单,跟前面那张图的实现方式一样,自己写一个布局,然后通过 setView 把布局设置进去,没错,我相信很多人都是这样实现的。但是我告诉大家,这里的实现方式不是通过 setView()的方式来实现的,而是通过修改 Android 系统原生的 AlertDialog 中的控件来达到我们想要的效果。这样做的好处是什么呢?我们知道,如果是我们自己写布局文件肯定是需要为最下方的两个按钮设置点击事件,这样代码量就非常大;而 AlertDialog 的NegativeButton和PositiveButton已经为我们提供了点击事件的接口,使用起来非常简单。

先来看看如何修改NegativeButton的字体颜色?

1、毫无疑问第一步我们先要获取Button,在 AlertDialog 中有这样一个方法

public Button getButton(int whichButton) {
        return mAlert.getButton(whichButton);
}

所以 可以通过以下代码获取

Button mNegativeButton = mAlertDialog.getButton(AlertDialog.BUTTON_NEGATIVE) ;

2、设置Button的字体颜色为绿色,同时也可以设置点击状态

mNegativeButton.setTextColor(0xff45c01a);
mNegativeButton.setBackgroundResource(R.drawable.button_selector);

Button的效果已经实现了,同理另一个按钮也可以实现,再来看看 title 的字体颜色, 当然也希望能像获取 Button 一样,获取 title,进入 AlertDialog.java找啊,找啊,结果翻了个底朝天,硬是没有这样的方法。那怎么办?这时候就需要用到 Resources下的一个方法

    public int getIdentifier(String name, String defType, String defPackage) {
        if (name == null) {
            throw new NullPointerException("name is null");
        }
        try {
            return Integer.parseInt(name);
        } catch (Exception e) {
            // Ignore
        }
        return mAssets.getResourceIdentifier(name, defType, defPackage);
    }

这个方法的作用是什么呢?根据方法名可知,获取 Identifier,就是获取识别码,也就是代码中唯一的 Id。那这个方法的三个参数又分别代表什么东西呢?

name:资源文件中所需要操作的名称

defType:资源文件中操作的类型

defPackage:资源文件所在的包名

这样说比较难理解,还是举个例子,如果 defType 类型为 id,那么 name 就是android:id=”@+id/id_title”中的id_title

接下来就来看看怎么通过这个方法获取 alertDialog 的 title

1、获取 AlertDialog 中的 title

final int titleId = mContext.getResources().getIdentifier("alertTitle","id","android") ;
        TextView titleTxt = (TextView) mAlertDialog.findViewById(titleId);

“alertTitle”为系统alert_dialog.xml布局文件中title控件的 id 名称android:id=”@+id/alertTitle”,”id”代表获取的是 id,”android”为系统包名

2、设置 title 的字体颜色为绿色

titleTxt.setTextColor(0xff45c01a);

既然拿到了 title 的 View,就可以随心所欲的根据我们需求来设置效果。

再来看看这条绿色的线条和中间内容区域的设置

        final int titleDivider = mContext.getResources().getIdentifier("titleDivider","id","android") ;
        View titleDividerImg =  mAlertDialog.findViewById(titleDivider);
        titleDividerImg.setVisibility(View.VISIBLE);
titleDividerImg.setBackgroundColor(0xff45c01a);
        final int contentPanel = mContext.getResources().getIdentifier("contentPanel","id","android") ;
        LinearLayout contentPanelLayout = (LinearLayout) mAlertDialog.findViewById(contentPanel);
        contentPanelLayout.setVisibility(View.VISIBLE);
        final int message = mContext.getResources().getIdentifier("message","id","android") ;
        TextView messageTextView = (TextView) mAlertDialog.findViewById(message);
        messageTextView.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,20,mContext.getResources().getDisplayMetrics()));
        messageTextView.setPadding(20,20,20,20);
        messageTextView.setVisibility(View.VISIBLE);

我们回到获取NegativeButton的代码中,其实既然 title 和 titleDivider能通过getIdentifier获取,button 同样能通过getIdentifier来获取,具体实现代码如下:

        final int button1 = mContext.getResources().getIdentifier("button1","id","android") ;
        Button negativeButton = (Button) mAlertDialog.findViewById(button1);
        negativeButton.setBackgroundResource(R.drawable.button_selector);
        negativeButton.setVisibility(View.VISIBLE);
        negativeButton.setTextColor(0xff45c01a);
        final int button2 = mContext.getResources().getIdentifier("button2","id","android") ;
        Button positiveButton = (Button) mAlertDialog.findViewById(button2);
        positiveButton.setBackgroundResource(R.drawable.button_selector);
        positiveButton.setVisibility(View.VISIBLE);
        positiveButton.setTextColor(0xff45c01a);

可以看到,第二张效果图,完全是使用的系统自带的对话框布局实现。

三、归纳

可以看到整篇文章的核心就是

public int getIdentifier(String name, String defType, String defPackage)

掌握了这个方法,对于修改 AlertDialog 就不在话下,当然此方法的用处在这里只能算的上是冰上一脚。

需要对 AlertDialog 的各个控件熟练运用就必须知道系统的alert_dialog.xml定义了那些 View,alert_dialog.xml的路径是

//device/apps/common/res/layout/alert_dialog.xml。

四、alert_dialog.xml的源码

<?xml version="1.0" encoding="utf-8"?>
    <!--
*//* //device/apps/common/res/layout/alert_dialog.xml
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*//*
            -->

    <LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parentPanel"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:paddingTop="9dip"
    android:paddingBottom="3dip"
    android:paddingStart="3dip"
    android:paddingEnd="1dip">

    <LinearLayout android:id="@+id/topPanel"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="54dip"
    android:orientation="vertical">
    <LinearLayout android:id="@+id/title_template"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:gravity="center_vertical"
    android:layout_marginTop="6dip"
    android:layout_marginBottom="9dip"
    android:layout_marginStart="10dip"
    android:layout_marginEnd="10dip">
    <ImageView android:id="@+id/icon"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="top"
    android:paddingTop="6dip"
    android:paddingEnd="10dip"
    android:src="@drawable/ic_dialog_info" />
    <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
    style="?android:attr/textAppearanceLarge"
    android:singleLine="true"
    android:ellipsize="end"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAlignment="viewStart" />
    </LinearLayout>
    <ImageView android:id="@+id/titleDivider"
    android:layout_width="match_parent"
    android:layout_height="1dip"
    android:visibility="gone"
    android:scaleType="fitXY"
    android:gravity="fill_horizontal"
    android:src="@android:drawable/divider_horizontal_dark" />
    <!-- If the client uses a customTitle, it will be added here. -->
    </LinearLayout>

    <LinearLayout android:id="@+id/contentPanel"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:orientation="vertical">
    <ScrollView android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="2dip"
    android:paddingBottom="12dip"
    android:paddingStart="14dip"
    android:paddingEnd="10dip"
    android:overScrollMode="ifContentScrolls">
    <TextView android:id="@+id/message"
    style="?android:attr/textAppearanceMedium"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="5dip" />
    </ScrollView>
    </LinearLayout>

    <FrameLayout android:id="@+id/customPanel"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_weight="1">
    <FrameLayout android:id="@+android:id/custom"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="5dip"
    android:paddingBottom="5dip" />
    </FrameLayout>

    <LinearLayout android:id="@+id/buttonPanel"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:minHeight="54dip"
    android:orientation="vertical" >
    <LinearLayout
    style="?android:attr/buttonBarStyle"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:paddingTop="4dip"
    android:paddingStart="2dip"
    android:paddingEnd="2dip"
    android:measureWithLargestChild="true">
    <LinearLayout android:id="@+id/leftSpacer"
    android:layout_weight="0.25"
    android:layout_width="0dip"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:visibility="gone" />
    <Button android:id="@+id/button1"
    android:layout_width="0dip"
    android:layout_gravity="start"
    android:layout_weight="1"
    style="?android:attr/buttonBarButtonStyle"
    android:maxLines="2"
    android:layout_height="wrap_content" />
    <Button android:id="@+id/button3"
    android:layout_width="0dip"
    android:layout_gravity="center_horizontal"
    android:layout_weight="1"
    style="?android:attr/buttonBarButtonStyle"
    android:maxLines="2"
    android:layout_height="wrap_content" />
    <Button android:id="@+id/button2"
    android:layout_width="0dip"
    android:layout_gravity="end"
    android:layout_weight="1"
    style="?android:attr/buttonBarButtonStyle"
    android:maxLines="2"
    android:layout_height="wrap_content" />
    <LinearLayout android:id="@+id/rightSpacer"
    android:layout_width="0dip"
    android:layout_weight="0.25"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:visibility="gone" />
    </LinearLayout>
    </LinearLayout>
    </LinearLayout>

源码下载地址:AlertDialog通过自带的布局实现自定义的风格

时间: 2024-10-10 06:27:50

Android AlertDialog对话框自定义风格的另类实现的相关文章

Android AlertDialog对话框回调

封装的Dialog对话框,有时候需要获取选项这时候就用到了函数的回调 package com.example.testlistq; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.view.KeyEvent; public class MyDialog { private static AlertDialog

android:常用的AlertDialog对话框及自定义对话框

常用的Dialog有确认对话框,单选按钮对话框,多选按钮对话框,复选按钮对话框另外还有自定义的对话框 AlertDialog的常用方法 setTitle:为对话框设置标题 setMessage:为对话框设置内容 setIcon:为对话框设置图标 setItems设置对话框要显示的list setMultiChoiceItems:一般用于复选框显示 setSingleChoiceItem:,设置单选按钮 setNeutralButton:普通按钮 setPositiveButton:添加确定按钮

Android基础入门教程——2.5.3 AlertDialog(对话框)详解

Android基础入门教程--2.5.3 AlertDialog(对话框)详解 标签(空格分隔): Android基础入门教程 本节引言: 本节继续给大家带来是显示提示信息的第三个控件AlertDialog(对话框),同时它也是其他 Dialog的的父类!比如ProgressDialog,TimePickerDialog等,而AlertDialog的父类是:Dialog! 另外,不像前面学习的Toast和Notification,AlertDialog并不能直接new出来,如果你打开 Alert

Android中 Alertdialog对话框点击消失?

在开发的时候遇到一个问题,就是一触摸对话框边缘外部,对话框会自动消失.这个问题很纠结啊,查找了一下发现从Android 4.0开始,AlertDialog有了变化,就是在触摸对话框边缘外部,对话框会自动消失,查了源码,找到解决办法: 研究其父类时候发现,可以设置这么一条属性,在AlertDialog.Builder.create()之后才能调用这两个方法 方法一: setCanceledOnTouchOutside(false);调用这个方法时,按对话框以外的地方不起作用.按返回键还起作用 方法

Android中制作自定义dialog对话框的实例

http://www.jb51.net/article/83319.htm 这篇文章主要介绍了Android中制作自定义dialog对话框的实例分享,安卓自带的Dialog显然不够用,因而我们要继承Dialog类来制作自己的对话框,需要的朋友可以参考下 自定义dialog基础版很多时候,我们在使用android sdk提供的alerdialog的时候,会因为你的系统的不同而产生不同的效果,就好比如你刷的是MIUI的系统,弹出框都会在顶部显示!这里简单的介绍自定义弹出框的应用. 首先创建布局文件d

Android之对话框

一:AlertDialog AlertDialog的构造方法全部是Protected的,所以不能直接通过new一个AlertDialog来创建出一个AlertDialog. 要创建一个AlertDialog,就要用到AlertDialog.Builder中的create()方法. AlertDialog.Builder常用方法    setTitle :为对话框设置标题 setIcon :为对话框设置图标 setMessage:为对话框设置内容 setView : 给对话框设置自定义样式 set

[Android] AlertDialog获取网上天气并显示各城市天气

    最近帮同学做android百度地图,其中涉及到定位城市天气功能.才知道自己技术非常的一般,还有很多东西需要学习,同时需要回归到我研究生的方向--数据挖掘.同时又见识到了一位叫柳峰的大神,推荐大家去看看他的文章,好像他还是贵州的老乡.博文地址:http://blog.csdn.net/lyq8479/ 言归正传,我主要通过两种方法实现: 1.第一种方法是通过调用中国天气网信息实现的,它的思想是通过查询静态数据库中个城市对应的WeatherCode,在通过访问中国天气网获取JSON格式数据显

Android开发之自定义Dialog二次打开报错问题解决

之前自定义了一个AlertDialog对话框,第一次点击时正常,但第二次调用时会出现错误:java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first. 关于这个错误纠结了我好久,在网上百度了也不少,但感觉解决效果都达不到自己想要的效果.网上的解释说是一个子视图指定了多个父视图.由此可以推断出,在第二

浅谈android中的自定义封装易用的Dialog

好久没写android的博客,最近在做一个android的项目,里面用到我们经常用的一个控件就是对话框,大家都知道android自带的对话框是很丑的,android5.x之后除外.所以就出现了自定义view,自己定义美观的对话框.好我们就来自定义对话框. 整体思路:定义一个类然后去继承Dialog类,然后重写相应的构造器方法.大家都知道一般的对话框的创建过程都是来一个AlertDialog.Builder对象,然后使用一些set方法来设置标题内容以及设置一些自定义的view和点击的Button以