Android
1.1 背景相关与系统架构分析 1.2 开发环境搭建 1.2.1 使用Eclipse + ADT + SDK开发Android APP 1.2.2 使用Android Studio开发Android APP 1.3 SDK更新不了问题解决 1.4 Genymotion模拟器安装 1.5.1 Git使用教程之本地仓库的基本操作 1.5.2 Git之使用GitHub搭建远程仓库 1.6 .9(九妹)图片怎么玩 1.7 界面原型设计 1.8 工程相关解析(各种文件,资源访问) 1.9 Android程序签名打包 1.11 反编译APK获取代码&资源 2.1 View与ViewGroup的概念 2.2.1 LinearLayout(线性布局) 2.2.2 RelativeLayout(相对布局) 2.2.3 TableLayout(表格布局) 2.2.4 FrameLayout(帧布局) 2.2.5 GridLayout(网格布局) 2.2.6 AbsoluteLayout(绝对布局) 2.3.1 TextView(文本框)详解 2.3.2 EditText(输入框)详解 2.3.3 Button(按钮)与ImageButton(图像按钮) 2.3.4 ImageView(图像视图) 2.3.5.RadioButton(单选按钮)&Checkbox(复选框) 2.3.6 开关按钮ToggleButton和开关Switch 2.3.7 ProgressBar(进度条) 2.3.8 SeekBar(拖动条) 2.3.9 RatingBar(星级评分条) 2.4.1 ScrollView(滚动条) 2.4.2 Date & Time组件(上) 2.4.3 Date & Time组件(下) 2.4.4 Adapter基础讲解 2.4.5 ListView简单实用 2.4.6 BaseAdapter优化 2.4.7ListView的焦点问题 2.4.8 ListView之checkbox错位问题解决 2.4.9 ListView的数据更新问题 2.5.0 构建一个可复用的自定义BaseAdapter 2.5.1 ListView Item多布局的实现 2.5.2 GridView(网格视图)的基本使用 2.5.3 Spinner(列表选项框)的基本使用 2.5.4 AutoCompleteTextView(自动完成文本框)的基本使用 2.5.5 ExpandableListView(可折叠列表)的基本使用 2.5.6 ViewFlipper(翻转视图)的基本使用 2.5.7 Toast(吐司)的基本使用 2.5.8 Notification(状态栏通知)详解 2.5.9 AlertDialog(对话框)详解 2.6.0 其他几种常用对话框基本使用 2.6.1 PopupWindow(悬浮框)的基本使用 2.6.2 菜单(Menu) 2.6.3 ViewPager的简单使用 2.6.4 DrawerLayout(官方侧滑菜单)的简单使用 3.1.1 基于监听的事件处理机制 3.2 基于回调的事件处理机制 3.3 Handler消息传递机制浅析 3.4 TouchListener PK OnTouchEvent + 多点触碰 3.5 监听EditText的内容变化 3.6 响应系统设置的事件(Configuration类) 3.7 AnsyncTask异步任务 3.8 Gestures(手势) 4.1.1 Activity初学乍练 4.1.2 Activity初窥门径 4.1.3 Activity登堂入室 4.2.1 Service初涉 4.2.2 Service进阶 4.2.3 Service精通 4.3.1 BroadcastReceiver牛刀小试 4.3.2 BroadcastReceiver庖丁解牛 4.4.1 ContentProvider初探 4.4.2 ContentProvider再探——Document Provider 4.5.1 Intent的基本使用 4.5.2 Intent之复杂数据的传递 5.1 Fragment基本概述 5.2.1 Fragment实例精讲——底部导航栏的实现(方法1) 5.2.2 Fragment实例精讲——底部导航栏的实现(方法2) 5.2.3 Fragment实例精讲——底部导航栏的实现(方法3) 5.2.4 Fragment实例精讲——底部导航栏+ViewPager滑动切换页面 5.2.5 Fragment实例精讲——新闻(购物)类App列表Fragment的简单实现 6.1 数据存储与访问之——文件存储读写 6.2 数据存储与访问之——SharedPreferences保存用户偏好参数 6.3.1 数据存储与访问之——初见SQLite数据库 6.3.2 数据存储与访问之——又见SQLite数据库 7.1.1 Android网络编程要学的东西与Http协议学习 7.1.2 Android Http请求头与响应头的学习 7.1.3 Android HTTP请求方式:HttpURLConnection 7.1.4 Android HTTP请求方式:HttpClient 7.2.1 Android XML数据解析 7.2.2 Android JSON数据解析 7.3.1 Android 文件上传 7.3.2 Android 文件下载(1) 7.3.3 Android 文件下载(2) 7.5.1 WebView(网页视图)基本用法 7.5.2 WebView和JavaScrip交互基础 7.5.3 Android 4.4后WebView的一些注意事项 7.5.4 WebView文件下载 7.5.5 WebView缓存问题 7.5.6 WebView处理网页返回的错误码信息 7.6.1 Socket学习网络基础准备 7.6.2 基于TCP协议的Socket通信(1) 7.6.3 基于TCP协议的Socket通信(2) 7.6.4 基于UDP协议的Socket通信 8.1.1 Android中的13种Drawable小结 Part 1 8.1.2 Android中的13种Drawable小结 Part 2 8.1.3 Android中的13种Drawable小结 Part 3 8.2.1 Bitmap(位图)全解析 Part 1 8.2.2 Bitmap引起的OOM问题 8.3.1 三个绘图工具类详解 8.3.2 绘图类实战示例 8.3.3 Paint API之—— MaskFilter(面具) 8.3.4 Paint API之—— Xfermode与PorterDuff详解(一) 8.3.5 Paint API之—— Xfermode与PorterDuff详解(二) 8.3.6 Paint API之—— Xfermode与PorterDuff详解(三) 8.3.7 Paint API之—— Xfermode与PorterDuff详解(四) 8.3.8 Paint API之—— Xfermode与PorterDuff详解(五) 8.3.9 Paint API之—— ColorFilter(颜色过滤器)(1/3) 8.3.10 Paint API之—— ColorFilter(颜色过滤器)(2-3) 8.3.11 Paint API之—— ColorFilter(颜色过滤器)(3-3) 8.3.12 Paint API之—— PathEffect(路径效果) 8.3.13 Paint API之—— Shader(图像渲染) 8.3.14 Paint几个枚举/常量值以及ShadowLayer阴影效果 8.3.15 Paint API之——Typeface(字型) 8.3.16 Canvas API详解(Part 1) 8.3.17 Canvas API详解(Part 2)剪切方法合集 8.3.18 Canvas API详解(Part 3)Matrix和drawBitmapMash 8.4.1 Android动画合集之帧动画 8.4.2 Android动画合集之补间动画 8.4.3 Android动画合集之属性动画-初见 8.4.4 Android动画合集之属性动画-又见 9.1 使用SoundPool播放音效(Duang~) 9.2 MediaPlayer播放音频与视频 10.1 TelephonyManager(电话管理器) 10.2 SmsManager(短信管理器) 10.3 AudioManager(音频管理器) 10.4 Vibrator(振动器) 10.5 AlarmManager(闹钟服务) 10.6 PowerManager(电源服务) 10.7 WindowManager(窗口管理服务) 10.8 LayoutInflater(布局服务) 10.9 WallpaperManager(壁纸管理器) 10.10 传感器专题(1)——相关介绍 10.11 传感器专题(2)——方向传感器 10.12 传感器专题(3)——加速度/陀螺仪传感器

