Android——布局学习笔记

Android布局这里指App应用界面UI布局,按照设计图将用到的控件按照一定的排列组合到一起最终实现设计图的效果。

android布局主要有四大布局:
LinearLayout:线性布局
RelativeLayout:相对布局
FrameLayout:帧布局
AbsoluteLayout:绝对布局,算是弃用了,移动设备碎片化过于严重,无法让所有设备屏幕适应固定的宽高或间隔。
support特殊布局:
DrawerLayout:侧滑布局
SwipeRefreshLayout:下拉刷新布局
ConstraintLayout:约束布局,已经作为AS默认布局方式了,据说是为了减少布局层级

每一个控件都有它的宽和高,是必须填写的控件属性,即:

android:layout_width="fill_parent|match_parent|wrap_content"
android:layout_height="fill_parent|match_parent|wrap_content"

fill_parent:目前这个属性其实已由match_parent代替,所以就不说了
match_parent:适应屏幕大小,即屏幕多大,控件的宽或高就多大
wrap_content:适应控件内容大小,即控件宽高跟内容宽高一致,受padding甚至布局(相对布局、约束布局)影响

当然啦,除了系统提供的属性值外还可以填入具体的尺寸大小,尺寸大小的单位有dp、px、sp等:
dp:距离单位(dpppi/160 = px)
sp:安卓字体大小的单位(sp
ppi/160 = px)
ppi是像素密度(PPI = √(长度像素数² + 宽度像素数²) / 屏幕对角线英寸数)
dp和sp只能说类似,具体在Android内部转换会存在些许差异。
系统屏幕密度(参考)
ldpi文件夹下对应的密度为120dpi,对应的分辨率为240320
mdpi文件夹下对应的密度为160dpi,对应的分辨率为320
480
hdpi文件夹下对应的密度为240dpi,对应的分辨率为480800
xhdpi文件夹下对应的密度为320dpi,对应的分辨率为720
1280
xxhdpi文件夹下对应的密度为480dpi,对应的分辨率为1080*1920

LinearLayout线性布局:

有两种排列方式:android:orientation=“horizontal|vertical”
horizontal:水平方向为默认方向:子控件水平排列
vertical:垂直方向
它的子控件可以设置权重:android:layout_weight="[float]"
权重:子控件会根据权重按比例占有宽或者高的大小
权重分配方向:子控件宽高中设置为0dp的方向即为权重分配方向

<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="match_parent"
	android:layout_height="wrap_content"
	android:orientation="horizontal">
	<TextView
		android:id="@+id/textView1"
		android:layout_width="0dp"
		android:layout_height="wrap_content"
		android:layout_weight="1"
		android:text="权重1"/>
	<TextView
		android:id="@+id/textView2"
		android:layout_width="0dp"
		android:layout_height="wrap_content"
		android:layout_weight="2"
		android:text="权重2"/>
</LinearLayout>

这里写图片描述
这里写图片描述
LinearLayout的宽或高需要是一个具体值(包括match_parent),然后子控件才能根据权重比例对这个具体值进行分配,权重分配的方向由orientation属性决定。权重分配是将LinearLayout的宽或高具体值减去所有子控件的宽或高具体值再来按比例分配的,即textView1=(match_parent-0-0)*1/3,同理textView2占2份。

xmlns:android="http://schemas.android.com/apk/res/android"
这句话是用来引用android系统属性的,必须写在前面,一个xml有一个就够了
同时如果有自定义属性需要引用的话,也是这样写,只不过要将android改成你想要的
比如:xmlns:app="http://schemas.android.com/apk/res-auto"
ConstraintLayout布局是support包的,也算是自定义的,所以也要这样引用
比如:xmlns:tools="http://schemas.android.com/tools"
android:weightSum="[float]"
这个属性表示将LinearLayout平均分成多少份,如果在以上的代码中添加这一句,则会按照子控件的顺序进行分配:
android:weightSum="1",则textView1占满全屏
android:weightSum="2",各占一半
android:weightSum="3",刚好可以按比例分配
android:weightSum="4",按比例分配后还剩一份留空白,以此类推。

android:gravity="bottom|top|left|right|center|..."
决定子控件的显示位置

android:id="@+id/?"
通用属性,方便系统辨识和调用,项目中不要有重名。
android:layout_gravity="bottom|top|left|right|center|..."
通用属性,决定该布局或控件在父布局中的位置
android:margin=""
外边距
android:padding=""
内边距

RelativeLayout相对布局:

相对布局的意思是需要有一个参考控件,然后其他控件相对于参考控件的位置,如果没有设置,默认都在左上角。

