《一个Android工程的从零开始》-3、base(二) BaseActivity布局相关代码——空布局控件的运用

关于标题##

“空布局控件的运用”可能大多数人都没看懂,就如同我只是知道功能,却不知道该如何称呼一样,再次先表达一下歉意,如果谁知道这部分内容的正确命名格式,欢迎随时分享。

再扯两句

虽然不知道该扯什么 ,但还是习惯性的想要要扯两句。说实话,上一篇博客确实有一些乱,起初想写的东西实际上并不多,甚至这一篇的内容原计划都是在上一篇中,只是随着写的过程拓展太多,只能把今天的部分拿出来,再写一篇了(多亏开始的时候我就很机智的把昨天的标题设置成了base(一)而不是base(上),不然后面的标题还真没法写了。。。)。
不过我最初的目的也是想写的老少皆宜,就尽力把自己遇到过的坑,或者自以为学到的点都展现出来,希望新手看的过程不需要过多的自行百度,老人能够重温一些早已遗忘的点。
好了,再多废话就不说了,下面就开始我们继续BaseActivity之旅。
另外,为了更方便代码管理,我将码云上的工程分为了基于ConstraintLayout与仍使用LinearLayout、RelativeLayout配合的两个工程,如果有兴趣的可以对应查看。

正文

正文部分依旧是继续说明的BaseActivity的创建过程,只不过是这次是进入了java代码的阶段,该阶段一共将分为两个部分:其一是布局相关的部分,是上一篇博客内容的延续;另一部分是其他常用的方法、常量、变量的预设定。
本篇博客将为大家带来的是布局相关的内容,其他的内容会在后面与大家分享。

布局相关

首先,有一件事需要提前说明一下,本系列博客的题目是《一个Android工程的从零开始》,所以昨天的三种布局展示中,LinearLayout与RelativeLayout单独使用,在工程中实际上都不科学,因此想了解的可以看一下我的上一篇博客《一个Android工程的从零开始》-2、base(一)上传的部分是工程中常用的两者配合的方式。
在今天内容开始之前,还需要做的一件事,就是最后完善一下昨天的布局,其实就是为今天将要使用到的控件加上id(id的功能详见附录1,同时附上了一些细节调整),并在下面空白的部分加上一个空的布局控件而已(这个控件要充满所有空白的部分),至于这个布局控件的用处,下面会有说明。
首先还是先将修改过的布局代码贴出来。

非ConstraintLayout布局

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/base_scroll_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.mybaseapplication.base.BaseActivity">

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

        <RelativeLayout
            android:id="@+id/base_title_layout"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="@color/colorPrimary">

            <ImageView
                android:id="@+id/base_back"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:padding="@dimen/size_13"
                android:src="@mipmap/back"
                android:tint="@android:color/white" />

            <TextView
                android:id="@+id/base_title"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_centerInParent="true"
                android:gravity="center"
                android:text="@string/title"
                android:textColor="@android:color/white"
                android:textSize="@dimen/size_20" />

            <ImageView
                android:id="@+id/base_right_icon2"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_toLeftOf="@+id/base_right_icon1"
                android:contentDescription="@string/second_function_key"
                android:padding="@dimen/size_13"
                android:src="@mipmap/add"
                android:tint="@android:color/white"
                android:visibility="gone" />

            <ImageView
                android:id="@+id/base_right_icon1"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_alignParentRight="true"
                android:contentDescription="@string/first_function_key"
                android:padding="@dimen/size_13"
                android:src="@mipmap/more"
                android:tint="@android:color/white"
                android:visibility="gone" />

            <TextView
                android:id="@+id/base_right_text"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_alignParentRight="true"
                android:gravity="center"
                android:text="@string/make_sure"
                android:textColor="@android:color/white"
                android:textSize="@dimen/size_17"
                android:visibility="visible" />
        </RelativeLayout>

        <LinearLayout
            android:id="@+id/base_main_layout"
            android:layout_width="match_parent"
            android:layout_height="0dip"
            android:layout_weight="1"
            android:orientation="vertical">

        </LinearLayout>
    </LinearLayout>
</ScrollView>

