3.2常见控件的使用
3.2.1TextView
3.2.2Button
<Button
android:id="@+id/button_on"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button"
android:textAllCaps="false"/>
textAllCaps属性,系统会对Button中所有英文字母转换为大写,false会显示原来的字符
3.2.3EditText
<EditText
android:id="@+id/edittext_on"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="This is EditText"
android:maxLines="3"/>
hint属性会给输入框一个提示性文本,当输入时就会消失
maxLines属性会限制显示最多行数
edittext_on = (EditText)findViewById(R.id.edittext_on);
String edittext = edittext_on.getText().toString();
将EditText中输入内容取出转化为字符串
3.2.4ImageView
布局文件中:
<ImageView
android:id="@+id/imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"/>
src引用图片
代码中:
设置为另一张图片
image.setImageResource(R.mipmap.ic_launcher_round);
3.2.5ProgressBar
用于界面上先是一个进度条,使用比较简单:
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Base.Widget.AppCompat.ProgressBar.Horizontal"/>
3.2.6AlertDialog
AlertDialog是在当前界面弹出一个对话框,置顶于所有界面元素之上,一般用于警告会非常重要的内容:
AlertDialog.Builder dialog = new AlertDialog.Builder(NormalActivity.this);
dialog.setTitle("关机");
dialog.setMessage("您确定要关机吗?");
dialog.setCancelable(false);
dialog.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(NormalActivity.this,"本机将在3秒后关机",Toast.LENGTH_SHORT).show();
}
});
dialog.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Toast.makeText(NormalActivity.this,"取消",Toast.LENGTH_SHORT).show();
}
});
dialog.show();
dialog.setCancelable(false);
setCancelable属性值为true时,点击AlertDialog以外区域时AlertDialog会被dismiss掉,setPositiveButton()是对话框设置确定按钮点击事件,setNegativeButton()是对话框设置取消按钮点击事件,show()是将对话框显示出来。
3.2.7ProgressDialog
与AlertDialog类似,弹出的是一个进度条,一般用于耗时操作;
ProgressDialog progress =new ProgressDialog(NormalActivity.this);
progress.setTitle("稍等");
progress.setMessage("等待");
progress.setCancelable(true);
progress.show();
如果setCancelable传入false,表示不能被取消,一定要控制,当数据加载完毕后,调用其dismiss()关闭。
3.5.2ListView
定制的ListView的界面
首先定义一个实体类,作ListView的适配器的适配类型:
public class Fruit {
private String name;
private int imageid;
public Fruit(String name , int imageid){
this.name = name;
this.imageid = imageid;
}
public String getName() {
return name;
}
public int getImageid() {
return imageid;
}
}
然后指定ListView子项的自定义布局,在layout中新建fruit_item.xml
<?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="wrap_content">
<ImageView
android:id="@+id/item_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"/>
<TextView
android:id="@+id/item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:text="名字"
android:layout_gravity="center_vertical"/>
</LinearLayout>
接下来创建自定义适配器,继承自ArrayAdapter,泛型指定为Furit类,新建FuritAdapter:
package co.example.hanwei.listviewtest;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
/**
* Created by hanwei on 2018/8/10 0010.
*/
public class FruitAdapter extends ArrayAdapter<Fruit>{
private int resourceid;
public FruitAdapter(Context context, int textviewResourceId, List<Fruit> Objects){/*重写的父类的一个构造函数*/
super(context,textviewResourceId,Objects);/*三个参数分别代表:上下文,ListView子项布局的id,和数据*/
resourceid = textviewResourceId;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {/*重写gteView(),这个方法在没个子项被滚动到屏幕时候调用*/
Fruit fruit = getItem(position);/*首先调用getItem()得到当前实例的Fruit实例*/
View view = LayoutInflater.from(getContext()).inflate(resourceid,parent,false);/*用LyoutInFlater来为这个子项加载我们传入的布局*/
ImageView fruit_image_id = (ImageView) view.findViewById(R.id.item_image); /*其中三个参数:ListView子项布局的id,当前视图的父级视图,*/
TextView fruit_name_id = (TextView) view.findViewById(R.id.item_name); /*雕鹰view获取ImageView和TextView的实例*/
fruit_image_id.setImageResource(fruit.getImageid()); /*调用setImageResource和setText来设置显示的图片和文字*/
fruit_name_id.setText(fruit.getName()); /*最后将布局返回*/
return view;
}
}
下面修改MainActivity中的代码:
package co.example.hanwei.listviewtest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<Fruit> furitlist = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruit();/*初始化所有水果数据*/
FruitAdapter adapter = new FruitAdapter(MainActivity.this,R.layout.fruit_item,furitlist);/*创建FruitAdapter适配器对象,传入上下文,自定义布局,要显示的数据*/
ListView fruit_listview = (ListView)findViewById(R.id.fruit_listview);
fruit_listview.setAdapter(adapter);/*将adapter作为适配器传递给ListView*/
}
public void initFruit(){
for(int i = 0;i < 10 ;i ++){
Fruit banana = new Fruit("Banana",R.mipmap.ic_launcher);/*在Fruit类的构造函数中将对应的水果名字和对应说过图片的id传入*/
furitlist.add(banana); /*将创建好的对象添加到水果列表中*/
Fruit apple = new Fruit("apple",R.mipmap.ic_launcher);
furitlist.add(apple);
Fruit orange = new Fruit("orange",R.mipmap.ic_launcher);
furitlist.add(orange);
Fruit pear = new Fruit("pear",R.mipmap.ic_launcher);
furitlist.add(pear);
Fruit cherry = new Fruit("cherry",R.mipmap.ic_launcher);
furitlist.add(cherry);
}
}
}
定制比较简单。
3.5.3提升ListView的运行效率
ListView运行效率很低,我们用一些方法来提高:getView()中有一个ConverView参数,用于将之前加载好的布局进行缓存,以后便可以复用。
每次还会调用View的findViewById()来获取一次控件的实例,借助ViewHolder进行优化。
package com.example.administrator.listviewtest;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
/**
* Created by Administrator on 2018/8/12.
*/
public class FruitAdapter extends ArrayAdapter<Fruit>{
private int resourceid;
public FruitAdapter(Context context , int textviewResourceId , List<Fruit> Objects){
super(context,textviewResourceId,Objects);
resourceid = textviewResourceId;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {/*每次都将布局重新加载一遍*/
Fruit fruit = getItem(position);/*convertView用于将之前加载好的布局进行缓存,可以进行重用*/
View view;
ViewHolder viewHolder;
if(convertView == null){
view = LayoutInflater.from(getContext()).inflate(resourceid,parent,false);
viewHolder = new ViewHolder();
viewHolder.fruit_iamge_id = (ImageView) view.findViewById(R.id.item_image);
viewHolder.fruit_name_id = (TextView) view.findViewById(R.id.item_name);
view.setTag(viewHolder);/*将viewHolder存储在view中*/
}else{
view = convertView;
viewHolder = (ViewHolder) view.getTag();/*当ViewHolder不为空的时候调用getTeg()重新获取ViewHolder,这样,所有的控件实例都缓存在了ViewHolder中*/
}
viewHolder.fruit_iamge_id.setImageResource(fruit.getImageid());
viewHolder.fruit_name_id.setText(fruit.getName());
return view;
}
class ViewHolder{/*新增一个内部类用于对控件进行缓存,当convertView为空时候,创建一个ViewHolder对象,将控件实例存放在ViewHolder里*/
ImageView fruit_iamge_id;/**/
TextView fruit_name_id;
}
}
3.5.4ListView的点击事件
fruit_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override/*四个参数分别代表:parent识别是哪个ListView,view当前listview的item的view的布局,用这个view,获取里面空间的id后操作控件,position当前item在listview中适配器里的位置,id是当前item在listview里的第几行的位置*/
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Fruit fruit = fruitList.get(position);/*通过position判断用户点击的是哪个子项*/
Toast.makeText(MainActivity.this,fruit.getName(),Toast.LENGTH_LONG).show();
}
});
3.6RecyclerView滚动控件
使用RecyclerView需要在app/build.gradle中添加依赖库:
compile 'com.android.support:recyclerview-v7:25.3.1'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
compile 'com.android.support:recyclerview-v7:25.3.1'
testCompile 'junit:junit:4.12'
}
点击Sync Now进行同步
准备适配器:
package co.example.hanwei.listviewtest;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
/**
* Created by hanwei on 2018/8/10 0010.
*/
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{
private List<Fruit> mFruitList;
/*
* 首先定义一个内部类ViewHolder继承自RecyclerView.ViewHolder
* ViewHolder的构造函数传入一个View的一个参数,通常就是RecyclerView子项的最外层布局
* 然后就可以通过findViewById获取布局中的图片和名字的实例
* */
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView fruit_image_id;
TextView fruit_name_id;
public ViewHolder(View itemView) {
super(itemView);
fruit_image_id = (ImageView)itemView.findViewById(R.id.item_image);
fruit_name_id = (TextView)itemView.findViewById(R.id.item_name);
}
}
/*
* 构造函数,用故意把要展示的数据源传进来,赋值给一个全局变量mFruitList
* */
public FruitAdapter(List<Fruit> fruitList){
mFruitList = fruitList;
}
/**
* 因为FruitAdapter是继承自RecyclerView.Adapter
*那么必须重写onCreateViewHolder(),onBindViewHolder(),getItemCount()
*/
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {/*在这里将布局加载进来,创建一个ViewHolder实例*/
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
ViewHolder holder = new ViewHolder(view);/*并把加载进来的布局传入到构造函数中*/
return holder;/*最后将ViewHolder的实例返回*/
}
/*
*onBindViewHolder是用于对RecyclceView子项数据进行赋值的,
* 会在每个子项滚入屏幕内执行,通过position参数得到当前Fruit实例
* 再将数据设置到ViewHolder的ImageView和TextView中
*/
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Fruit fruit = mFruitList.get(position);
holder.fruit_image_id.setImageResource(fruit.getImageid());
holder.fruit_name_id.setText(fruit.getName());
}
/*
*告诉RecyclerView一共有多少子项
*/
@Override
public int getItemCount() {
return mFruitList.size();
}
}
控件布局:
<?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"
tools:context="co.example.hanwei.listviewtest.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/fruit_receclerview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
MainActivity.java修改:
package co.example.hanwei.listviewtest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private List<Fruit> furitlist = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruit();/*初始化所有水果数据*/
RecyclerView fruit_recyclerview = (RecyclerView)findViewById(R.id.fruit_receclerview);
/*LinearLayoutManager:线性布局管理器*/
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
/*将他设置到RecyclerView中,LinearLayoutManager用于指定RecyclerView的布局方式,LinearLayoutManager是线性布局的意思,可以实现ListView类似的效果*/
fruit_recyclerview.setLayoutManager(layoutManager);
/*接下来创建FruitAdapter实例,将furitlist水果数据传入到FruitAdapter的构造函数中*/
FruitAdapter adapter = new FruitAdapter(furitlist);
fruit_recyclerview.setAdapter(adapter);/*将adapter作为适配器传递给RecyclerView*/
}
public void initFruit(){
for(int i = 0;i < 30 ;i ++){
Fruit banana = new Fruit("Banana",R.mipmap.ic_launcher);/*在Fruit类的构造函数中将对应的水果名字和对应说过图片的id传入*/
furitlist.add(banana); /*将创建好的对象添加到水果列表中*/
Fruit apple = new Fruit("apple",R.mipmap.ic_launcher);
furitlist.add(apple);
Fruit orange = new Fruit("orange",R.mipmap.ic_launcher);
furitlist.add(orange);
Fruit pear = new Fruit("pear",R.mipmap.ic_launcher);
furitlist.add(pear);
Fruit cherry = new Fruit("cherry",R.mipmap.ic_launcher);
furitlist.add(cherry);
}
}
}
实现了类似ListView的效果。
3.6.2实现横向滚动和瀑布流布局
记者如一行代码,来设置布局的排列方向,HORIZONTAL表示让布局横向排列
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruit();/*初始化所有水果数据*/
RecyclerView fruit_recyclerview = (RecyclerView)findViewById(R.id.fruit_receclerview);
/*LinearLayoutManager:线性布局管理器*/
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
/*将他设置到RecyclerView中,LinearLayoutManager用于指定RecyclerView的布局方式,LinearLayoutManager是线性布局的意思,可以实现ListView类似的效果*/
fruit_recyclerview.setLayoutManager(layoutManager);
/*接下来创建FruitAdapter实例,将furitlist水果数据传入到FruitAdapter的构造函数中*/
FruitAdapter adapter = new FruitAdapter(furitlist);
fruit_recyclerview.setAdapter(adapter);/*将adapter作为适配器传递给ListView*/
}
自定义布局修改为:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:id="@+id/item_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
android:layout_gravity="center_horizontal"/>
<TextView
android:id="@+id/item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="名字"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
RecyclerView能做到横向滚动,是因为布局排列交给了LayoutManager,其中制订了一套可扩展的布局排列接口,子类只要按照接口的规范来实现,就能定制出不同排列方式的布局,RecyclerView给我们提供了StaggeredGridLayoutManager和GridLayoutManager,我们试一下StaggeredGridLayoutManager:
修改item布局文件:
<?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="wrap_content"
android:layout_margin="5dp"
android:orientation="vertical">
<! -- 这里做了几处小的调整,首先将 Linear Layout的宽度由100dp改成了 match parent,因为
瀑布流布局的宽度应该是根据布局的列数来自动适配的,而不是一个固定值。另外我们使用了
layout margin属性来让子项之间互留一点间距,这样就不至于所有子项都紧贴在一些。还有
就是将 Text view的对齐属性改成了居左对齐,因为待会我们会将文字的长度变长,如果还是居
中显示就会感觉怪怪的-->
<ImageView
android:id="@+id/item_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
android:layout_gravity="center_horizontal"/>
<TextView
android:id="@+id/item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="名字"
android:layout_gravity="left"/>
</LinearLayout>
代码中修改:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruit();/*初始化所有水果数据*/
RecyclerView fruit_recyclerview = (RecyclerView)findViewById(R.id.fruit_receclerview);
/*在onCreate()实现瀑布流布局StaggeredGridLayoutManager构造函数接受两个参数,第一个指定布局的列数,指定布局的排列方向,传入StaggeredGridLayoutManager.VERTICAL会纵向排列*/
StaggeredGridLayoutManager layoutManager= new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
/*LinearLayoutManager:线性布局管理器*/
/*LinearLayoutManager layoutManager = new LinearLayoutManager(this);*/
/*layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);*/
/*将他设置到RecyclerView中,LinearLayoutManager用于指定RecyclerView的布局方式,LinearLayoutManager是线性布局的意思,可以实现ListView类似的效果*/
fruit_recyclerview.setLayoutManager(layoutManager);
/*接下来创建FruitAdapter实例,将furitlist水果数据传入到FruitAdapter的构造函数中*/
FruitAdapter adapter = new FruitAdapter(furitlist);
fruit_recyclerview.setAdapter(adapter);/*将adapter作为适配器传递给ListView*/
}
具体效果:
3.6.3 RecyclerView的点击事件
RecyclerView直接摒弃了子项点击事件的监听器,所有的点击事件都由具体的Ⅴiew去注册。在FruitAdapter中修改。
我们先是修改了 ViewHolder,在 Viewholder中添加了 fruitier变量来保存子项最外层布局的实例:
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView fruit_image_id;
TextView fruit_name_id;
/*用于保存子项最外层布局实例*/
View fruitview;
public ViewHolder(View itemView) {
super(itemView);
fruitview = itemView;
fruit_image_id = (ImageView)itemView.findViewById(R.id.item_image);
fruit_name_id = (TextView)itemView.findViewById(R.id.item_name);
}
}
在onCreateViewHolder中注册点击事件:
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {/*在这里将布局加载进来,创建一个ViewHolder实例*/
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
final ViewHolder holder = new ViewHolder(view);/*并把加载进来的布局传入到构造函数中*/
holder.fruitview.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/*获取实例中点击item在adapter中的position(位置)*/
int position = holder.getAdapterPosition();
/*通过position(位置)拿到相应的实例*/
Fruit fruit = mFruitList.get(position);
Toast.makeText(v.getContext(),"你点击了"+fruit.getName(),Toast.LENGTH_SHORT).show();
}
});
holder.fruit_image_id.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Toast.makeText(v.getContext(),"你点击了图片"+fruit.getImageid(),Toast.LENGTH_SHORT).show();
}
});
return holder;/*最后将ViewHolder的实例返回*/
}