上一篇简单说明了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复制出来。