Android Studio提供了可视化的编辑器,实际开发中应该是直接运用更加直观,但本文博先对xml代码进行学习Android所自带的UI开发工具。
目录
Android常用的UI控件
TextView
Button
EditText
ImageView
ProgressBar
AlertDialog
ProgressDialog
控件的基本布局
LinearLayout(线性布局)
RelativeLayout(相对布局)
FrameLayout(帧布局)
百分比布局
ListView
ListView中点击事件
TextView可以说是Android中最简单的一个控件了。它主要用于在界面上显示一段文本信息。修改博文《Android学习笔记之——Android Studio的安装(3.6版本)、Java的基本语法及Android的概述 》中的hello world工程中的activity_main.xml代码:
//指定TextView中显示的文本内容
运行结果如下图所示
虽然指定的文本内容正常显示了,不过我们好像没看出来TextView的宽度是和屏幕一样宽的。其实这是由于TextView中的文字默认是居左上角对齐的,虽然TextView的宽度充满了整个屏幕,可是由于文字内容不够长,所以从效果上完全看不出来。接下来修改文字的对齐方式
使用android:gravity 来指定文字的对齐方式,可选值有top 、bottom 、left、right 、center。可以用“|”来同时指定多个值
除此之外,还可以对其字体的大小和颜色进行修改。
通过android:textSize 属性可以指定文字的大小,通过android:textColor 属性可以指定文字的颜色,在Android中字体大小使用sp作为单位
Button是程序用于和用户进行交互的一个重要控件,它可配置的属性和TextView是差不多的。
在布局文件里面设置的文字是“Button”,但最终的显示结果却是“BUTTON”。这是由于系统会对Button中的所有英文字母自动进行大写转换。可以使用如下配置来禁用这一默认特性
接下来我们可以在MainActivity中为Button的点击事件注册一个监听器,如下所示:
package com.example.demo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button= (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//在此处添加逻辑,这样按了按钮后,就会执行这个逻辑下的方法
}
});
}
}
EditText是程序用于和用户进行交互的另一个重要控件,它允许用户在控件里输入和编辑内容,并可以在程序中对这些内容进行处理。EditText的应用场景非常普遍,在进行发短信、发微博、聊QQ等操作时,都是使用EditText,修改activity_main.xml中的代码,如下所示:
《
至此,我们也可以总结出Android控件的使用规律了,用法基本上都很相似:给控件定义一个id,再指定控件的宽度和高度,然后再适当加入一些控件特有的属性就差不多了。
《
这里使用android:hint 属性指定了一段提示性的文本,然后重新运行程序
可以通过添加android:maxLines="2"。指定了EditText的最大行数为两行,这样当输入的内容超过两行时,文本就会向上滚动,而EditText则不会再继续拉伸。
接下来实现一个小功能为:通过点击button按钮,来获得输入的内容。修改MainActivity代码:
package com.example.demo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button= (Button) findViewById(R.id.button);
editText=(EditText) findViewById(R.id.editext); //得到EditText的实例
button.setOnClickListener(this);
}
@Override
public void onClick(View v) { //在按钮点击事件中调用getText() 方法
switch (v.getId()) {
case R.id.button:
String inputText = editText.getText().toString();//getText() 方法获取到输入的内容,再调用toString() 方法转换成字符串,
Toast.makeText(MainActivity.this, inputText,Toast.LENGTH_SHORT).show(); //Toast将输入的内容显示出来
break;
default:
break;
}
}
}
结果如下
ImageView是用于在界面上展示图片的一个控件,它可以让我们的程序界面变得更加丰富多彩。学习这个控件需要提前准备好一些图片,图片通常都是放在以“drawable”开头的目录下的。目前我们的项目中有一个空的drawable目录,不过由于这个目录没有指定具体的分辨率,所以一般不使用它来放置图片。这里我们在res目录下新建一个drawable-xhdpi目录,然后将事先准备好的两张图片img_1.png和img_2.png复制到该目录当中。接下来修改activity_main.xml,如下所示:
《
使用android:src 属性给ImageView指定了一张图片
还可以在程序中通过代码动态地更改ImageView中的图片,然后修改MainActivity的代码
package com.example.demo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private EditText editText;
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button= (Button) findViewById(R.id.button);
editText=(EditText) findViewById(R.id.editext); //得到EditText的实例
imageView=(ImageView) findViewById(R.id.image_view);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) { //在按钮点击事件中调用getText() 方法
switch (v.getId()) {
case R.id.button:
// String inputText = editText.getText().toString();//getText() 方法获取到输入的内容,再调用toString() 方法转换成字符串,
// Toast.makeText(MainActivity.this, inputText,Toast.LENGTH_SHORT).show(); //Toast将输入的内容显示出来
imageView.setImageResource(R.drawable.img_2);
break;
default:
break;
}
}
}
点击一下按钮就会变为其他照片了
ProgressBar用于在界面上显示一个进度条,表示我们的程序正在加载一些数据。它的用法也非常简单,修改activity_main.xml中的代码,如下所示:
《
mainactivity修改为:
package com.example.demo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private EditText editText;
private ImageView imageView;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button= (Button) findViewById(R.id.button);
editText=(EditText) findViewById(R.id.editext); //得到EditText的实例
// imageView=(ImageView) findViewById(R.id.image_view);
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) { //在按钮点击事件中调用getText() 方法
switch (v.getId()) {
case R.id.button:
// String inputText = editText.getText().toString();//getText() 方法获取到输入的内容,再调用toString() 方法转换成字符串,
// Toast.makeText(MainActivity.this, inputText,Toast.LENGTH_SHORT).show(); //Toast将输入的内容显示出来
// imageView.setImageResource(R.drawable.img_2);
// if (progressBar.getVisibility() == View.GONE) {
// progressBar.setVisibility(View.VISIBLE);
// } else {
// progressBar.setVisibility(View.GONE);
// }
int progress = progressBar.getProgress();
progress = progress + 10;
progressBar.setProgress(progress);
break;
default:
break;
}
}
}
AlertDialog可以在当前的界面弹出一个对话框,这个对话框是置顶于所有界面元素之上的,能够屏蔽掉其他控件的交互能力,因此AlertDialog一般都是用于提示一些非常重要的内容或者警告信息。比如为了防止用户误删重要内容,在删除前弹出一个确认对话框。修改MainActivity中的代码,如下所示:
package com.example.demo;
import androidx.appcompat.app.AppCompatActivity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private EditText editText;
private ImageView imageView;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button= (Button) findViewById(R.id.button);
editText=(EditText) findViewById(R.id.editext); //得到EditText的实例
// imageView=(ImageView) findViewById(R.id.image_view);
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) { //在按钮点击事件中调用getText() 方法
switch (v.getId()) {
case R.id.button:
//捕获文字
// String inputText = editText.getText().toString();//getText() 方法获取到输入的内容,再调用toString() 方法转换成字符串,
// Toast.makeText(MainActivity.this, inputText,Toast.LENGTH_SHORT).show(); //Toast将输入的内容显示出来
//改变显示的图片
// imageView.setImageResource(R.drawable.img_2);
////进度调
// if (progressBar.getVisibility() == View.GONE) {
// progressBar.setVisibility(View.VISIBLE);
// } else {
// progressBar.setVisibility(View.GONE);
// }
// int progress = progressBar.getProgress();
// progress = progress + 10;
// progressBar.setProgress(progress);
//警告框
//首先通过AlertDialog.Builder创建一个AlertDialog的实例
AlertDialog.Builder dialog = new AlertDialog.Builder (MainActivity.this);
dialog.setTitle("This is Dialog");//为这个对话框设置标题
dialog.setMessage("Something important.");//内容
dialog.setCancelable(false);//可否用Back键关闭对话框等属性
dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
//调用setPositiveButton() 方法为对话框设置确定按钮的点击事件
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
//调用setNegativeButton() 方法设置取消按钮的点击事件
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.show(); //将对话框显示出来
break;
default:
break;
}
}
}
ProgressDialog和AlertDialog有点类似,都可以在界面上弹出一个对话框,都能够屏蔽掉其他控件的交互能力。不同的是,ProgressDialog会在对话框中显示一个进度条,一般用于表示当前操作比较耗时,让用户耐心地等待。(这里就不作介绍了)
布局的内部除了放置控件外,也可以放置布局,通过多层布局的嵌套,我们就能够完成一些比较复杂的界面实现。
由于之前的demo中,都是通过android:orientation 属性指定了排列方向是vertical,所以所有的控件都是垂直方向排列的,如果改为horizontal,则控件会变为水平方向排列。首先将activity_main.xml中代码修改如下:
如下图所示
若改为垂直排列,则有
这里需要注意,如果LinearLayout的排列方向是horizontal,内部的控件就绝对不能将宽度指定为match_parent ,因为这样的话,单独一个控件就会将整个水平方向占满,其他的控件就没有可放置的位置了。同样的道理,如果LinearLayout的排列方向是vertical,内部的控件就不能将高度指定为match_parent 。
修改android:layout_gravity为bottom有:
接下来,我们看看android:layout_weight。这个属性允许我们使用比例的方式来指定控件的大小,它在手机屏幕的适配性方面可以起到非常重要的作用。比如我们需要编写一个消息发送界面,需要一个文本编辑框和一个发送按钮。修改activity_main.xml代码如下所示:
由于我们使用了android:layout_weight 属性,此时控件的宽度就不应该再由android:layout_width 来决定,这里指定成0dp是一种比较规范的写法。另外,dp是Android中用于指定控件大小、间距等属性的单位。
在EditText和Button里都将android:layout_weight 属性的值指定为1,这表示EditText和Button将在水平方向平分宽度。系统会先把LinearLayout下所有控件指定的layout_weight 值相加,得到一个总值,然后每个控件所占大小的比例就是用该控件的layout_weight 值除以刚才算出的总值。
它可以通过相对定位的方式让控件出现在布局的任何位置。(感觉Android开发有很多的函数和各种的设置,后面要买一本工具书专门查,而不是记着这么多的函数~~~)这部分就先跳过了,这里就不做测试了
这种布局没有方便的定位方式,所有的控件都会默认摆放在布局的左上角。
在这种布局中,我们可以不再使用wrap_content 、match_parent 等方式来指定控件的大小,而是允许直接指定控件在布局中所占的百分比,这样的话就可以轻松实现平分布局甚至是任意比例分割布局的效果了。对于简单的UI设计既简易,也不会太丑~
百分比布局定义在了support库当中,只需要在项目的build.gradle中添加百分比布局库的依赖,就能保证百分比布局在Android所有系统版本上的兼容性了。
打开app/build.gradle文件,在dependencies 闭包中添加如下内容:
implementation 'androidx.percentlayout:percentlayout:1.0.0'
需要注意的是,每当修改了任何gradle文件时,Android Studio都会弹出一个如下图所示的提示。只需要点击Sync Now就可以了
然后来修改activity_main.xml中的代码:
最外层使用了PercentFrameLayout,由于百分比布局并不是内置在系统SDK当中的,所以需要把完整的包路径写出来。然后还必须定义一个app的命名空间,这样才能使用百分比布局的自定义属性。
ListView允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕。首先修改activity_main.xml中的代码
将宽度和高度都设置为match_parent ,这样ListView也就占满了整个布局的空间。
然后修改MainActivity中的代码,如下所示:
package com.example.demo;
import androidx.appcompat.app.AppCompatActivity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Toast;
//public class MainActivity extends AppCompatActivity implements View.OnClickListener{
public class MainActivity extends AppCompatActivity {
private String[] data = { "Apple", "Banana", "Orange", "Watermelon",
"Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango",
"Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape",
"Pineapple", "Strawberry", "Cherry", "Mango" };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//数组中的数据是无法直接传递给ListView的,需要借助适配器来完成。
//定义一个适配器ArrayAdapter。
// 可以通过泛型来指定要适配的数据类型,然后在构造函数中把要适配的数据传入。
ArrayAdapter adapter = new ArrayAdapter(MainActivity.this, android.R.layout.simple_list_item_1, data);
//使用了android.R.layout.simple_list_item_1 作为ListView子项布局的id,
// 这是一个Android内置的布局文件,里面只有一个TextView,可用于简单地显示一段文本。
ListView listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(adapter);//调用ListView的setAdapter() 方法,将构建好的适配器对象传递进去
}
}
使用setOnItemClickListener() 方法为ListView注册了一个监听器,当用户点击了ListView中的任何一个子项时,就会回调onItemClick() 方法。在这个方法中可以通过position 参数判断出用户点击的是哪一个子项,然后获取到相应的水果,并通过Toast将水果的名字显示出来。
package com.example.demo;
import androidx.appcompat.app.AppCompatActivity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.Toast;
//public class MainActivity extends AppCompatActivity implements View.OnClickListener{
public class MainActivity extends AppCompatActivity {
private String[] data = { "Apple", "Banana", "Orange", "Watermelon",
"Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango",
"Apple", "Banana", "Orange", "Watermelon", "Pear", "Grape",
"Pineapple", "Strawberry", "Cherry", "Mango" };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//数组中的数据是无法直接传递给ListView的,需要借助适配器来完成。
//定义一个适配器ArrayAdapter。
// 可以通过泛型来指定要适配的数据类型,然后在构造函数中把要适配的数据传入。
ArrayAdapter adapter = new ArrayAdapter(MainActivity.this, android.R.layout.simple_list_item_1, data);
//使用了android.R.layout.simple_list_item_1 作为ListView子项布局的id,
// 这是一个Android内置的布局文件,里面只有一个TextView,可用于简单地显示一段文本。
ListView listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(adapter);//调用ListView的setAdapter() 方法,将构建好的适配器对象传递进去
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView parent, View view, int position, long id) {
Toast.makeText(MainActivity.this, data[position],Toast.LENGTH_SHORT).show();
}
});
}
}
除此以外,还有RecyclerView,可以说是一个增强版的ListView,不仅可以轻松实现和ListView同样的效果,还优化了ListView中存在的各种不足之处。在此就先不学习,等以后用到的时候再学吧哈~