视图基础

设置视图的宽高

通过Layout文件设置视图宽高

  • 视图宽度通过android:layout_width设置
  • 视图高度通过属性android:layout_height设置
  • 宽高的取值
    • match_parent和上级视图保持一致
    • wrap_content根据内容自适应
    • 以dp为单位的具体数值

AndroidStudio操作小技巧:ctrl+shift+f 可以格式化代码(或者ctrl+alt+l),调整代码缩进并把每行代码按字母排序

通过Activity文件设置视图宽高

  • 确保XML中的宽高属性为wrap_content
  • 调用控件对象的getLayoutParams方法获取该控件的布局参数
  • 布局参数的width属性表示宽度,height表示高度,修改这两个属性值即可改变控件的宽高
  • 调用控件对象的setLayoutParams方法,填入修改后的属性值使之生效(这里需要将dp转换为px)

新建util包,包中新建一个插件类用于将dp单位转换为px单位src\main\java\com\example\chapter03\util\DpConverter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.example.chapter03.util;

import android.content.Context;

public class DpConverter {
/**
* 根据屏幕的分辨率将dp单位转换为px单位
* @param context
* @param dpvalue
* @return
*/
public static int dip2px(Context context, float dpvalue){
//获取当前设备像素密度(1dp对应的px)
float scale = context.getResources().getDisplayMetrics().density;
return (int)(dpvalue * scale + 0.5f);
}
}

在Activity文件内调用方法,并修改控件的布局属性\src\main\java\com\example\chapter03\ViewBorderActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ViewBorderActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_border);
TextView tv_code_layout = findViewById(R.id.tv_code_layout);
//获取控件布局参数
ViewGroup.LayoutParams params = tv_code_layout.getLayoutParams();
//修改宽度,这里使用px作为单位,需要提前将dp转为px
params.width = DpConverter.dip2px(this, 250);
//设置布局参数
tv_code_layout.setLayoutParams(params);
}
}

设置视图的间距

  • layout_margin属性指定当前视图与平级视图和父级视图之间的距离。包括layout_marginLeftlayout_marginToplayout_marginRightlayout_marginBottom
  • padding属性指定当前视图与内部下级视图之间的距离。包括paddingLeftpaddingToppaddingRightpaddingBottom
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?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="300dp"
android:orientation="vertical"
android:background="@color/teal_200">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="20dp"
android:background="@color/purple_200"
android:padding="50dp">

<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/teal_700"/>

</LinearLayout>

</LinearLayout>

设置视图的对齐方式

Layout文件设置视图对齐的两种方式

  • layout_gravity属性,设置当前视图相对于上级视图的对齐方式。
  • gravity属性,设置下级视图相对于当前视图的对齐方式。

layout_gravity属性的取值包括:top、bottom、center。

gravity属性的取值包括:top、bottom、start(从左到右)、end(从右到左)

如果需要左下、右上诸如此类的布局,可以将当前元素设置layout_gravity的值为top或bottom,父元素的gravity设置为start或end

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="@color/teal_200"
android:orientation="horizontal">

<LinearLayout
android:layout_width="0dp"
android:layout_height="200dp"
android:layout_weight="1"
android:layout_gravity="top"
android:gravity="end"
android:background="@color/purple_200">

<View
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="bottom"
android:background="@color/purple_500"/>

</LinearLayout>

<LinearLayout
android:layout_width="0dp"
android:layout_height="200dp"
android:layout_weight="1"
android:layout_gravity="bottom"
android:background="@color/purple_200">
<View
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="top"
android:background="@color/purple_500"/>
</LinearLayout>

</LinearLayout>

常用布局

线性布局LinearLayout

线性布局内部视图有两种排列方式

  • android:orientation="vertical"内部视图按垂直方向从上到下排列
  • android:orientation="horizontal"内部视图按水平方向从左到右排列(可以使用gravity属性更改内部视图排列)
线性布局的权重

线性布局的权重指的是线性布局的下级视图各自拥有多大比例的宽高

使用layout_weight设置权重,但该属性不在LinearLayout节点设置,而在线性布局的子视图设置,表示该子视图占据父视图宽高的比例。

  • 当前视图layout_width设置为0,当前视图layout_weight表示水平方向的宽度比例
  • 当前视图layout_height设置为0,当前视图layout_weight表示垂直方向的高度比例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="第一个权重1"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="第二个权重1"/>