10.8 LayoutInflater(布局服务)

本节引言:

 本节继续带来的是Android系统服务中的LayoutInflater(布局服务),说到布局,大家第一时间 可能想起的是写完一个布局的xml,然后调用Activity的setContentView()加载布局,然后把他显示 到屏幕上是吧~其实这个底层走的还是这个LayoutInflater,用的Android内置的Pull解析器来解析 布局。一般在Android动态加载布局或者添加控件用得较多,本节我们就来学习下他在实际开发中 的一些用法~

官方API文档LayoutInflater


1.LayoutInflater的相关介绍


1)Layout是什么鬼?

答:一个用于加载布局的系统服务,就是实例化与Layout XML文件对应的View对象,不能直接使用, 需要通过getLayoutInflater( )方法或getSystemService( )方法来获得与当前Context绑定的 LayoutInflater实例!


2)LayoutInflater的用法

①获取LayoutInflater实例的三种方法

LayoutInflater inflater1 = LayoutInflater.from(this);  
LayoutInflater inflater2 = getLayoutInflater();  
LayoutInflater inflater3 = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); 

PS:后面两个其实底层走的都是第一种方法~

②加载布局的方法

public View inflate (int resource, ViewGroup root, boolean attachToRoot) 该方法的三个参数依次为:

①要加载的布局对应的资源id

