一、UI的定义 Android提供了一系列UI,这些UI可以为我们的界面提供布局和控件,使我们的界面变得美观、合理 二、常见的UI控件
- 2.1 TextView
作用:主要用于在界面上显示一段文本信息 TextView常见属性使用:
<TextView
android:id="@+id/text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This is TextView"
android:gravity="center"
android:textSize="24sp"
android:textColor="#00ff00"
/>
在Android的UI控件中,match_parent和fill_parent表示让当前控件的大小和父布局的大小一样;wrap_content表示让当前控件的大小能够刚好包含住里面的内容
- 2.2 Button
- 作用:表示在界面上显示一个按钮,常见的属性使用如下:
<Button
android:id="@+id/button_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button 1"
android:textAllCaps="false"
/>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button)findViewById(R.id.button_1);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
}
(二)实现接口的方式注册: 1、继承View.OnClickListener接口 2、重写onClick(View v) 方法
public class MainActivity<onClick> extends AppCompatActivity implements View.OnClickListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button)findViewById(R.id.button_1);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button_1:
break;
default:
break;
}
}
}
- 2.3 EditText
作用:允许用户在控件里输入和编辑内容,并可以在程序中对这些内容进行处理
<EditText
android:id="@+id/edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Type something here"
android:maxLines="2"
/>
我们还可以结合使用EditText和Button来完成一些功能,比如通过点击按钮来获取EditText中输入的内容
private EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button)findViewById(R.id.button_1);
editText = (EditText)findViewById(R.id.edit_text);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button_1:
String inputText = editText.getText().toString();
Toast.makeText(MainActivity.this,inputText,Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
- 2.4 ImageView
作用:适用于在界面上展示图片的一个控件,他可以使得程序界面变得更加丰富多彩。注意,图片一般都是放在drawable文件下的
<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/img_1"
/>
我们还可以通过点击按钮来更换图片
private ImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button)findViewById(R.id.button_1);
imageView = (ImageView) findViewById(R.id.image_view);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button_1:
imageView.setImageResource(R.drawable.img_2);
break;
default:
break;
}
}
- 2.5 ProgressBar
(一)作用:用于在界面上显示一个进度条,表示我们的程序正在加载一些数据,代码如下:
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
(二)当数据加载完成时,如何让进度条消失?
- 1、Android控件的可见属性:所有的控件可以通过android:visibility进行指定,其中选定的值有三种:visible、invisible、gone;①visible表示控件是可见的;②invisible表示控件不可见,但是仍然占据着原来的位置的大小;③gone表示控件不仅不可见,而且不再占用任何屏幕空间
- 2、通过代码来设置控件的可见性,使用的是setVisibility()方法,可以传入View.VISIBLE、View.INVISIBLE、View.GONE这三种值
实现代码:
public class MainActivity<onClick> extends AppCompatActivity implements View.OnClickListener{
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button)findViewById(R.id.button_1);
progressBar = (ProgressBar)findViewById(R.id.progress_bar);
button.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button_1:
if(progressBar.getVisibility() == View.GONE){
progressBar.setVisibility(View.VISIBLE);
}else{
progressBar.setVisibility(View.GONE);
}
break;
default:
break;
}
}
}
(三)给ProgressBar控件指定不同的样式,默认为圆形进度条
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
/>
- 2.6 AlertDialog
作用:在当前得界面弹出一个对话框,该对话框置顶于所有界面元素之上的,能够屏蔽掉其他控件得交互能力,因此AlertDialog一般都是用于提示一些非常重要的内容或着警告信息,示例代码如下:
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button_1:
AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
dialog.setTitle("This is a dialog");
dialog.setMessage("Something important.");
dialog.setCancelable(false);
dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.show();
break;
default:
break;
}
}
- 2.7 ProgressDialog
作用:跟ProgressDialog类似,弹出一个对话框,能够屏蔽掉其他控件的交互能力。不同的是,ProgressDialog会在对话框中显示一个进度条,一般用于表示当前操作比较耗时,让用户耐心地等待
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button_1:
ProgressDialog progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setTitle("This is a dialog");
progressDialog.setMessage("loading.....");
progressDialog.setCancelable(false);
progressDialog.show();
break;
default:
break;
}
}
注意:如果数据或者操作执行完成,需要通过调用dismiss()方法来关闭对话框,否则该控件会一直存在
- 2.8 ListView
作用:该控件允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚出屏幕
- 2.8.1 定制ListView的界面
以定制一个球星姓名的列表为例: 1、由于ListView这一控件是由一个个item组成,因此我们首先需要定义一个实体bean类。类中的数据成员包含着每一个item所要展示的元素。这个实体类还是作为ListView适配器的适配类型。代码如下图所示:
public class soccerName {
private String name;
public soccerName(String name){
this.name = name;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
}
2、然后需要为ListView的子项指定一个我们自定义的布局,在layout目录下新建name_item.xml,代码如下图所示:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="100px"
android:gravity="center"
android:layout_margin="10px"
/>
</LinearLayout>
3、接下来创建一个自定义的适配器,该适配器能将我们要展示的数据传入到ListView控件当中。这里我们适配器要继承自ArrayAdapter,并将泛型指定为类。新建一个FruitAdapter类,代码如下:
public class SoccerAdapter extends ArrayAdapter<Soccer> {
private int resourceId;
public SoccerAdapter(@NonNull Context context, int resource, int textViewResourceId, @NonNull List<Soccer> objects) {
super(context, resource, textViewResourceId, objects);
resourceId = textViewResourceId;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Soccer soccer = getItem(position);
View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
TextView name = view.findViewById(R.id.name);
name.setText(soccer.getName());
return view;
}
}
4、在我们要引用ListView的布局文件中添加ListView这个控件
<ListView
android:id="@+id/list_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="MissingConstraints" />
5、最后在java中的代码如下:
private List<Soccer> soccerList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initName();
SoccerAdapter soccerAdapter = new SoccerAdapter(MainActivity.this,R.layout.name_item,soccerList);
ListView listView = findViewById(R.id.list_name);
listView.setAdapter(soccerAdapter);
}
public void initName(){
for(int i=0;i<2;i++){
Soccer name1 = new Soccer("c罗");
soccerList.add(name1);
Soccer name2 = new Soccer("本泽马");
soccerList.add(name2);
Soccer name3 = new Soccer("贝尔");
soccerList.add(name3);
Soccer name4 = new Soccer("莫德里奇");
soccerList.add(name4);
Soccer name5 = new Soccer("卡塞米罗");
soccerList.add(name5);
Soccer name6 = new Soccer("克罗斯");
soccerList.add(name6);
Soccer name7 = new Soccer("马塞洛");
soccerList.add(name7);
Soccer name8 = new Soccer("拉莫斯");
soccerList.add(name8);
Soccer name9 = new Soccer("瓦拉内");
soccerList.add(name9);
Soccer name10 = new Soccer("卡瓦哈尔");
soccerList.add(name10);
Soccer name11 = new Soccer("纳瓦斯");
soccerList.add(name11);
Soccer name12 = new Soccer("齐达内");
soccerList.add(name12);
}
}
结果如下: 
- 2.8.2 提升ListView 的运行效率
- (一)在正常情况下getView()方法中,每次都会将布局重新加载一边,而当ListView快速滚动时,这就会成为性能的瓶颈。而getView()方法中convertView参数,用于将之前加载好的布局进行缓存,便于之后进行重新使用。以下是优化方法:
Soccer soccer = getItem(position);
View view;
if(convertView == null)
view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
else
view = convertView;
TextView name = view.findViewById(R.id.name);
name.setText(soccer.getName());
return view;
- (二)解决重复加载布局之后,我们还发现现在getView()方法每加载一次都会调用view.findById()方法获取一次控件的实例,以下是优化方法:
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Soccer soccer = getItem(position);
View view;
ViewHolder viewHolder;
if(convertView == null) {
view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
viewHolder = new ViewHolder();
viewHolder.name = view.findViewById(R.id.name);
view.setTag(viewHolder);
}else {
view = convertView;
viewHolder = (ViewHolder) view.getTag();
}
viewHolder.name.setText(soccer.getName());
return view;
}
class ViewHolder{
TextView name;
}
我们定义了一个ViewHolder的内部类,用于存放所需要实例化控件。第一次加载布局时,实例化控件并且通过调用View对象的setTag()方法将ViewHolder的对象存入到view的Tag当中;再次加载布局时,调用getTag()方法找回实例化的控件
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initName();
SoccerAdapter soccerAdapter = new SoccerAdapter(MainActivity.this,R.layout.name_item,soccerList);
ListView listView = findViewById(R.id.list_name);
listView.setAdapter(soccerAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Soccer soccer = soccerList.get(position);
Toast.makeText(MainActivity.this,soccer.getName(),Toast.LENGTH_LONG).show();
}
});
}
使用setOnItenClickListener()方法为ListView注册了一个监听器,当用户点击了ListView中的任何一个子项时,都会回调onItemClick()方法,在该方法中通过判断用户点击了哪一个子项然后获取到相应的名字,并通过Toast将水果名字显现出来
- 2.9 RecyclerView
RecyclerView控件是ListView的增强版,不仅可以轻松实现和ListView同样的效果,还优化了ListView中存在的不足之处
- 2.9.1 RecyclerView用法
1、导入RecyclerView的依赖 implementation 'com.android.support:recyclerview-v7:28.0.0' 2、同ListView一样,创建一个实体Bean类,并且为子项定义一个布局文件 3、在我们想要的布局文件中加入RecyclerView控件,代码如下:
<android.support.v7.widget.RecyclerView
android:id="@+id/list_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints" />
4、自定义适配器
public class SoccerAdapter extends RecyclerView.Adapter<SoccerAdapter.ViewHolder> {
private List<Soccer> soccerList;
static class ViewHolder extends RecyclerView.ViewHolder{
TextView name;
public ViewHolder(@NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.name);
}
}
public SoccerAdapter(List<Soccer> soccerList){
this.soccerList = soccerList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.name_item,parent,false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Soccer soccer = soccerList.get(position);
holder.name.setText(soccer.getName());
}
@Override
public int getItemCount() {
return soccerList.size();
}
}
1、首先我们定义了一个内部类ViewHolder,并让他继承RecyclerView.ViewHolder类
2、然后在构造函数中传入一个View参数,这个参数通常就是RecyclerView子项的最外层布局
3、获取控件的实例
4、SoccerAdapter类中的构造函数用于把要展示的数据源传进来,并赋予给一个全局变量List集合,以便于后续调用
5、三个被重写的方法中第一个方法用于创建ViewHolder的实例
6、第二个方法用于对RecyclerView的子项的数据源进行赋值
7、第三个返回数据源长度
8、该适配器要继承自 RecyclerView.Adapter 并且 泛型指定为 SoccerAdapter.ViewHolder
5、修改MainActivity中的代码:
public class MainActivity extends AppCompatActivity {
List<Soccer> soccerList = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initName();
RecyclerView recyclerView = findViewById(R.id.list_name);
LinearLayoutManager linearLayout = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayout);
SoccerAdapter soccerAdapter = new SoccerAdapter(soccerList);
recyclerView.setAdapter(soccerAdapter);
}
public void initName() {
.......
}
}
1、在onCreate()方法中我们先获取到RecyclerView的实例
2、然后创建了一个LinearLayoutManager对象,并将他设置到RecyclerView当中
3、LayoutManager用于指定RecyclerView的布局方式,这里指定的时线性布局的方式,此外还有滚动和瀑布流布局
4、创建SoccerAdapter实例,并将数据传入到其构造函数当中
5、调用recyclerView的setAdapter()方法完成适配器的设置
- 2.9.2 实现横向滚动和瀑布流布局
(一)如何实现横向滚动?
- 1、首先要对子项布局进行修改,将子项里的元素的排列方式改成垂直排列,并且设置布局的宽度
- 2、接下来我们修改MainActivity中的代码,改变布局排列方向,在声明了LinearLayoutManager对象后加入如下代码
linearLayout.setOrientation(LinearLayoutManager.HORIZONTAL);
StaggeredGridLayoutManager gridLayoutManager = new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
其中,第一个参数 3 表示是列数,第二个参数表示排列方式,上面是垂直排列
- 2.9.3 RecyclerView的点击事件
与ListView不同的是,RecyclerView需要自己给子项具体的View去注册点击事件,注册方法如下:
static class ViewHolder extends RecyclerView.ViewHolder{
View soccerView;
TextView name;
public ViewHolder(@NonNull View itemView) {
super(itemView);
soccerView = itemView;
name = itemView.findViewById(R.id.name);
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.name_item,parent,false);
final ViewHolder viewHolder = new ViewHolder(view);
viewHolder.soccerView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
return viewHolder;
}
1、在ViewHolder添加一个soccerView变量用于保存子项最外层布局的实例
2、然后在onCreateViewHolder()方法中声明一个final类型的ViewHolder实例,然后注册监听器
3、RecyclerView点击事件优势:可以为整个子项注册监听器,如上述代码的soccerView,也可以为子项中的单个元素注册监听器,如直接把上面代码的 soccerView 更改成 name,即为TextView元素注册了一个监听器
三、创建自定义控件
- 3.1 常用控件和布局的继承结构
 1、所有的控件都是直接或间接继承自View的 2、所有的布局都是直接或间接继承自ViewGroup的 3、View是Android中最基本的一种UI组件,它在在屏幕上绘制一块矩形区域,并能够响应这块区域的各种事件。 4、ViewGroup是一种特殊的View,他可以包含很多子View和子ViewGroup,是一个用于放置控件和布局的容器 - 3.2 引入自定义布局
