热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

浅析AndroidDialog中setContentView()方法

本篇文章主要介绍了AndroidDialog中setContentView()方法的相关知识。具有很好的参考价值。下面跟着小编一起来看下吧

概述

Dialog在Android中是一个很优秀的工具。在使用Dialog时,我们一般都会自定义要显示的内容布局。Dialog自带了三个方法来支持自定义内容布局。

 public void setContentView (int layoutResID);
 public void setContentView (View view);
 public void setContentView (View view, ViewGroup.LayoutParams params);

这三个方法内部的实现原理都是一样的,只是其封装深度不同而已。三个方法可以说分别照顾了不同定制深度的开发者。

setContentView()流程

直接查看Dialog的源代码,如下图1所示。

【图1】

上图中mWindow在Dialog类中的定义如下:

 import android.view.Window;
 Window mWindow;

那么,它从何而来呢?如下图2所示。

【图2】

由上图2可知,在构造Dialog对象时,这个mWindow的值也被确定。它由PolicyManager提供。再往下跟系统代码。

makeNewWindow(Context)方法的实现如下:

  // The static methods to spawn new policy-specific objects
  public static Window makeNewWindow(Context context) {
   return sPolicy.makeNewWindow(context);
  }

还得继续往下跟。

import com.andorid.policy.internal.policy.impl.Policy;
/**
 * {@hide}
 */
public class Policy implements IPolicy {
 //...

 public Window makeNewWindow(Context context) {
  return new PhoneWindow(context);
 }
}

到这,貌似就差不多看到尽头了,原来我们调用的setContentView就是在这个PhoneWindow类中被实现的。继续跟进。

import com.android.internal.policy.impl.PhoneWindow;
/**
 * Android-specific Window.
 * 

* todo: need to pull the generic functionality out into a base class * in android.widget. */ public class PhoneWindow extends Window implements MenuBuilder.Callback { //... }

setContentView(int)

这个方法的代码实现如下图3所示。

【图3】

整个的实现流程乍一看还算简单明了。我们传入的布局参数最后就是被加载到上图所示的那个 mContentParent 中的。这个mContentParent是一个ViewGroup类对象。

在上图所示的代码中第367行作了空判断,可见这个对象的实例的创建与installDecor()方法有关系。这个方法的实现较为复杂,这里我们只看mContentParent的实例化过程。

【图4】

这个generateLayout()方法的实现过程很繁杂。我们没有必要去把每一行的代码都看懂。只需要知道在它内部是这样创建mContentParent对象的就好了

最后会把这个contentParent作为结果返回即可。然后再回到图3,在图中所示代码处第378行完成了将我们传入的布局加载进系统容器中的操作。

setContentView(View)与setContentView(View, ViewGroup.LayoutParams)

这种方式设置内容布局比较灵活。一般用于布局中有需要在Java代码中做特殊操作的布局。如设置监听等。其具体实现代码如下图5所示。

【图5】

这个代码,并没什么特别的,它的目的都已经明明白白的表现在代码上了,就不再赘述了。

setContentView(View)无法设置布局尺寸的问题

使用setContentView(int)的方式时,可以直接通过在layout的根容器中指定宽、高来设置布局的尺寸。这里得注意,我指的是在根视图中直接指定宽度多少像素,高度多少像素这种直白的写法才可以控制布局的尺寸。若直接设为MATCH_PARENT,那么它的效果等同于WRAP_CONTENT。为什么会是这样的结果呢?本人并没有深究它的原因,但本人猜测(且后续并未去证实)这与mContentParent加载了布局后重新确定整个视图的尺寸的过程脱不了干系。我们来翻翻ViewGroup的代码,在ViewGroup中,有如下图6所示的一段代码。

【图6】

对于一个ViewGroup及其子类来说,它的MeasureSpec要么是EXACTLY要么是AT_MOST,我记不清这里头的具体关系了。但上图6所示的代码也已经非常直白了。对于MATCH_PARENT,它确实是按照WRAP_CONTENT的方式来处理的。这也就解释了上面所说的“令人费解”的情况了。虽然这个只是本人的猜测,但我估计也是八九不离十了。

而使用setContentView(View)的方式时,无论layout中根容器的宽高是什么,都按照WRAP_CONTENT的方式来走。这是为什么?我们先回去看看图5所示代码中这个方法的实现。可以发现,PhoneWindow给了一个默认的ViewGroup.LayoutParams对象。并且宽、高的值不偏不倚,正好是MATCH_PARENT。因此,当使用这种方式时,无论layout中根容器的宽高如何设置,它都表现成按内容的尺寸来适配布局的效果。因此,想要能控制对话框布局的尺寸,还是老老实实自己建一个有指定宽高值的LayoutParams对象给PhoneWindow对象吧,不要指望人家帮你擦屁股,擦不干净的~~

那么,到了这里,我们再来简单探究一下,setContentView(int)又是如何做到可以直接设置尺寸的。我们回去图3,看看这个方法的实现代码中,第378行。它在映射xml时,第二个参数传的直接是mContentParent。比较一下我们平时使用映射布局函数时,讲道理,直接传一个null的比较多吧,或者说,或许我们平时都很少注意到这个参数。我们去LayoutInflater中转转。

 import android.view.LayoutInflater;

inflate()方法的代码还是挺长的,这里就不详细贴了,我们只挑有代表性的来看。

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot)