其子控件可以设置的一些相对属性:

	android:layout_alignTop="@id/?"
    android:layout_alignBottom="@id/?"
    android:layout_alignLeft="@id/?"
    android:layout_alignStart="@id/?"
    android:layout_alignRight="@id/?"
    android:layout_alignEnd="@id/?"
    android:layout_toEndOf="@id/?"
    android:layout_toRightOf="@id/?"
    android:layout_toStartOf="@id/?"
    android:layout_toLeftOf="@id/?"
    android:layout_above="@id/?"
    android:layout_below="@id/?"
    ...

还有以下属性参考物为RelativeLayout:

    android:layout_alignParentTop="true|false"
	android:layout_alignParentBottom="true|false"      
    android:layout_alignParentLeft="true|false"
    android:layout_alignParentStart="true|false"  
    android:layout_alignParentRight="true|false"
    android:layout_alignParentEnd="true|false"                   
    android:layout_centerHorizontal="true|false"
    android:layout_centerInParent="true|false"
    android:layout_centerVertical="true|false"

因为相对布局的影响,子控件的属性android:layout_gravity是无效的。

FrameLayout帧布局

根布局就是这个,有重叠控件时用的多吧。如果子控件不用layout_gravity属性的话,子控件就是重叠再左上角默认位置。

DrawerLayout侧滑布局

该侧滑布局最多只有三个子布局(控件):左侧滑布局,默认布局,右侧滑布局
其中左右侧滑布局需要设置android:layout_gravity=“left|start|right|end”

SwipeRefreshLayout下拉刷新

该布局属于下拉刷新布局,是比较常用的一种刷新方式,当然目前开源的下拉或上拉刷新控件网上蛮多的,这里只说安卓自带的,属性没什么需要介绍的,想深入的话可以参考源码。需要实现OnRefreshListener监听,通过设置setRefreshing(true|false)显示或隐藏刷新状态。

上一篇简单说明了Android架构。

现在开始Android开发:Android应用界面元素有Activity、Fragment、Dialog等,这些元素都有各自对应的xml文件,即布局文件。界面显示元素的排布方式由布局文件决定,那么Android应用开发首先需要从布局开始,当然首先你得会Android开发语言:Java或Kotlin,推荐用Kotlin。

一、布局方式
布局方式 布局用法
ConstraintLayout 约束布局
LinearLayout 线性布局
RelativeLayout 相对布局
FrameLayout 帧布局
目前推荐的是约束布局ConstraintLayout,可以说是它是其余几个的集合体也不为过,所以就不写其他布局的属性,其实也不多,可以参照ConstraintLayout的属性。

约束布局跟相对布局的相似点就是需要有参照物,关于ConstraintLayout是有单独的库的,那么它的属性用法就相当于自定义属性,需要添加xmlns:app=“http://schemas.android.com/apk/res-auto”:

属性名 简介
layout_constraintTop_toTopOf 视图与参照物顶部对齐,值id
layout_constraintBottom_toBottomOf 视图与参照物底部对齐,值id
layout_constraintStart_toStartOf 视图与参照物左边对齐,值id
layout_constraintEnd_toEndOf 视图与参照物右边对齐,值id
layout_constraintTop_toBottomOf 视图顶部与参照物底部对齐,值id
layout_constraintBottom_toTopOf 视图底部与参照物顶部对齐,值id
layout_constraintStart_toEndOf 视图左边与参照物右边对齐,值id
layout_constraintEnd_toStartOf 视图右边与参照物左边对齐,值id
layout_constraintCircle 视图在参照物圆形定位上,值id
layout_constraintCircleAngle 视图在参照物圆形定位某角度上,值0-359
layout_constraintCircleRadius 视图在参照物圆形定位某半径上,值xxpx/dp
layout_constraintHorizontal_bias 水平偏移,需要确定左右对齐,值0~1
layout_constraintVertical_bias 垂直偏移,需要确定上下对齐,值0~1
layout_constrainedHeight 强制约束高度,值true/false
layout_constrainedWidth 强制约束宽度,值true/false
layout_constraintWidth_percent 水平占比,前置条件:width=0dp
layout_constraintHeight_percent 垂直占比,前置条件:height=0dp
layout_constraintDimensionRatio 宽高比约束,如宽高比2:1
layout_constraintHorizontal_chainStyle 水平链式关联,链式视图需要跟其中之一对齐,可设置weight
layout_constraintVertical_chainStyle 垂直链式关联,链式视图需要跟其中之一对齐,可设置weight
layout_constraintHorizontal_weight 水平占比权重,前置:width=0dp
layout_constraintVertical_weight 垂直占比权重,前置:height=0dp
layout_goneMarginTop 当参考视图为gone时生效,等同于marginTop,其余类似
二、Activity、Dialog
每一个界面都对应有布局文件,没有布局文件的界面就是一个空白界面,并没有意义。

