Android 布局小技巧汇总

xml 布局文件看似好写,也的确好,但是大家总是百思不得其解,为啥我写的页面显示慢,效率低,扩展麻烦,有的手机会出兼容问题!这都是大家平时积累不够的锅啊,xml布局文件的书写是有规范的,你写得差一点有的手机的确没事,但是这并不代表所有都是如此,我本人就碰到过使用相对布局不规范,出现的兼容问题。还有一两层布局嵌套就能解决的问题,为啥还有人写嵌套写到让人奔溃呢,善用 xml,写好 xml,可是看一个 android 开发技术功底的事,这里记录一些我个人看到的,总结的小技巧。

目录导航

  • 灵活使用 linearlayout 布局的权重
  • textview 最大行数,固定显示几行,下划线,删除线
  • 相对布局规范:能确定位置的,被依赖的控件写在前面
  • EditView的自定义样式:光标,下划线,选中图标,选中文字颜色
  • Scrollbar自定义样式
  • clipChildren属性的使用:允许子View超出父View
  • 点九图(.9.png)的使用
  • 使用 tools:attribute 属性在 xml 中查看效果
  • 快速生成 style 样式

灵活使用 linearlayout 布局的权重


  • 将一个Button在一行中居中,并且Button的宽度占屏幕宽度的一半

解决方案:先看具体的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="wrap_content"

    android:background="#708069"

    android:gravity="center_horizontal"

    android:orientation="horizontal"

    android:weightSum="1" >

    <Button

        android:layout_width="0dp"

        android:layout_height="wrap_content"

        android:layout_weight="0.5"

        android:text="测试按钮" />
 
</LinearLayout>

其中LinearLayout的android:gravity="center_horizontal"作用是让Button水平居中;LinearLayout的android:weightSum="1",Button设置android:layout_weight="0.5",则表示button占据父布局即LinearLayout一半的宽度,而LinearLayout为match_parent,因此Button会占据屏幕一半的宽度。


  • 最外层是LinearLayout,里面水平从左到右放TextView A,TextView B和一个Button C,要求A居左,C居右,B紧靠A,且单行显示,如果文字过多则打点。

解决方案:为A设置android:layout_width="wrap_content",为C设置 android:layout_width="wrap_content",且 android:gravity="right|center_vertical",为B设置android:layout_width="0dp",android:layout_weight="1"和android:singleLine="true"。 很容易理解,A在左边,C在右边,然后B利用权重占据剩余的水平空间,由于设置了singleLine,因此文字如果超过一行就会打点。

  • 实现下图的效果


解决方案:

(1)左右分别为TextView和ImageView(当然使用Button也可以,这不是重点),外层包一个水平的LinearLayout。使用shape为TextView和Button分别设置带圆角(左边的shape设置左上和左下圆角,右边的shape设置右上和右下圆角)和蓝色边框的背景。这样做的问题是TextView的右边框和Button的左边框都会存在,导致中间的线会是正常边框的两倍。因为shape不支持隐藏某一边的边框,因此只能另想他法,我采用了将右边Button左移动1dp(边框的宽度为1dp,或者TextView右移1dp),这样中间的两个线条就会重合,基本可以实现如图效果,但也有瑕疵,细看的话,中间的竖线由于是两条线的重合效果,会显得比边框亮一些。

(2)为外层LinearLayout设置带四个圆角和颜色的边框,LiearLayout里面水平放置2个控件,左边TextView,中间一个竖线View(width=1dp,跟边框相同宽度,高度为match_parent,颜色为边框颜色),右边是Button,然后再给TextView和Button设置shape背景,与方法(1)不同的是不要设置实体边框,因为LinearLayout已经设置了边框。这样实现的效果就比较完美了。值得注意的是需要给LinearLayout设置一个边框宽度大小的padding,不然TextView和Button的默认颜色会覆盖掉LinearLayout边框的颜色,导致看不到外层边框。

textview 最大行数,固定显示几行,下划线,删除线


  • TextView文本最多显示两行,多则在末尾打点显示。

解决方案:为TextView添加如下属性:

android:maxLines="2"

android:ellipsize="end"

第一个属性表示该TextView最多可显示两行。第二个属性设为end,表示将会在末尾打点,还可以设为其他属性,如start、middle、none等,根据名字很容易就能理解了。