作用:我们可以只创建一个通用格式的布局,然后在其他的活动中调用此布局文件,这样就避免频繁的重复的操作控件 举例:创建如下的导航栏  1、在layout包下创建一个布局文件title.xml,然后添加控件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/title_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="Back"
android:textColor="#00ff66" />
<TextView
android:id="@+id/title_text"
android:layout_width="0dp"
android:layout_height="58dp"
android:layout_weight="1"
android:gravity="center"
android:text="Title Text"
android:textColor="#00ff66"
android:textSize="24sp" />
<Button
android:id="@+id/title_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:text="Edit"
android:textColor="#00ff66" />
</LinearLayout>
2、引用该文件的方法:
<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"
tools:context=".MainActivity">
<include layout="@layout/title"/>
</LinearLayout>
在include中,引号里的格式:“@包名/布局文件名” 3、java文件中,修改代码,将系统自带的标题栏隐藏掉
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null){
actionBar.hide();
}
}
- 3.3 创建自定义控件
作用:对自己已经创建好的控件进行操作设置,比如上面的自定义的布局中的Back键,Back键的目的就是销毁该活动,我们可以通过自定义Back的控件,使得每一个自定义的布局中Back键执行的情况都是相同,这样就避免在每一个活动中都需要重新注册一遍返回按钮的点击事件。 1、新建一个类,继承LinearLayout类,让他成为我们自定义的标题栏控件
public class TitleLayout extends LinearLayout {
public TitleLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.title,this);
}
}
LayoutInflater的from()方法创建了一个LayoutInflater对象,调用inflate()方法以动态加载一个布局文件,传入的第一个参数就要加载的布局文件的id,第二个参数就是给加载好的布局再添加一个父布局
2、在我们想要引用该控件的布局文件中中添加自定义控件代码:
<com.example.uicustomviews.TitleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
3、然后再在回到java代码中为按钮注册点击事件
public class TitleLayout extends LinearLayout {
public TitleLayout(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.title,this);
Button titleback = (Button)findViewById(R.id.title_back);
Button titleEdit = (Button)findViewById(R.id.title_edit);
titleback.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
((Activity)getContext()).finish();
}
});
titleEdit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getContext(),"Editing",Toast.LENGTH_SHORT).show();
}
});
}
}
四、 小结 1、本节讲了七种常见控件及其使用方法
- TextView——主要用于在界面上显示一段文本信息
- Button——表示在界面上显示一个按钮,有两种注册监听器的方法
- EditText——允许用户在控件里输入和编辑内容,并可以在程序中对这些内容进行处理
- ImageView——适用于在界面上展示图片的一个控件,他可以使得程序界面变得更加丰富多彩
- ProgressBar——用于在界面上显示一个进度条,表示我们的程序正在加载一些数据
- AlertDialog——可以在当前得界面弹出一个对话框,该对话框置顶于所有界面元素之上的,能够屏蔽掉其他控件得交互能力,因此AlertDialog一般都是用于提示一些非常重要的内容或着警告信息
- ProgressDialog——跟ProgressDialog类似,弹出一个对话框,能够屏蔽掉其他控件的交互能力。不同的是, ProgressDialog会在对话框中显示一个进度条,一般用于表示当前操作比较耗时,让用户耐心地等待
- ListView以及优化方法和点击事件
- 以及横向滚动和瀑布流布局和点击事件
2、引用自定义布局 3、创建自定义控件
|