②为该布局的外部再嵌套一层父布局,如果不需要的话,写null就可以了!

③是否为加载的布局文件的最外层套一层root布局,不设置该参数的话, 如果root不为null的话,则默认为true 如果root为null的话,attachToRoot就没有作用了! root不为null,attachToRoot为true的话,会在加载的布局文件最外层嵌套一层root布局; 为false的话,则root失去作用! 简单理解就是:是否为加载的布局添加一个root的外层容器~!


③通过LayoutInflater.LayoutParams来设置相关的属性:

比如RelativeLayout还可以通过addRule方法添加规则,就是设置位置:是参考父容器呢? 还是参考子控件?又或者设置margin等等,这个由你决定~


2.纯Java代码加载布局

我们早已习惯了使用XML生成我们需要的布局,但是在一些特定的情况下,我们 需要使用Java代码往我们的布局中动态的添加组件或者布局!

但是不建议大家完全地使用Java代码来编写Android页面布局,首先一点就是代码会多, 一多久容易乱,而且不利于业务的分离,我们还是建议使用xml来完成布局,然后通过 Java代码对里面的组件进行修改,当然有些时候可能需要使用Java动态的来添加组件!

纯Java代码加载布局的流程


——Step 1

创建容器:LinearLayout ly = new LinearLayout(this);

创建组件:Button btnOne = new Button(this);

——Step 2:

可以为容器或者组件设置相关属性: 比如:LinearLayout,我们可以设置组件的排列方向:ly.setOrientation(LinearLayout.VERTICAL); 而组件也可以:比如Button:btnOne.setText("按钮1"); 关于设置属性的方法可参见Android 的API,通常xml设置的属性只需在前面添加:set即可,比如 setPadding(左,上,右,下);

——Step 3:

将组件或容器添加到容器中,这个时候我们可能需要设置下组件的添加位置,或者设置他的大小: 我们需要用到一个类:LayoutParams,我们可以把它看成布局容器的一个信息包!封装位置与大小 等信息的一个类!先演示下设置大小的方法:(前面的LinearLayout可以根据不同容器进行更改)

LinearLayout.LayoutParams lp1 = new LinearLayout.LayoutParams(  
        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 

很简单,接着就到这个设置位置了,设置位置的话,通常我们考虑的只是RelativeLayout! 这个时候用到LayoutParams的addRule( )方法!可以添加多个addRule( )哦! 设置组件在父容器中的位置,

比如设置组件的对其方式:

RelativeLayout rly = new RelativeLayout(this);  
RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
lp2.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);  
Button btnOne = new Button(this);  
rly.addView(btnOne, lp2);