</LinearLayout>

相对布局RelativeLayout

相对布局的下级视图位置由其他视图决定。用于确定下级视图位置的参照视图分为两种:

  • 与该视图平级的视图
  • 该视图的父级视图(包含它的RelativeLayout)

如果不设置下级视图的参照视图,那么下级视图默认显示在RelativeLayout内部的左上角

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="150dp">
<TextView
android:id="@+id/tv_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@color/teal_200"
android:text="垂直水平居中"
android:textSize="11sp"
android:textColor="@color/black"/>

<TextView
android:id="@+id/tv_enter_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:background="@color/teal_200"
android:text="水平居中"
android:textSize="11sp"
android:textColor="@color/black"/>

<TextView
android:id="@+id/tv_enter_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:background="@color/teal_200"
android:text="垂直居中"
android:textSize="11sp"
android:textColor="@color/black"/>

<TextView
android:id="@+id/tv_align_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="@color/teal_200"
android:text="相对父元素右对齐"
android:textColor="@color/black"
android:textSize="11sp" />

<TextView
android:id="@+id/tv_align_view_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/tv_center"
android:layout_alignBottom="@id/tv_center"
android:layout_marginLeft="10dp"
android:background="@color/teal_200"
android:text="相对中间元素右、底部对齐"
android:textColor="@color/black"
android:textSize="11sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_center"
android:layout_alignLeft="@id/tv_center"
android:layout_marginTop="10dp"
android:text="在中间元素下面,左对齐"
android:textColor="@color/black"
android:textSize="11sp" />

</RelativeLayout>

网格布局GridLayout

网格布局支持多行多列的表格排列。

网格布局默认从左往右、从上到下排列,它新增了两个属性:

  • columnCount属性,它指定了网格的列数,即每行能放多少个视图
  • rowCount属性,它指定了网格的行数,即每列能放多少个视图。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnCount="2"
android:rowCount="2">
<TextView
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_columnWeight="1"
android:background="@color/teal_200"
android:text="文字1"
android:gravity="center"
android:textColor="@color/black"
android:textSize="17sp"/>
<TextView
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_columnWeight="1"
android:background="@color/purple_200"
android:textColor="@color/black"
android:gravity="center"
android:text="文字2"
android:textSize="17sp"/>
<TextView
android:layout_width="80dp"
android:layout_height="60dp"
android:layout_columnWeight="1"
android:background="@color/teal_700"
android:gravity="center"
android:text="文字3"
android:textColor="@color/black"
android:textSize="17sp"/>
<TextView
android:layout_width="80dp"
android:layout_height="60dp"
android:layout_columnWeight="1"
android:background="@color/purple_500"
android:gravity="center"
android:textColor="@color/black"
android:text="文字4"
android:textSize="17sp"/>
</GridLayout>

滚动视图ScrolView

滚动视图有两种

  • ScrollView:它是垂直方向的滚动视图;垂直方向滚动,layout_width属性值设置为match_parentlayout_height属性值设置wrap_content
  • HorizontalScrollView:它是水平方向的滚动视图;水平方向滚动时,layout_width属性值设置为wrap_contentlayout_height属性值设置为match_parent
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="200dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal">
<View
android:layout_width="300dp"
android:layout_height="match_parent"
android:background="@color/purple_200"/>

<View
android:layout_width="300dp"
android:layout_height="match_parent"
android:background="@color/teal_700"/>
</LinearLayout>
</HorizontalScrollView>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="500dp"
android:background="@color/purple_200"/>

<View
android:layout_width="match_parent"
android:layout_height="500dp"
android:background="@color/teal_700"/>
</LinearLayout>
</ScrollView>
</LinearLayout>

按钮

按钮控件Button由TextView派生而来,它们之间的区别有:

  • Button拥有默认的按钮背景,而TextView默认无背景
  • Button的内部文本默认居中对齐,而TextView的内部文本
  • Button会默认将英文字母转为大写,而TextView保持原始的英文大小写

与TextView相比,Button增加了两个新属性

  • textAllCaps属性,是否将所有英文字母转为大写,默认为true
  • onClik属性,指定点击事件产生时调用哪个方法