注意有一个android:ellipsize="marquee",即传说中的跑马灯效果,

若要让TextView里的文本滚动,必须满足以下几个因素:

(1)TextView里文本宽度超过TextView的宽度,一般需设置android:singleLine="true"

(2)android:ellipsize="marquee"

(3)只有在TextView获取到焦点时,才会滚动.所以加上android:focusableInTouchMode="true"

android:focusable="true"

滚动重复次数设置:

android:marqueeRepeatLimit="marquee_forever"

注意:有时候设置了android:maxLines="2",而文字只有一行的时候,会导致TextView跟有两行文字时高度不一致,因此常常同时设置

android:lines="2",强制占据两行的高度。

  • 需求:给文字设置下划线、中划线

解决方案:如下代码分别设置了下划线和中划线

textView.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG );

textView.getPaint().setFlags(Paint.STRIKE_THRU_TEXT_FLAG);

注意,所生成的线的颜色跟TextView文字的颜色是一致的,如果想把文字和下划线分别设为不同的颜色,貌似没有发现TextView有现成的方法或属性支持,我们可以采用其他策略实现,如文字和下划线使用两个不同的view来实现。

相对布局规范:能确定位置的,被依赖的控件写在前面


先来看一个布局
[图片上传失败...(image-75d901-1518453662209)]
这个布局的特点是按钮3底部对齐,按钮2在按钮3的上面,文本框水平充满剩余的区域,按钮1顶部对齐,列表框垂直充满剩余的区域。

下面我们会拆分为下面两个子问题:

水平充满剩余区域的问题:

水平方向上有两个组件,一个组件宽度为wrap_content(或者固定宽度),另外一个组件的需要充满剩余的宽度,效果如下:
[图片上传失败...(image-527c18-1518453662210)]
左侧一个文本框,右侧一个按钮
如果是嵌套一个LinearLayout布局肯定就十分简单了,如果用RelativeLayout也是可以的,如下:

<Button
    android:id="@+id/btn2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@id/btn3"
    android:layout_alignParentRight="true"
    android:text="按钮2"
    />
<EditText
    android:id="@+id/et"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBaseline="@id/btn2"
    android:layout_alignParentLeft="true"
    android:layout_toLeftOf="@id/btn2"
    />

主要方法如下:(主要通过toRightOf和toLeftOf两个属性)

  1. 两个组件的布局宽度都是wrap_content(或者固定宽度)
  2. 左边的组件alignParentLeft,右边的组件alignParentRight(如果他们左右分别有一些固定宽度的组件,就用toRightOf(左侧)或者toLeftOf(右侧)指定的组件)
  3. 为了让左边的组件紧挨着右边的组件,也就是拉长左侧的文本框,设置toLeftOf="右边组件的ID" (这里是重点),这样,左侧文本框就会自动拉伸至和右侧按钮紧挨着。
  4. 当然,最后,两边组件要水平对齐,对左边组件用alignBaseline="右边组件的ID"
  5. 注意要把右侧按钮在代码中放到前面(否则编译时找不到对应的id,因为左侧EditText布局依赖右侧按钮)

垂直充满剩余空间的问题:

垂直方向上有两个组件,第一个组件的高度为wrap_content(或固定高度),另外一个组件的高度需要充满剩余的高度,效果如前面的ListView:
[图片上传失败...(image-10e696-1518453662210)]