参照其他组件的对其方式: (有个缺点,就是要为参考组件手动设置一个id,是手动!!!!) 比如:设置btnOne居中后,让BtnTwo位于btnOne的下方以及父容器的右边!

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        RelativeLayout rly = new RelativeLayout(this);  
        Button btnOne = new Button(this);  
        btnOne.setText("按钮1");  
        Button btnTwo = new Button(this);  
        btnTwo.setText("按钮2");  
        // 为按钮1设置一个id值  
        btnOne.setId(123);  
        // 设置按钮1的位置,在父容器中居中  
        RelativeLayout.LayoutParams rlp1 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
        rlp1.addRule(RelativeLayout.CENTER_IN_PARENT);  
        // 设置按钮2的位置,在按钮1的下方,并且对齐父容器右面  
        RelativeLayout.LayoutParams rlp2 = new RelativeLayout.LayoutParams(  
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
        rlp2.addRule(RelativeLayout.BELOW, 123);  
        rlp2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);  
        // 将组件添加到外部容器中  
        rly.addView(btnTwo, rlp2);  
        rly.addView(btnOne, rlp1);  
        // 设置当前视图加载的View即rly  
        setContentView(rly);  
    }  
}  

——step 4:

调用setContentView( )方法加载布局对象即可! 另外,如果你想移除某个容器中的View,可以调用容器.removeView(要移除的组件);

运行截图


3.Java代码动态添加控件或xml布局

第二点我们讲解了使用纯Java代码来加载布局,实际当中用得并不多,更多的时候是动态 的添加View控件以及动态的加载XML布局!

1)Java代码动态增加View

动态添加组件的写法有两种,区别在于是否需要先setContentView(R.layout.activity_main); 下面演示下两种不同写法添加一个Button的例子:

先写个布局文件先:activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/RelativeLayout1"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent" >  
  
    <TextView   
        android:id="@+id/txtTitle"  
        android:layout_width="match_parent"  
        android:layout_height="wrap_content"  
        android:text="我是xml文件加载的布局"/>  
      
</RelativeLayout>  

第一种不需要setContentView()加载布局文件先:

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        Button btnOne = new Button(this);  
        btnOne.setText("我是动态添加的按钮");  
        RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(    
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    
        lp2.addRule(RelativeLayout.CENTER_IN_PARENT);    
        LayoutInflater inflater = LayoutInflater.from(this);  
        RelativeLayout rly = (RelativeLayout) inflater.inflate(  
                R.layout.activity_main, null)  
                .findViewById(R.id.RelativeLayout1);  
        rly.addView(btnOne,lp2);  
        setContentView(rly);  
    }  
} 

第二种不需要setContentView()加载布局文件先:

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        Button btnOne = new Button(this);  
        btnOne.setText("我是动态添加的按钮");  
        RelativeLayout.LayoutParams lp2 = new RelativeLayout.LayoutParams(    
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    
        lp2.addRule(RelativeLayout.CENTER_IN_PARENT);    
        RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);  
        rly.addView(btnOne,lp2);  
    }  
} 

分析总结

代码很简单,创建按钮后,我们又创建了一个LayoutParams对象,用来设置Button的大小, 又通过addRule()方法设置了Button的位置!

第一种方法:通过LayoutInflate的inflate()方法加载了activity_main布局,获得了外层容器, 接着addView添加按钮进容器,最后setContentView();

第二种方法:因为我们已经通过setContetView()方法加载了布局,此时我们就可以通过 findViewById找到这个外层容器,接着addView,最后setContentView()即可!

另外,关于这个setContentView( )他设置的视图节点是整个XML的根节点!


2)Java代码动态加载xml布局

接下来的话,我们换一个,这次加载的是xml文件!动态地添加xml文件! 先写下主布局文件和动态加载的布局文件:

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/RelativeLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <Button
        android:id="@+id/btnLoad"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="动态加载布局"/>
</RelativeLayout>  

inflate.xml