ConstraintLayout布局

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/base_scroll_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".base.BaseActivity">

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/base_title"
            android:layout_width="0dp"
            android:layout_height="50dp"
            android:background="@color/colorPrimary"
            android:gravity="center"
            android:text="@string/title"
            android:textColor="@android:color/white"
            android:textSize="@dimen/size_20"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.0" />

        <ImageView
            android:id="@+id/base_back"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:padding="@dimen/size_13"
            android:src="@mipmap/back"
            android:tint="@android:color/white" />

        <ImageView
            android:id="@+id/base_right_icon2"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:padding="@dimen/size_13"
            android:src="@mipmap/add"
            android:tint="@android:color/white"
            android:visibility="gone"
            app:layout_constraintRight_toLeftOf="@+id/base_right_icon1" />

        <ImageView
            android:id="@+id/base_right_icon1"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:padding="@dimen/size_13"
            android:src="@mipmap/more"
            android:tint="@android:color/white"
            android:visibility="gone"
            app:layout_constraintRight_toRightOf="@+id/base_right_text" />

        <TextView
            android:id="@+id/base_right_text"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:gravity="center"
            android:text="@string/make_sure"
            android:textColor="@android:color/white"
            android:textSize="@dimen/size_17"
            android:visibility="visible"
            app:layout_constraintRight_toRightOf="@+id/base_title" />

        <android.support.constraint.ConstraintLayout
            android:id="@+id/base_main_layout"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginBottom="0dp"
            android:layout_marginLeft="0dp"
            android:layout_marginRight="0dp"
            android:layout_marginTop="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintLeft_toLeftOf="@+id/base_back"
            app:layout_constraintRight_toRightOf="@+id/base_right_text"
            app:layout_constraintTop_toBottomOf="@+id/base_title"
            app:layout_constraintVertical_bias="0.0">

        </android.support.constraint.ConstraintLayout>
    </android.support.constraint.ConstraintLayout>
</ScrollView>

强烈建议使用ScrollView内嵌套ConstraintLayout的看一下附录2。
以上就是在上一篇博客的基础上修改的布局代码,使用属性基本没变,如果不明白可以看一下上一篇我的上一篇博客(本篇开篇有链接)。
下面开始对应布局部分对应的java。

空布局控件的运用

首先,我们先从今天刚刚添加的,填充下面空白部分的布局控件开始吧。
刚创建工程的时候,系统会默认给我们生成一个MainActivity(如果你没有改名字的话),下面我们就在MainActivity的基础上进行我们后续的操作,帮助大家完善BaseActivity的同时,也能同时体会到为何要费这么大的力气去创建一个BaseActivity。

public class MainActivity extends AppCompatActivity {

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

上面的代码就是MainActivity生出来就带着的,无非就是一个类,继承了AppCompatActivity,这个类与Activity的区别,参见cxm11AppCompatActivity,然后重写了onCreate方法。而布局文件中则只有一个简单的TextView,内容则是经典的不能再经典的“Hello World”。
不过为了方便与BaseActivity配合的效果更明显的表示,我将TextView的布局更改了一下,充满父控件,加了背景颜色。至于效果,先保密,一会对比的时候再给大家看。

先给大家看一下我们运用后添加的新布局的,也就是id为base_main_layout布局,下面分别是传统布局与ConstraintLayout布局对应的方法,

传统布局

public void setBaseContentView(int layoutId) {
        ((ScrollView)findViewById(R.id.base_scroll_view)).setFillViewport(true);
        LinearLayout layout = (LinearLayout) findViewById(R.id.base_main_layout);
        LayoutInflater inflater = getLayoutInflater();
        final View view = inflater.inflate(layoutId, null);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.MATCH_PARENT);
        layout.addView(view, params);
}

ConstraintLayout布局

public void setBaseContentView(int layoutId) {
        ((ScrollView)findViewById(R.id.base_scroll_view)).setFillViewport(true);
        ConstraintLayout layout = (ConstraintLayout) findViewById(R.id.base_main_layout);
        LayoutInflater inflater = getLayoutInflater();
        final View view = inflater.inflate(layoutId, null);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT, 
                LinearLayout.LayoutParams.MATCH_PARENT);
        layout.addView(view, params);
    }

显而易见,这两种布局对应的代码唯一的区别就是在于base_main_layout对应的控件是LinearLayout还是ConstraintLayout,其他部分都是相同的。
首先说一下方法中的第一行代码吧,也是最让我想骂娘的一行代码。
findViewById(控件id),可以理解为校长点名,叫到谁的ID,就是谁,不过为了出来的结果不过都是这个学校的学生,所以这个时候就需要老师出来强转一下告诉校长,你点名的这个人是哪个班的(不过比名字多的限定是同一个xml文件中的id只能是唯一的)。所以这就是前面“(ScrollView)”作用,就是将得到的控件装换成为我们需要的ScrollView。校长为什么找你,肯定有事啊,那就是“.”后面的内容。
这里我不得不吐槽一下ScrollView,放在其内的控件的高度是默认的wrag_content,所以我防止了一个布局文件在其中之后,在程序执行的时候,由于其中什么也没有,计算了高度是0,再添加布局的时候,由于高度是0,所以就什么都显示不出来了,具体效果图,会在后面一起给出。
感谢Caesardadi《ScrollView子View为自定义View时需要注意的几点问题》帮了个大忙,没让我刚开始博客就夭折了,不然刚开始直接出一个显示不了的bug,而且还是我最引以为傲的点,后面也就不用写了。
在Caesardadi的博客中提到了上面我使用的方法