// ...

final AttributeSet attrs = Xml.asAttributeSet(parser);

// ...

// Create layout params that match root, if supplied
params = root.generateLayoutParams(attrs);

// ...

// Temp is the root view that was found in the xml
final View temp = createViewFromTag(root, name, attrs, false);

// ...

if (root != null && attachToRoot) {
 root.addView(temp, params);
}
// ...

够清晰了吧。在这里,LayoutInflater在映射xml布局时主动去解析了所有的属性。当然会包括外层容器的属性。然后根据解析的结果生成一个LayoutParams对象,最后,再将要内容布局联合这个即时创建的LayoutParams对象一同添加到mContentParent容器中去,其实就相当于调用setContentView(View, LayoutParams)方法。所以在文章开头我才说到Dialog的三个设置内容布局的方法本质是一样的,只是其封装深度不同而已。

设置Dialog的背景为完全透明

Dialog默认有一个灰色的背景,首先这个背景巨丑,其次背景的存在还影响我们对对话框UI的定制。

   

在Activity中,可以通过在创建Dialog时传入一个无背景对话框的风格样式给构造器,以构造出无灰色背景的对话框出来。也可以通过Java代码控制对话框的背景色为透明色。还可以先show()对话框,然后再给它setContentView()来达到无背景色的对话框的目的。

1、 通过风格样式

  

 AlertDialog dialog = new AlertDialog.Builder(mContext, R.style.transBg).create();
 //或
 Dialog dlg = new Dialog(mContext, R.style.transBg);
 //等 

2、通过Java代码控制

所谓背景,其实就是PhoneWindow的背景。我们只需要设置PhoneWindow的背景为透明,就能达到我们想要的结果了。

// ...
AlertDialog dialog = builder.create();
dialog.show();
dialog.setContentView(view);
//方式1,使用透明的ColorDrawable对象。
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(0));
//方式2,使用一张透明的Drawable图片。
dialog.getWindow().setBackgroundDrawableResource(R.drawable.transparent);

3、先显示对话框再设置布局

这种方式只在Activity中有效果。

 AlertDialog dialog = builder.create();
 dialog.show();
 dialog.setContentView(view);

至于Service中为什么没有效果,本人怀疑是由于在Service中要想弹出对话框,只能将它设为系统级对话框,需要加多的一段代码导致的。但其具体原理还没有去研究过。

dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

在Service中。只能通过上述第1、第2种方式来实现背景透明的目的。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!


推荐阅读
  • Android 九宫格布局详解及实现:人人网应用示例
    本文深入探讨了人人网Android应用中独特的九宫格布局设计,解析其背后的GridView实现原理,并提供详细的代码示例。这种布局方式不仅美观大方,而且在现代Android应用中较为少见,值得开发者借鉴。 ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 本文详细介绍了如何使用Spring Boot进行高效开发,涵盖了配置、实例化容器以及核心注解的使用方法。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 2023年京东Android面试真题解析与经验分享
    本文由一位拥有6年Android开发经验的工程师撰写,详细解析了京东面试中常见的技术问题。涵盖引用传递、Handler机制、ListView优化、多线程控制及ANR处理等核心知识点。 ... [详细]
  • 本文介绍如何在 Unity 的 XML 配置文件中,将参数传递给自定义生命周期管理器的构造函数。我们将详细探讨 CustomLifetimeManager 类的实现及其配置方法。 ... [详细]
  • 解决JAX-WS动态客户端工厂弃用问题并迁移到XFire
    在处理Java项目中的JAR包冲突时,我们遇到了JaxWsDynamicClientFactory被弃用的问题,并成功将其迁移到org.codehaus.xfire.client。本文详细介绍了这一过程及解决方案。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
  • 本文介绍如何使用布局文件在Android应用中排列多行TextView和Button,使其占据屏幕的特定比例,并提供示例代码以帮助理解和实现。 ... [详细]
  • Startup 类配置服务和应用的请求管道。Startup类ASP.NETCore应用使用 Startup 类,按照约定命名为 Startup。 Startup 类:可选择性地包括 ... [详细]
  • 本文详细分析了JSP(JavaServer Pages)技术的主要优点和缺点,帮助开发者更好地理解其适用场景及潜在挑战。JSP作为一种服务器端技术,广泛应用于Web开发中。 ... [详细]
  • 本文探讨了如何在日常工作中通过优化效率和深入研究核心技术,将技术和知识转化为实际收益。文章结合个人经验,分享了提高工作效率、掌握高价值技能以及选择合适工作环境的方法,帮助读者更好地实现技术变现。 ... [详细]
  • 探索电路与系统的起源与发展
    本文回顾了电路与系统的发展历程,从电的早期发现到现代电子器件的应用。文章不仅涵盖了基础理论和关键发明,还探讨了这一学科对计算机、人工智能及物联网等领域的深远影响。 ... [详细]
author-avatar
萍子WYP
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有