\src\main\res\layout\activity_button_style.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="点击事件处理"
android:textColor="@color/black"
android:textAllCaps="false"
android:textSize="17sp"
android:onClick="doClick"/>
<TextView
android:id="@+id/tv_event_target"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="点击按钮改变"
android:textColor="@color/black"
android:textSize="17sp"/>
</LinearLayout>

\src\main\java\com\example\chapter03\ButtonStyleActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class ButtonStyleActivity extends AppCompatActivity {

private TextView tv_event_target;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_button_style);
tv_event_target = findViewById(R.id.tv_event_target);
}
public void doClick(View view){
String desc = String.format("%s 您点击了按钮: %s",DateUtil.getNowTime(),((Button)view).getText());
tv_event_target.setText(desc);
}
}

\src\main\res\layout\activity_button_style.xml

1
2
3
4
5
6
public class DateUtil {
public static String getNowTime(){
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
return sdf.format(new Date());
}
}

点击事件

监听器专门用于监听控件的动作行为,只有控件发生了指定的动作,监听器才会触发并执行对应的代码逻辑。

按钮控件有两种常用的监听器:

  • 点击监听器,通过setOnClickListener方法设置。按键被按住少于500毫秒
  • 长按监听器,通过setOnLongClickListener方法设置。按键按住超过500毫秒时,会触发长按事件。

\src\main\java\com\example\chapter03\ButtonClickActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class ButtonClickActivity extends AppCompatActivity implements View.OnClickListener{

private TextView tv_btn_click;

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

Button btn_click = findViewById(R.id.btn_click);
Button btn_click_public = findViewById(R.id.btn_click_public);
tv_btn_click = findViewById(R.id.tv_btn_click);
//MyOnClickListener是自定义的监听器,它实现了View.OnClickListener这个接口
btn_click.setOnClickListener(new MyOnClickListener(tv_btn_click));
//当前类需要实现View.OnClickListener这个接口才能使用this作为监听器
btn_click_public.setOnClickListener(this);
}

/*公共点击事件处理方法(多个控件公用一个事件处理方法)*/
@Override
public void onClick(View view) {
if (view.getId() == R.id.btn_click_public){
tv_btn_click.setText("公共点击事件处理");
}
}
/*自定义监听器*/
static class MyOnClickListener implements View.OnClickListener {
private final TextView tv_btn_click;
public MyOnClickListener(TextView tv_btn_click) {
this.tv_btn_click = tv_btn_click;
}
@Override
public void onClick(View view) {
//调用自定义类DateUtil中的方法获取当前时间字符串
String desc = String.format("%s", DateUtil.getNowTime());
tv_btn_click.setText(desc);
}
}
}

长按点击事件

  • 长按监听器,通过setOnLongClickListener方法设置。按键按住超过500毫秒时,会触发长按事件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ButtonLongActivity extends AppCompatActivity {

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

TextView tv_long_click = findViewById(R.id.tv_long_click);
Button long_click = findViewById(R.id.long_click);
long_click.setOnLongClickListener(view -> {
String str = DateUtil.getNowTime();
tv_long_click.setText(str);
return true;
});
}
}

禁用和恢复按钮

按钮有可用状态和不可用状态,它们在外观和功能上区别如下:

  • 不可用按钮:按钮不允许点击,不会产生点击事件,按钮文字为灰色。
  • 可用按钮:按钮允许点击,产生点击事件,按钮文字为黑色。

\src\main\java\com\example\chapter03\ButtonEnableActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class ButtonEnableActivity extends AppCompatActivity implements View.OnClickListener {

private TextView tv_test_click;
private Button btn_test;

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

btn_test = findViewById(R.id.btn_test);//获取测试按钮视图对象
Button enable_click = findViewById(R.id.enable_click);//获取启用按钮视图对象
Button disable_click = findViewById(R.id.disable_click);//获取禁用按钮视图对象
tv_test_click = findViewById(R.id.tv_test_click);

enable_click.setOnClickListener(this);
disable_click.setOnClickListener(this);
btn_test.setOnClickListener(this);
}

//公共点击事件处理方法(类需要实现View.OnClickListener接口)
@Override
public void onClick(View view) {
if (view.getId() == R.id.enable_click){
btn_test.setEnabled(true);
}else if (view.getId() == R.id.disable_click){
btn_test.setEnabled(false);
}else{
tv_test_click.setText(DateUtil.getNowTime());
}
}
}