这个时候也可以通过RelativeLayout实现,下面我贴出了整个布局的代码(为了更好的说明,我在上面和下面都加了一个组件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">
    <Button
        android:id="@+id/btn1"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:text="固定宽度按钮"/>
    <Button
        android:id="@+id/btn3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:text="按钮3"/>
    <Button
        android:id="@+id/btn2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@id/btn3"
        android:layout_alignParentRight="true"
        android:text="按钮2"
        />
    <EditText
        android:id="@+id/et"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@id/btn2"
        android:layout_alignParentLeft="true"
        android:layout_toLeftOf="@id/btn2"
        />
    <ListView
        android:id="@+id/lv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_above="@id/btn2"
        android:layout_below="@id/btn1"
        />
</RelativeLayout>

主要看ListView的布局,方法如下:

  1. 让ListView below=上面的组件
  2. 让ListView above=下面的组件
  3. 注意将ListView依赖的组件都放到ListView的上面
    看前面我们给出的完整的布局文件代码,这里需要说明如下内容:

注意组件在代码中的前后摆放,不然会编译报错(前面一直在说),方法如下:
需要拉伸的组件放到后面,然后用另一个组件来进行整体的布局。也就是被依赖位置的都放到前面,那些固定长宽(指的是固定或者wrap_content且不依赖其他组件布局的)或者依赖父容器的组件都放到前面,其他组件放到后面,如前面的按钮1,按钮3,按钮2都放到了前面,因为按钮2依赖于按钮3(按钮2 above 按钮3),所以按钮2也放到了按钮3的后面。 (按钮1说的是最上面那个固定高度按钮)

让两个组件水平中线对齐的问题:

让一个组件和另外一个组件中线对齐:让其中一个组件足够高(或者我们知道哪个组件高度一定是高于顶一个组件的),然后让需要对齐的组件和这个没有内容的组件上下皆对齐(alignTop,alignBottom设置),然后将第二个组件的gravity为垂直居中即可。
如果是有 baseline 属性的 TextView,Button 这类显示文本的组件的话,可以通过 align_Baseline 来进行对齐,这里的 baseline指的是文本底部对其的,就像我们小时候拿一把尺子,然后比着尺子写字那种意思。

EditView的自定义样式:光标,下划线,选中图标,选中文字颜色


首先看看默认样式(SdkVersion=23,安卓6.0):



文字选择操作时:



文字选中时:

1.修改光标颜色

修改光标的颜色很简单,只需要使用android:textCursorDrawable="XXX" 属性。

首先我们自定义drawable,cursor.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <solid android:color="#9bd435"/> <!--颜色设置为浅绿色-->
    <size android:width="2dp"/>

</shape>

使用:

<EditText
     android:layout_width="match_parent"
     android:textCursorDrawable="@drawable/cursor"
     android:layout_height="50dp" />

效果图:


2.修改选中图标

这个图标就是默认样式的2图与3图中的墨绿色水滴状图标。同样也很简单,直接上代码。

<EditText
     android:layout_width="match_parent"
     android:textCursorDrawable="@drawable/cursor"
     android:textSelectHandleLeft="@drawable/icon"
     android:textSelectHandleRight="@drawable/icon"
     android:textSelectHandle="@drawable/icon"
     android:layout_height="50dp" />

效果:



是不是还觉得有点别扭,文字的选中颜色与EditView默认的下划线还是墨绿色,其实改起来也很简单。加上下面两行代码。

android:backgroundTint="#9bd435"     <!--下划线颜色-->
android:textColorHighlight="#9bd435" <!--选中文字背景色-->

最终自定义效果:


使用Material Design主题属性

首先了解一下Material Design 各个属性。这里有张在网上找来的图(感谢),此图一目了然。


那么其实就简单了,代码如下

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
       <item name="colorAccent">#9bd435</item>
       <item name="android:colorControlActivated">#9bd435</item>
       <item name="android:colorControlNormal">#cccccc</item>
</style>

补充一下:android:colorControlActivated表示EditText、Switch、CheckBox、RadioButton等控件激活时候的颜色。android:colorAccent与android:colorControlActivated作用一样,但是它可以同时设置文字选中颜色。android:colorControlNormal表示EditText、Switch、CheckBox、RadioButton等控件默认时的颜色。兼容5.0以下必须使用Theme.AppCompat主题(兼容部分效果),并且Activity要继承AppCompatActivity,在兼容时候需要把前面的android:前缀去掉。

效果图:



我看了下自己手机中的部分应用,发现使用1、2方法去自定义的只有UC浏览器,其中微信和淘宝直接使用的默认样式。支付宝使用了3方法,毕竟简单,效果也不错。

Scrollbar自定义样式


首先看看默认样式(SdkVersion=23,安卓6.0):

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:paddingLeft="20dp"
    android:paddingRight="20dp"
    android:layout_height="wrap_content">

    ......

</ScrollView>

效果图:

自定义滚动条首先我们要自定义drawable,scrollbar.xml自定义代码:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <solid android:color="#9bd435"/>
    <corners android:radius="2dp" />

</shape>

使用scrollbarThumbVertical:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:paddingLeft="20dp"
    android:paddingRight="20dp"
    android:scrollbarSize="4dp"
    android:scrollbars="vertical"
    android:scrollbarThumbVertical="@drawable/scrollbar"
    android:layout_height="wrap_content">

    ......

</ScrollView>

效果图:


当然水平方向的滚动条也是可以自定义的,同时这些也都适用于ListView、RecyclerView。

android:scrollbars="horizontal"
android:scrollbarThumbHorizontal="xxx"

最后还有一个android:scrollbarStyle="xxx",可以设置滚动条的位置。默认是insideOverlay,下面我直接上相应设置对应的效果图。

insideInset:(位置在padding内,会插入在View后面,不会遮挡View)


outsideOverlay:(位置在padding外,覆盖在View上,如果滚动条比padding大会遮挡View)


outsideInset:(位置在padding外,会插入在View后面,不会遮挡View)


最后两张图可能乍一看是一样的,其实仔细看button距滚动条的位置其实是不一样的。

3.修改滑动尽头阴影颜色

默认阴影如图:(SdkVersion=23,安卓6.0)

修改颜色有一种简单方法,使用Material Design主题属性colorPrimary,代码效果如下:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
       <item name="colorPrimary">#9bd435</item>
</style>

当然,如果你想去除阴影也非常简单,加上android:overScrollMode="never" 属性即可。

clipChildren属性的使用:允许子View超出父View


android:clipChildren的意思是是否允许子View超出父View。好像有点懵,那我们直接上例子。

图中是现在大多外卖app都会有的一个购物车效果。其中红框中的部分高度略高于旁边的View。那么这时就可以使用clipChildren来实现。首先在布局根节点设置android:clipChildren="false",在使用android:layout_gravity="xxx"控制超出部分。

代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipChildren="false"> <!--这里-->

    <LinearLayout
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:orientation="horizontal">

        <RelativeLayout
            android:layout_gravity="bottom" <--这里
            android:layout_marginLeft="10dp"
            android:layout_width="48dp"
            android:layout_height="60dp">

            <ImageView
                android:src="@drawable/icon_cart"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />

            <TextView
                android:layout_marginTop="6dp"
                android:layout_alignParentRight="true"
                android:background="@drawable/icon_spot"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                tools:text="1"
                android:textSize="12sp"
                android:gravity="center"
                android:textColor="#ffffff"/>

        </RelativeLayout>

        <TextView
            android:layout_marginLeft="10dp"
            android:textColor="#9bd435"
            tools:text="¥5.00"
            android:textStyle="bold"
            android:textSize="18sp"
            android:gravity="center_vertical"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="match_parent" />

        <TextView
            android:layout_width="110dp"
            android:textColor="#ffffff"
            android:gravity="center"
            android:textSize="16sp"
            android:text="去购物车"
            android:background="#9bd435"
            android:layout_height="match_parent" />

    </LinearLayout>

</RelativeLayout>

效果图:


点九图(.9.png)的使用


接着上面的购物车效果,在图中是不是有一个代表购买商品数量的数字。如果此时一个土豪一次买了上百份的外卖,上面的效果会如何?我就试了试,得到了下面的效果:


可以清楚地看到原本的圆形被横向拉伸了。。。那就说明这个圆形图标不是点九图。那么我们来制作张。

大家使用Studio可以很方便的去制作,首先右键图片,会弹出以下菜单:


点击Create 9-Patch file... 创建点九图片。


上图就是最终完成的图片,在上面我有标注各个位置的含义。

替换图片后现在再来看看效果:


使用 tools:attribute 属性在 xml 中查看效果


xml 中的 tools 属性是一个测试用的辅助属性,设置了 tools 的属性并不会真是的去给这个属性值赋值,而仅仅是用来在 xml 观察效果的


4134622-fec5a0b33476b3e5.gif

快速生成 style 样式


以前我们写 style 样式的样式是一样一样复制过去的,麻烦的要死,但是呢 AS 这个 IDE 开发工具是无比强大的,其实可以快速生成 style 样式的。右键打开菜单,依次选择Refactor -> Extract -> Style ,下面看我的图就明白了


Snip20180213_3.png

我们先正常编写一个 view ,然后在这个 view 的位置点击右键,然后如上面的操作,就会出现一个生成 style 样式的确认页,可以选择相关的属性,给 style 命名。是不是很方面

参考文章:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容