1 UI设计相关概念
1.1 View
视图,类似于窗户的格子,然后每个格子显示用户定义的内容。一般我们不直接使用View类,而是使用它的子类。
需要注意的是:View类位于android.view包内,而View的子类一般都位于android.widget包中。
View的常用属性:
- android:id属性,为view设定一个唯一的标识。
- android:background属性,为view设置背景,具体值可以是图片资源,也可以是颜色值
android:background="@mipmap/bg" android:background="#FF6600"
- android:padding属性,设置一个view的上下左右的4个内边距
//将四个方向的内边距设置成一样
android:padding="@dimen/activity_margin"
//分别对四个方向的内边距进行设置
android:paddingLeft
android:paddingTop
android:paddingRight
android:paddingBottom
android:paddingStart //其实就是左内边距
android:paddingEnd //其实就是右内边距
1.2 ViewGroup
如果将view比作窗户的格子的话,那么ViewGroup就是窗户框,负责控制格子的摆放。
ViewGroup类继承于View类,而且是一个抽象类。
ViewGroup控制其子组件分布时依赖于两个内部类:
- ViewGroup.LayoutParams类
- android:layout_height:FILL_PARENT、MATCH_PARENT、WRAP_PARENT
- android:layout_width:FILL_PARENT、MATCH_PARENT、WRAP_PARENT
- ViewGroup.MarginLayoutParams类
1.3 Android UI组件的层次结构
2 控制UI界面
2.1 选择控制UI界面的方法
2.1.1 使用XML布局文件控制UI界面(推荐)
好处:将布局文件待遇与控制逻辑的Java代码分隔开来
① 在Android应用的res/layout目录下编写XML布局文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
②在Activity中使用以下Java代码显示XML文件中布局的内容
setContentView(R.layout.activity_main);
2.1.2 在Java代码中控制UI界面
在android中,支持像JavaSwing一样完全通过Java代码来控制布局。
package com.example.xmllayout;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;
import org.w3c.dom.Text;
public class MainActivity extends AppCompatActivity {
@SuppressLint("ResourceAsColor")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout frameLayout = new FrameLayout(this);
frameLayout.setBackgroundResource(R.mipmap.tableball);
setContentView(frameLayout);
TextView text = new TextView(this);
text.setText(R.string.start);
text.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
text.setTextColor(Color.rgb(17, 85, 114));
text.setBackgroundColor(R.color.purple_700);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
params.gravity = Gravity.CENTER;
text.setLayoutParams(params);
text.setOnClickListener((v)->{
new AlertDialog.Builder(MainActivity.this).setTitle("系统提示")
.setMessage("游戏有风险,进入需谨慎,真的要进入吗?")
.setPositiveButton("确定",
(dialog, which)->{
Log.i("桌面台球","进入游戏");
})
.setNegativeButton("退出",
(dialog, which)->{
Log.i("桌面台球","退出游戏");
finish();
}).show();
});
frameLayout.addView(text);
}
}
2.1.3 使用XML和Java代码混合控制UI界面
<?xml version="1.0" encoding="utf-8"?>
<GridLayout 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/layout"
android:rowCount="3"
android:columnCount="4"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:context=".MainActivity">
</GridLayout>
package com.example.xmlandjava;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.GridLayout;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity {
private ImageView[] imgs = new ImageView[12];
private int[] imagePaths = new int[]{
R.mipmap.image1,R.mipmap.image2,R.mipmap.image3,R.mipmap.image4,
R.mipmap.image5,R.mipmap.image6,R.mipmap.image7,R.mipmap.image8,
R.mipmap.image9,R.mipmap.image10,R.mipmap.image11,R.mipmap.image12
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GridLayout layout = findViewById(R.id.layout);
for(int i = 0; i < imagePaths.length; i++) {
imgs[i] = new ImageView(MainActivity.this);
imgs[i].setImageResource(imagePaths[i]);
imgs[i].setPadding(2,2,2,2);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
400,
100);
imgs[i].setLayoutParams(params);
layout.addView(imgs[i]);
}
}
}
2.1.4 开发自定义的View
package com.example.myview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
public class RabbitView extends View {
public float bitmapX;
public float bitmapY;
public RabbitView(Context context) {
super(context);
bitmapX = 290;
bitmapY = 130;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
Bitmap bitmap = BitmapFactory.decodeResource(this.getResources(), R.mipmap.rabbit);
canvas.drawBitmap(bitmap, bitmapX, bitmapY, paint);
if(bitmap.isRecycled()) {
bitmap.recycle();
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/background"
tools:context=".MainActivity">
</FrameLayout>
package com.example.myview;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FrameLayout layout = findViewById(R.id.layout);
RabbitView rabbit = new RabbitView(this);
rabbit.setOnTouchListener(new View.OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event) {
rabbit.bitmapX = event.getX();
rabbit.bitmapY = event.getY();
rabbit.invalidate();
return true;
}
});
layout.addView(rabbit);
}
}
3 布局管理器
3.1什么是布局管理器
用于控制组件是如何摆放的。
3.2 有哪些常用的布局管理器
3.2.1 RelativeLayout
指定一个组件作为参考点,然后其他组件相对这个组件进行放置。
两个属性:
- android:gravity,设置子组件的摆放方式
- android:ignoreGravity,指定哪个组件可以不受第一个组件的影响
RelativeLayout.LayoutParams:
- android:layout_above、android:layout_below、android:layout_toLeftOf、android:layout_toRightOf。设置组件相对于某一组件的位置
- android:layout_alignParentBottom、android:layout_alignParentLeft、android:layout_alignParentRight、android:layout_alignParentTop。设置组件与父容器的哪一边对其,值均为布尔值。
- android:layout_alignBottom、android:layout_alignLeft、android:layout_alignRight、android:alignTop。边界对齐
- android:layout_centerHorizontal、android:layout_centerParent、android:layout_centerVertical。设置组件水平居中、中间位置、垂直居中
示例:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="@mipmap/bg"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:text="发现有Widget的新版本,您想现在就安装吗?" />
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="以后再说"
android:layout_below="@id/textView1"
android:layout_marginRight="10dp"
android:layout_alignRight="@id/textView1"/>
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="立即安装"
android:layout_below="@id/textView1"
android:layout_toLeftOf="@id/button1"
android:layout_marginRight="10dp"/>
</RelativeLayout>
3.2.2 LinearLayou
将组件按照纵向或横向进行排列
两个重要属性:
- android:oriention,表示方向
- android:gravity,设置组件内的安放位置
子组件的属性:
- android:layout_weight,组件占剩余空间的比例
示例:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center|top"
android:padding="16dp"
tools:context=".MainActivity">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="QQ号/微信号/手机号"
android:paddingBottom="10dp"
android:drawableLeft="@mipmap/zhanghao"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="密码"
android:paddingBottom="10dp"
android:drawableLeft="@mipmap/mima"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="登录"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:text="登录遇到问题?"/>
</LinearLayout>
3.2.3 FrameLayout
主要用于显示层叠的内容,以及拖动的动画效果。
最先放置的组件在最下面
两个重要是属性:
- android:foreground,为这个帧布局设置一个前景图像
- android:foregroundGravity,设置前景图像的位置
什么是前景图像?一个始终位于最上层的图像,其他图像无法覆盖它。
示例:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="@mipmap/foreground"
android:foregroundGravity="bottom|right"
tools:context=".MainActivity">
<TextView
android:layout_width="300dp"
android:layout_height="300dp"
android:background="#0000ff"
android:layout_gravity="center"
android:text="蓝色背景的正方形"/>
<TextView
android:layout_width="200dp"
android:layout_height="200dp"
android:background="#87CEEB"
android:layout_gravity="center"
android:text="天蓝色的正方形"/>
<TextView
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#1E90FF"
android:layout_gravity="center"
android:text="水蓝色的正方形"/>
</FrameLayout>
3.2.4 TableLayout
表格布局管理器,以行列的形式来管理放入其中的UI组件
<?xml version="1.0" encoding="utf-8"?>
<TableLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/biaoge"
android:stretchColumns="0,3"
tools:context=".MainActivity">
<TableRow
android:paddingTop="400dp">
<TextView/>
<TextView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="账 号:"
android:textSize="18sp"/>
<EditText
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:hint="邮箱或者手机号"/>
<TextView/>
</TableRow>
<TableRow>
<TextView/>
<TextView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="密 码:"
android:textSize="18sp"/>
<EditText
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:hint="输入6-16位数字或字母"/>
<TextView/>
</TableRow>
<TableRow>
<TextView/>
<Button
android:text="注册"/>
<Button
android:text="登录"/>
<TextView/>
</TableRow>
<TableRow>
<TextView/>
<TextView/>
<TextView
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:text="忘记密码?"
android:gravity="right"/>
<TextView/>
</TableRow>
</TableLayout>
3.2.5 GridLayout
与表格布局管理器相比,网格布局管理器可以跨列显示、跨行显示。
三个重要属性:
- columnCount:指定网格的最大列数
- orientation:指定排列顺序
- rowCount:指定网格的最大行数
GridLayout.LayoutParams:
- android:layout_column:指定子组件位于第几列
- android:layout_columnSpan:指定子组件跨几列
- android:layout_columnWeight:指定子组件在列上占剩余空间的权重
- android:gravity:指定子组件在网格内的位置
- android:layout_row:指定子组件位于第几行
- android:layout_rowSpan:指定子组件跨几行
- android:layout_rowWeight:指定子组件在行上占剩余空间的权重
示例:
<?xml version="1.0" encoding="utf-8"?>
<GridLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:columnCount="6"
android:rowCount="4"
android:background="@mipmap/bg"
tools:context=".MainActivity">
<ImageView
android:src="@mipmap/ico2"
android:layout_column="5"
android:layout_row="0"
android:layout_marginRight="10dp"/>
<ImageView
android:src="@mipmap/a1"
android:layout_column="1"
android:layout_row="0"
android:layout_columnSpan="4"
android:layout_gravity="right"/>
<ImageView
android:src="@mipmap/ico1"
android:layout_column="0"
android:layout_row="1"
android:layout_marginLeft="10dp"/>
<ImageView
android:src="@mipmap/b1"
android:layout_columnSpan="4"
android:layout_column="1"
android:layout_row="1"
android:layout_gravity="left"/>
<ImageView
android:src="@mipmap/ico2"
android:layout_column="5"
android:layout_row="2"
android:layout_marginRight="10dp"/>
<ImageView
android:src="@mipmap/a2"
android:layout_column="1"
android:layout_row="2"
android:layout_columnSpan="4"
android:layout_gravity="right"/>
<ImageView
android:src="@mipmap/ico1"
android:layout_column="0"
android:layout_row="3"
android:layout_marginLeft="10dp"/>
<ImageView
android:src="@mipmap/b2"
android:layout_columnSpan="4"
android:layout_column="1"
android:layout_row="3"
android:layout_gravity="left"/>
</GridLayout>
3.2.6 布局管理器的嵌套
几大原则:
- 根布局管理器必须包含xmlns属性
- 一个xml文件中,最多只能有一个根布局管理器
- 不能嵌套太深,否则影响性能