mScrollView.setFillViewport(true); 本方法是使子View可以拉伸来填满整个屏幕

所以,如此设置之后,我们传递来布局就能正常显示了。
而显示布局的所使用的方法就是布局的addView,可以将其他的布局添加到当前的布局控件之中,比如上面的方法是添加到LinearLayout中,而第二个方法则是添加到ConstraintLayout中。

而布局传递的方式自然是通过的万能的id,只不过这次传递的是layout的id而不再是前面使用的控件的id,至于layout的id去哪里找。

《《一个Android工程的从零开始》-3、base(二) BaseActivity布局相关代码——空布局控件的运用》 这里写图片描述

其中的xml的文件名就是id只是要
记得将“.xml”后缀去掉

使用getLayoutInflater();获取布局解析器,执行布局解析器的inflate(解析)方法就可以将布局解析出来,得到的是一个View,其中有两个参数,分别是布局id以及父控件(传null)。关于这部分内容,我在些这篇博客的过程中也发现了一个疑问,在最下方的疑问部分的疑问1,如果有哪位大能能够帮助解答,感激不尽。

抛开疑问先不谈,上面的在这部分代码还是能在正常工作的,如果后面找到答案,也会对应发布到我的博客中。

而这个方法调用时也很简单,先给大家在看一下原本的MainActivity中的代码是什么样的:

public class MainActivity extends AppCompatActivity {

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

我们在看一下更改之后的:

public class MainActivity extends BaseActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setBaseContentView(R.layout.activity_main);
    }
}

只需要两步就搞定了,1、将继承AppCompatActivity 改为继承BaseActivity;2、将setContentView改为setBaseContentView,也就是刚刚我们自己写的方法。
下面我们来看一下效果:
原本的布局:

《《一个Android工程的从零开始》-3、base(二) BaseActivity布局相关代码——空布局控件的运用》 这里写图片描述

好吧,这就是我刚刚说的修改后的布局,美观100%无缘了,好在效果够明确,下面再看一下使用了BaseActivity之后的是什么样的呢:

《《一个Android工程的从零开始》-3、base(二) BaseActivity布局相关代码——空布局控件的运用》 这里写图片描述

大家看出来变化了没有,所以只要之后用到这种布局的,就都使用一下使用一下BaseActivity,简简单单改两处地方,就可以轻松实现,不然用时你就需要做一遍我在上一篇博客中所做的操作,新页面加不停,工作重复不断,想想都觉得累,你说呢。
或许有人会问,做为什么出来的效果跟我的不一样,在标题栏上面会多出来一部分内容,就像下图中红色框内的部分:

《《一个Android工程的从零开始》-3、base(二) BaseActivity布局相关代码——空布局控件的运用》 这里写图片描述

这个部分参见附录3。

小结结语

以上这么长的篇幅,不知道大家看得如何,为了防止有人对我动刀动枪,临时决定,头部的处理就留在下一篇博客继续了。
别打脸!我也不想,可是随着写,总会拓展进来一些新的东西,我想与大家一起进步吗,仔细一点不是都能多学点东西嘛,嘿嘿嘿,好了,我要赶下一篇博客喽!敬请期待!

附录###

附录1:####

android:id=”@+id/XXX”:
就好像生出一个控件孩子,你给孩子取的名字,取了名字后自然需要向计生办报备,区别就在于这个现实中需要我们自己操作的过程,在as中自动在执行了,也就是将这个名字写入R.java,并未其生成一个int值的对应编号,也就相当于我们的身份证号。之后对控件如何操作,我们就可以使用它的名字XXX来代替了。
android:contentDescription:
这个属性是之前所没有注意到的,今天看到报黄才看了一下,是方便一些生理功能有缺陷的人使用应用程序的。比如我们有一个ImageView里面放置一张颜色复杂的图片,可能一些色弱色盲的人,分不清这张图片中画的是什么东西。如果用户安装了辅助浏览工具比如TalkBack,TalkBack就会大声朗读出用户目前正在浏览的内容。TextView控件TalkBack可以直接读出里面的内容,但是ImageView TalkBack就只能去读contentDescription的值,告诉用户这个图片到底是什么。
android:layout_toLeftOf:
是我依然使用的方法,但是在2.3.2中就已经报黄了,提示我们最好使用android:layout_toStartOf代替,但是替换后会提示将API level升至17,并且,还需要同时设置android:layout_toLeftOf属性,直到老平台忽略TextAlignment属性。所以这里就没有更换。
android:textSize
这里报黄我也很无奈啊,至于原因和解决方法很简单,那就是Google规定字体大小统一使用sp作单位,而这里我却使用了dp做单位。至于为什么,那就要从android的屏幕适配说起了,内容太多,大家自行百度一下dp这个单位是什么含义就能明白了。