将布局文件加载到界面调用setContentView,Fragment也对应着自己的布局文件,但Fragment的定义是Activity的碎片,意思是fragment是加载到Activity的layout中的,加载的方式是LayoutInflater.inflate()。

三、SwipeRefreshLayout

1、用法

<android.support.v4.widget.SwipeRefreshLayout
    android:id="@+id/refreshClient"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/spinner1">
    <!-- 这里是一个子view,仅能有一个子view,一般为AbsListView -->
</android.support.v4.widget.SwipeRefreshLayout>

让Activity继承SwipeRefreshLayout.OnRefreshListener
然后refreshLayout.setOnRefreshListener(this);
即可监听刷新动作,只要在onRefresh()里执行刷新代码即可

博主在使用时发现SwipeRefreshLayout会占满剩余屏幕,且它的子view也是一样,可以看SwipeRefreshLayout源码的onMeasure和onLayout方法。如果想要使它的子view是适应内容高度的话,博主测试了下,跟ScrollView的做法是一样的,但是这样子的话AbsListView就不能滑动了,从而知道SwipeRefreshLayout跟ScrollView还是不同的,之后就试了下在AbsListView外面套一层ScrollView,这时候就能让AbsListView自适应内容高度且能上下滑动了。

public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mTarget == null) {
            ensureTarget();
        }
        if (mTarget == null) {
            return;
        }
        mTarget.measure(MeasureSpec.makeMeasureSpec(
                getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
                MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(
                getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), MeasureSpec.EXACTLY));
        mCircleView.measure(MeasureSpec.makeMeasureSpec(mCircleDiameter, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(mCircleDiameter, MeasureSpec.EXACTLY));
        mCircleViewIndex = -1;
        // Get the index of the circleview.
        for (int index = 0; index < getChildCount(); index++) {
            if (getChildAt(index) == mCircleView) {
                mCircleViewIndex = index;
                break;
            }
        }
    }
    其中mCircleView就是那个刷新时出现的转圈圈的ImageView,而mTarget就是我们在布局文件里定义的SwipeRefreshLayout子View。可以看到mTarget和SwipeRefreshLayout的宽高是一致的,当然啦,不包括SwipeRefreshLayout的padding。
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        final int width = getMeasuredWidth();
        final int height = getMeasuredHeight();
        if (getChildCount() == 0) {
            return;
        }
        if (mTarget == null) {
            ensureTarget();
        }
        if (mTarget == null) {
            return;
        }
        final View child = mTarget;
        final int childLeft = getPaddingLeft();
        final int childTop = getPaddingTop();
        final int childWidth = width - getPaddingLeft() - getPaddingRight();
        final int childHeight = height - getPaddingTop() - getPaddingBottom();
        child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
        int circleWidth = mCircleView.getMeasuredWidth();
        int circleHeight = mCircleView.getMeasuredHeight();
        mCircleView.layout((width / 2 - circleWidth / 2), mCurrentTargetOffsetTop,
                (width / 2 + circleWidth / 2), mCurrentTargetOffsetTop + circleHeight);
    }
    一开始博主有试过在这里让mTarget自适应内容高度,也成功了,结果就是不能滑动,跟上面的一个方法效果一样,所以最后只能选择再套一层ScrollView了。

这里只是android本身自带的刷新控件的使用,网上很多人把这个layout修改成下拉刷新,上拉加载的控件了,博主还没看过源码,水平较低,暂不知怎么实现。如果要实现,怎么的也要将SwipeRefreshLayout负责出来修改,同时也要把MaterialProgressDrawable和CircleImageView复制出来。

布局时尽量不要嵌套太多层,减少加载耗时,优化性能。
布局时尽量不要写死控件宽高,减少屏幕适配问题,毕竟安卓碎片化严重。
目前手机应该是以4.4以上居多了,图片资源可使用mipmap-xhdpi和xxhdpi。
4.4以上的手机已经可以支持沉浸式了。
6.0以上手机必须进行危险权限申请了。
8.0的主题设置需要注意了

第三方库

网路请求:okhttp、retrofit
图片加载:fresco、glide、picasso、universal-image-loader
依赖注释:butterknife
设计模式:MVP、MVC、单例、观察者
通知:eventbus
移动后端:bmob、parse(需自己搭建)
数据库:ormlite(我也没用过)、greendao
json解析:gson、fastjson
埋点:bugly、友盟
网络调试:stetho
内存泄漏检查:leakcanary
xls读写:jxl.jar、POI
viewpager指示器:https://github.com/ongakuer/CircleIndicator
第三方登录:微信、QQ、微博等
分享:微信、QQ、微博等
地图:高德、百度
IM:环信、LeanCloud等
UI:
https://github.com/opendigg/awesome-github-android-ui
https://github.com/Trinea/android-open-project

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值