UI开发
常用控件
Android提供了大量的UI控件,合理地使用这些控件就可以非常轻松地编写出相当不错的界
面,下面我们就挑选几种常用的控件,详细介绍下 它们的使用方法。
TextView
用于在界面上显示一段信息。
<TextView
android:id="@+id/text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="24sp"
android:textColor="#00ff00"
android:text="This is TextView"/>
Button
在界面上显示一个按钮,可以在ManiActivity
中为其注册监听器来实现对按钮事件的监听。
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button"/>
android:textAllCaps="false"
:避免系统自动对所有字母更换大写。
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" />
ImageView
展示图片
<ImageView
android:id="@+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/img_1"
/>
ProgressBar
在界面上显示一个进度条,默认环形进度条,可以增加属性style="?android:attr/progressBarStyleHorizontal"
将进度条设置为长条形,之后还可以添加android:max="100"
属性给进度条设置一个最大值
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleHorizontal"
android:max="100" />
AlertDialog
弹出一个对话框,置顶于所有界面元素之上,屏蔽掉其他控件的交互能力,一般用于提示一些非常重要的内容或者警告信息。
AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);
dialog.setTitle("This is Dialog");
dialog.setMessage("Something important");
dialog.setCancelable(false);
dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.setNegativeButton("Canel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
dialog.show();
ProgressDialog
弹出一个对话框,显示进度条
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button:
ProgressDialog progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setTitle("This is ProgressDialog");
progressDialog.setMessage("Loading...");
progressDialog.setCancelable(true);
progressDialog.show();
break;
default:
break;
}
}
}
4种基本布局
线性布局
将它所包含的控件在线性方向上依次排列,通过android:orentation
属性指定排列方向是vertical
使其排列方向垂直,如果是horizontal
则水平排列
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
android:layout_gravity
:指定控件在布局中的对齐方式。
android:layout_weight
:使用比例控制控件大小。
相对布局
相对父布局定位
android:layout_alignParentTop
android:layout_centerInParent
android:layout_alignParentBottom
android:layout_alignParentLeft
android:layout_alignParentRight
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:text="Button1" />
<Button
android:id="@+id/button_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:text="Button2 "/>
<Button
android:id="@+id/button_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Button3" />
<Button
android:id="@+id/button_4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:text="Button4" />
<Button
android:id="@+id/button_5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:text="Button5" />
</RelativeLayout>
相对控件布局
android:layout_above
android:layout_below
android:layout_toLeftOf
android:layout_toRightOf
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/button_3"
android:layout_toLeftOf="@id/button_3"
android:text="Button1" />
<Button
android:id="@+id/button_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/button_3"
android:layout_toRightOf="@id/button_3"
android:text="Button2 "/>
<Button
android:id="@+id/button_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Button3" />
<Button
android:id="@+id/button_4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/button_3"
android:layout_toLeftOf="@id/button_3"
android:text="Button4" />
<Button
android:id="@+id/button_5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/button_3"
android:layout_toRightOf="@id/button_3"
android:text="Button5" />
</RelativeLayout>
帧布局
所有控件默认放在布局的左上角
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
自定义控件
引入布局
创建布局,在活动布局引入该布局即可
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/back_bg">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/title_back"
android:layout_gravity="center"
android:layout_margin="5dp"
android:background="#EFCECE"
android:text="Back"
android:textColor="#BC3131"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/title_text"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:text="Title Text"
android:textColor="#fff"
android:textSize="24sp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/title_edit"
android:layout_gravity="center"
android:layout_margin="5dp"
android:background="@drawable/back"
android:text="Edit"
android:textColor="#fff"/>
</LinearLayout>
//在主活动布局中引入
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/title"/>
</LinearLayout>
//隐藏标题栏
ActionBar actionbar = getSupportActionBar();
if(actionbar != null){
actionbar.hide();
}
自定义控件
避免同一点击事件,在每一个活动中都重新注册一遍。
public class TitleLayout extends LinearLayout {
public TitleLayout(Context context, AttributeSet attrs) {
super(context);
LayoutInflater.from(context).inflate(R.layout.title,this);
Button titleBack = (Button) findViewById(R.id.title_back);
Button titleView = (Button) findViewById(R.id.title_edit);
titleBack.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
((Activity)getContext()).finish();
}
});
titleView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(getContext(),"You clicked Edit button",Toast.LENGTH_SHORT).show();
}
});
}
}
在指明控件时,我们要指明其完整的类名,包名在这是不可以省略的。
<com.example.uicustomviews.TitleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" />
ListView
允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内。
定制ListView界面
- 布局中加入ListView
- 创建ListView子 布局
- 创建内容类
- 定义ListView适配器类
- 主活动中初始化内容并且为其设置适配器
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"/>
</LinearLayout>
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;
}
}
public class FruitAdapter extends ArrayAdapter<Fruit> {
private int resourceId
public FruitAdapter( Context context, int textViewResourceId,List<Fruit> objects) {
super(context, resource, objects);
resourceId = textViewResourceId;
}
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Fruit fruit = getItem(position); //获取当前项的Fruit实例
View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);
fruitImage.setImageResource(fruit.getImageId());
fruitName.setText(fruit.getName());
return view;
}
}
public class MainActivity extends AppCompatActivity {
private List<Fruit> fruitList = new ArrayList<Fruit>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//定制ListView
initFruits(); //初始化水果数据
FruitAdapter adapter = new FruitAdapter(MainActivity.this,R.layout.fruit_item,fruitList);
ListView listView = (ListView)findViewById(R.id.list_view);
listView.setAdapter(adapter);
}
private void initFruits() {
for(int i = 0;i < 2; i++){
Fruit apple = new Fruit("Apple",R.drawable.apple);
fruitList.add(apple);
Fruit orange = new Fruit("Orange",R.drawable.orange);
fruitList.add(orange);
Fruit banana = new Fruit("Banana",R.drawable.banana);
fruitList.add(banana);
Fruit watermelon = new Fruit("Watermelon",R.drawable.watermelon);
fruitList.add(watermelon);
Fruit pear = new Fruit("Pear",R.drawable.pear);
fruitList.add(pear);
Fruit grape = new Fruit("Grape",R.drawable.grape);
fruitList.add(grape);
Fruit pineapple = new Fruit("Pineapple",R.drawable.pineapple);
fruitList.add(pineapple);
Fruit cherry = new Fruit("Cherry",R.drawable.cherry);
fruitList.add(cherry);
Fruit peach = new Fruit("Peach",R.drawable.peach);
fruitList.add(peach);
}
}
}
提升ListView的运行效率
两种方法:
- 缓存布局内容
- 缓存控件的实例
public class FruitAdapter extends ArrayAdapter<Fruit> {
private int resourceId;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Fruit fruit = getItem(position); //获取当前项的Fruit实例
View view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
ViewHolder viewHolder;
//快速滚动
if(convertView == null){
view = LayoutInflater.from(getContext()).inflate(resourceId,parent,false);
viewHolder = new ViewHolder();
viewHolder.fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
viewHolder.fruitName = (TextView)view.findViewById(R.id.fruit_name);
view.setTag(viewHolder); //将ViewHolder存入View
}else{
view = convertView;
viewHolder = (ViewHolder) view.getTag(); //重新获取ViewHolder
//提升运行效率
viewHolder.fruitImage.setImageResource(fruit.getImageId());
viewHolder.fruitName.setText(fruit.getName());
return view;
}
class ViewHolder{
ImageView fruitImage;
TextView fruitName;
}
}
ListView的点击事件
在活动中为Listview注册监听器即可
initFruits(); //初始化水果数据
FruitAdapter adapter = new FruitAdapter(MainActivity.this,R.layout.fruit_item,fruitList);
ListView listView = (ListView)findViewById(R.id.list_view);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Fruit fruit = fruitList.get(i);
Toast.makeText(MainActivity.this,fruit.getName(),Toast.LENGTH_SHORT).show();
}
});
RecyclerView
RecyclerView的基本用法
- 新增控件,先添加以依赖,在
build.gradle
中导入 - 布局中加入RecyclerView
- 创建RecyclerView子布局
- 创建内容类
- 定义RecyclerView适配器类
- 主活动中初始化内容并且为其设置适配器
dependencies {
implementation 'androidx.recyclerview:recyclerview:1.1.0'
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/fruit_name"
android:gravity="center"
android:layout_marginLeft="10dp"
android:textSize="30sp"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
</LinearLayout>
public class Fruit {
String name;
int image;
public Fruit(String name,int image){
this.image=image;
this.name=name;
}
public String getName() {
return name;
}
public int getImage() {
return image;
}
}
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
private List<Fruit> mFruitList;
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView fruitImage;
TextView fruitName;
public ViewHolder(View itemView) {
super(itemView);
fruitImage = (ImageView) itemView.findViewById(R.id.fruit_image);
fruitName = (TextView) itemView.findViewById(R.id.fruit_name);
}
}
public FruitAdapter(List<Fruit> fruitList){
mFruitList = fruitList;
}
@Override
public FruitAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.fruit_item,parent,false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(FruitAdapter.ViewHolder holder, int position) {
Fruit fruit = mFruitList.get(position);
holder.fruitImage.setImageResource(fruit.getImageId());
holder.fruitName.setText(fruit.getName());
}
@Override
public int getItemCount() {
return mFruitList.size();
}
}
public class MainActivity extends AppCompatActivity {
private List<Fruit> fruitList=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initFruits();
RecyclerView recyclerView=(RecyclerView) findViewById(R.id.recycler_view);
LinearLayoutManager manager=new LinearLayoutManager(this);//获取manager实例,并为RecyclerView设置manager
recyclerView.setLayoutManager(manager);
FruitAdapter adapter=new FruitAdapter(fruitList);//获取适配器实例,并为RecyclerView设置适配器
recyclerView.setAdapter(adapter);
}
private void initFruits(){//给RecyclerView初始化内容
for(int i=0;i<50;i++){
Fruit apple=new Fruit("apple",R.drawable.apple);
fruitList.add(apple);
}
}
}
实现横向滚动和瀑布流布局
横向滚动
首先在子布局文件中修改
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="100dp"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"/>
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="10dp"/>
</LinearLayout>
在活动主代码中加入
RecyclerView recyclerView=(RecyclerView) findViewById(R.id.recycler_view);
LinearLayoutManager manager=new LinearLayoutManager(this);
manager.setOrientation(RecyclerView.HORIZONTAL);//将manager设置为横向即可
recyclerView.setLayoutManager(manager);
FruitAdapter adapter=new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
网格布局
RecyclerView recyclerView=(RecyclerView) findViewById(R.id.recycler_view);
GridLayoutManager manager=new GridLayoutManager(this,2);//将manager换为这种形式,第二个参数就是列数
recyclerView.setLayoutManager(manager);
FruitAdapter adapter=new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
瀑布流布局
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
FruitAdapter adapter = new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
RecyclerView的点击事件
不同于ListView,RecyclerView并不能给子布局注册监听器,只能给每个子项注册监听器,所有的点击事件都由具体的View去注册。并且RecyclerView的监听器是在适配器中注册的
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
private List<Fruit> mFruitList;
static class ViewHolder extends RecyclerView.ViewHolder{
View fruitView;
ImageView fruitImage;
TextView fruitName;
public ViewHolder(View itemView) {
super(itemView);
fruitView = itemView;
fruitImage = (ImageView) itemView.findViewById(R.id.fruit_image);
fruitName = (TextView) itemView.findViewById(R.id.fruit_name);
}
}
public FruitAdapter(List<Fruit> fruitList){
mFruitList = fruitList;
}
@Override
public FruitAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
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 view) {
int position = holder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Toast.makeText(view.getContext(),"you clicked View"+fruit.getName(),Toast.LENGTH_SHORT).show();
}
});
holder.fruitImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = holder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Toast.makeText(view.getContext(),"you clicked Image"+fruit.getName(),Toast.LENGTH_SHORT).show();
}
});
return holder;
}