附录2:####

想必来看附录2的朋友已经体验到ScrollView内嵌ConstraintLayout是有多恶心了吧,当然,如果你还没有被恶心到,可以去尝试一下。
布局代码的目的就是将用一个布局控件充满下方的标题下方的空白处,可是ScrollView内的直接子控件默认设置的高度是wrap_content,即便你设置了match_parent也依然如此(这部分在后面java部分也会有影响),所以当我们使用ConstraintLayout玩“拼图游戏”的时候,就会发现,新加进来的布局将原本的标题的布局都破坏了。
作为一个懒汉,我并没有去深究造成布局破坏的原因,而是直接将ScrollView注释掉,在ConstraintLayout中先把布局搞定,然后重新把ScrollView释放出来即可。

附录3:####

如果出现上面的问题,只需要修改一下AndroidManifest.xml中的主题就好。

《《一个Android工程的从零开始》-3、base(二) BaseActivity布局相关代码——空布局控件的运用》 这里写图片描述

将框内的部分修改成:

android:theme="@style/Theme.AppCompat.Light.NoActionBar">

这样再运行的时候,就不会有上面的那部分了。
至于AndroidManifest.xml在哪里,还是上图:

《《一个Android工程的从零开始》-3、base(二) BaseActivity布局相关代码——空布局控件的运用》 这里写图片描述

当然,作为懒人怎么可能这么费力去找,我们可以做一下如下操作:

《《一个Android工程的从零开始》-3、base(二) BaseActivity布局相关代码——空布局控件的运用》 这里写图片描述

《《一个Android工程的从零开始》-3、base(二) BaseActivity布局相关代码——空布局控件的运用》 这里写图片描述

这次是不是不需要我加箭头,你也能找到在哪里了!
不过,世界的进步是靠懒人推动的,当没有java文件或者是xml文件打开的时候,可以看到as出现如下的内容

《《一个Android工程的从零开始》-3、base(二) BaseActivity布局相关代码——空布局控件的运用》 这里写图片描述

不知道大家有没有好奇使用过的,而其中第一个就是我要说的,双击shift,在出现的提示框中输入你要搜的文件名即可

《《一个Android工程的从零开始》-3、base(二) BaseActivity布局相关代码——空布局控件的运用》 这里写图片描述

显而易见,我还没输入全,它自己就耐不住寂寞蹦出来了,只需要鼠标左击或者敲回车键就可以打开。

附录4:####

《一个Android工程的从零开始》目录

疑问###

疑问1:
解析的部分只能使用final View view = inflater.inflate(layoutId, null);,再将得到的view添加到layout中,而不能直接使用inflater.inflate(layoutId, (ViewGroup) layout, true);或者inflater.inflate(layoutId, (ViewGroup) layout, false);。
代码如下:

正常显示:

public void setBaseContentView(int layoutId) {
        ((ScrollView)findViewById(R.id.base_scroll_view)).setFillViewport(true);
        ConstraintLayout layout = (ConstraintLayout) findViewById(R.id.base_main_layout);
        LayoutInflater inflater = getLayoutInflater();
        final View view = inflater.inflate(layoutId, null);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
        layout.addView(view, params);
    }

非正常显示:

public void setBaseContentView(int layoutId) {
        ((ScrollView)findViewById(R.id.base_scroll_view)).setFillViewport(true);
        ConstraintLayout layout = (ConstraintLayout) findViewById(R.id.base_main_layout);
        LayoutInflater inflater = getLayoutInflater();
        layout = (ConstraintLayout)inflater.inflate(layoutId, (ViewGroup) layout, true);
    }

以及:

public void setBaseContentView(int layoutId) {
        ((ScrollView)findViewById(R.id.base_scroll_view)).setFillViewport(true);
        ConstraintLayout layout = (ConstraintLayout) findViewById(R.id.base_main_layout);
        LayoutInflater inflater = getLayoutInflater();
        layout = (ConstraintLayout)inflater.inflate(layoutId, (ViewGroup) layout, false);
    }
    原文作者:半寿翁
    原文地址: https://www.jianshu.com/p/35e265f8b630
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