<?xml version="1.0" encoding="utf-8"?>  
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  
    android:gravity="center"  
    android:orientation="vertical"  
    android:id="@+id/ly_inflate" >  
  
    <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:text="我是Java代码加载的布局" />  
  
    <Button  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:text="我是布局里的一个小按钮" />  
  
</LinearLayout> 

接着到我们的MainActivity.java在这里动态加载xml布局:

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        //获得LayoutInflater对象;  
        final LayoutInflater inflater = LayoutInflater.from(this);    
        //获得外部容器对象  
        final RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);  
        Button btnLoad = (Button) findViewById(R.id.btnLoad);  
        btnLoad.setOnClickListener(new OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                //加载要添加的布局对象  
                LinearLayout ly = (LinearLayout) inflater.inflate(  
                        R.layout.inflate_ly, null, false).findViewById(  
                        R.id.ly_inflate);  
                //设置加载布局的大小与位置  
                RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(    
                        LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);    
                lp.addRule(RelativeLayout.CENTER_IN_PARENT);    
                rly.addView(ly,lp);  
            }  
        });  
    }  
} 

运行截图

代码分析

①获取容器对象:

final RelativeLayout rly = (RelativeLayout) findViewById(R.id.RelativeLayout1);

②获得Inflater对象,同时加载被添加的布局的xml,通过findViewById找到最外层的根节点

final LayoutInflater inflater = LayoutInflater.from(this);
LinearLayout ly = (LinearLayout) inflater.inflate(R.layout.inflate_ly, null, false)
   .findViewById(R.id.ly_inflate);

③为这个容器设置大小与位置信息:

RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(  
               LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
       lp.addRule(RelativeLayout.CENTER_IN_PARENT); 

④添加到外层容器中:

rly.addView(ly,lp);

4.LayoutInflater的inflate()方法源码

最后提供下LayoutInflater的inflate()方法的源码吧,有兴趣的可以看看~,其实就是Pull解析而已~

public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {    
    synchronized (mConstructorArgs) {    
        final AttributeSet attrs = Xml.asAttributeSet(parser);    
        mConstructorArgs[0] = mContext;    
        View result = root;    
        try {    
            int type;    
            while ((type = parser.next()) != XmlPullParser.START_TAG &&    
                    type != XmlPullParser.END_DOCUMENT) {    
            }    
            if (type != XmlPullParser.START_TAG) {    
                throw new InflateException(parser.getPositionDescription()    
                        + ": No start tag found!");    
            }    
            final String name = parser.getName();    
            if (TAG_MERGE.equals(name)) {    
                if (root == null || !attachToRoot) {    
                    throw new InflateException("merge can be used only with a valid "    
                            + "ViewGroup root and attachToRoot=true");    
                }    
                rInflate(parser, root, attrs);    
            } else {    
                View temp = createViewFromTag(name, attrs);    
                ViewGroup.LayoutParams params = null;    
                if (root != null) {    
                    params = root.generateLayoutParams(attrs);    
                    if (!attachToRoot) {    
                        temp.setLayoutParams(params);    
                    }    
                }    
                rInflate(parser, temp, attrs);    
                if (root != null && attachToRoot) {    
                    root.addView(temp, params);    
                }    
                if (root == null || !attachToRoot) {    
                    result = temp;    
                }    
            }    
        } catch (XmlPullParserException e) {    
            InflateException ex = new InflateException(e.getMessage());    
            ex.initCause(e);    
            throw ex;    
        } catch (IOException e) {    
            InflateException ex = new InflateException(    
                    parser.getPositionDescription()    
                    + ": " + e.getMessage());    
            ex.initCause(e);    
            throw ex;    
        }    
        return result;    
    }    
} 

本节小结:

本节给大家讲解了一下Android中的LayoutInflater(布局服务),以及动态加载View和控件 相关的东西,相信对初学控件的朋友带来帮助~好的,就说这么多,谢谢~

© 2021 jiaocheng.bubufx.com  联系我们
ICP备案:鲁ICP备09046678号-3