3.1 如何编写程序界面
3.2 常用控件的使用方法
3.2.1TextView
3.2.2 Button
3.2.3 EditText
3.2.4 ImageView
3.2.5 ProgressBar
3.2.6 AlertDialog
3.2.7 ProgressDialog
3.3 详解4种常用布局
3.3.1 线性布局
3.3.2 相对布局
3.3.3 帧布局
3.3.4 百分比布局
3.4 系统控件不够用?创建自定义控件
3.4.1 引入布局
3.4.2 创建自定义控件
3.5 最常用和最难用的控件——ListView
3.5.1 ListView的简单用法
3.5.2 定制ListView的界面
3.5.3 提升ListView的运行效率
3.5.4 ListView的点击事件
3.6 更强大的滚动控件——RecyclerView
3.6.1 RecyclerView的基本用法
3.6.2 实现横向滚动和瀑布流布局
3.6.3 RecyclerView的点击事件
3.7 编写界面的最佳实践
3.7.1 制作Nine-Patch图片
3.7.2 编写精美的聊天布局
3.8 小结与点评
Android中有多种编写程序界面的方式可供选择。Android Studio 和Eclipse中都提供了相应的可视化编辑器,允许使用拖放控件的方式来编写布局,并能在视图上直接修改控件的属性。不过我并不推荐你使用这种方式来编写界面,因为可视化编辑工具并不利于你去真正了解界面背后的实现原理。通过这种方式制作出的界面通常不具有很好的屏幕适配性,而且当需要编写较为复杂的界面时,可视化编辑工具将很难胜任。因此本书中所有的界面都将通过最基本的方式去实现,即编写XML代码。等你完全掌握了使用XML来编写界面的方法之后,不管是进行高复杂度的界面实现,还是分析和修改当前现有界面,对你来说都将是手到擒来。
显示一段文本信息
用户交互的控件(比如,点击跳转)
输入 和编辑内容(如:微信发送的消息)
图片控件 用于显示图片
进度条
Style不写 默认 圆形进度条 ?android:attr/progressBarStyleHorizontal
可以在当前的界面弹出一个对话框
new AlertDialog.Builder(this)
.setTitle("确定要删除吗?")
.setMessage("Something important.")
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
}
})
.show();
进度条弹框
final ProgressDialog dialog = new ProgressDialog(this);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);// 设置水平进度条
dialog.setCancelable(true);// 设置是否可以通过点击Back键取消
dialog.setCanceledOnTouchOutside(false);// 设置在点击Dialog外是否取消Dialog进度条
dialog.setIcon(R.drawable.ic_launcher);// 设置提示的title的图标,默认是没有的
dialog.setTitle("提示");
dialog.setMax(100);
dialog.setButton(DialogInterface.BUTTON_POSITIVE, "确定",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
});
dialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
});
dialog.setButton(DialogInterface.BUTTON_NEUTRAL, "中立",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
}
});
dialog.setMessage("这是一个水平进度条");
dialog.show();
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
int i = 0;
while (i < 100) {
try {
Thread.sleep(200);
// 更新进度条的进度,可以在子线程中更新进度条进度
dialog.incrementProgressBy(1);
// dialog.incrementSecondaryProgressBy(10)//二级进度条更新方式
i++;
} catch (Exception e) {
// TODO: handle exception
}
}
// 在进度条走完时删除Dialog
dialog.dismiss();
}
}).start();
LinearLayout又称作线性布局,是一种非常常用的布局。
android:orientation="horizontal" 默认水平 vertical 修改后横向
可以通过相对定位的方式让空间出现在布局的任何位置。
如下让Button2 在Button1 右侧
应用场景也少了很多,所有控件都会显示在布局的左上角
前面3 种布局都是从Android 1.0版本中就开始支持了,一直沿用到现在,但是特殊情况以上布局实现起来很不支持的
百分比库 地址 使用方式 请同时查看
https://github.com/JulienGenoud/android-percent-support-lib-sample
当系统自带的控件不能支持我们的需求时,就需要自定义空控件了。
这2章主要是讲 新建一个xml文件 设置标题栏的布局
并不是我们所想的自定义View
由于屏幕控件比较有限,能够一次性在屏幕上显示的内容不多,所以有大数据的时候需要用到列表
在布局中加入ListView 控件,并为ListView 指定了一个id 设置成match_parent 占满整个空间
在Activity中
public class MainActivity extends Activity {
private String[] data = { "Apple", "Banana", "Orange", "Watermelon",
"Pear", "Grape", "Pineapple", "Strawberry", "Cherry", "Mango" };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayAdapter adapter = new ArrayAdapter(
MainActivity.this, android.R.layout.simple_list_item_1, data);
ListView listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(adapter);
}
}
在这里我运用了系统包含的一个TextView的布局文件:android.R.layout.simple_expandable_list_item_1,调用这个比较方便,
ArrayAdapter
ArrayAdapter是BaseAdapter的子类
定义一个实体类Fruit
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 的子项指定一个我们自定义的布局 fruit_item.xml。
创建一个自定义的适配器 FruitAdapter,这个适配器继承自 ArrayAdapter。重写构造方法和 getView 方法。
public class FruitAdapter extends ArrayAdapter{
private final int resourceId;
public FruitAdapter(Context context, int textViewResourceId, List objects) {
super(context, textViewResourceId, objects);
resourceId = textViewResourceId;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Fruit fruit = (Fruit) getItem(position); // 获取当前项的Fruit实例
View view = LayoutInflater.from(getContext()).inflate(resourceId, null);//实例化一个对象
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;
}
}
View view = LayoutInflater.from(getContext()).inflate(resourceId, null);使用Inflater对象来将布局文件解析成一个View
在MainActivity中编写,初始化水果数据
public class MainActivity extends Activity {
private List fruitList = new ArrayList();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
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() {
Fruit apple = new Fruit("Apple", R.drawable.apple_pic);
fruitList.add(apple);
Fruit banana = new Fruit("Banana", R.drawable.banana_pic);
fruitList.add(banana);
Fruit orange = new Fruit("Orange", R.drawable.orange_pic);
fruitList.add(orange);
Fruit watermelon = new Fruit("Watermelon", R.drawable.watermelon_pic);
fruitList.add(watermelon);
Fruit pear = new Fruit("Pear", R.drawable.pear_pic);
fruitList.add(pear);
Fruit grape = new Fruit("Grape", R.drawable.grape_pic);
fruitList.add(grape);
Fruit pineapple = new Fruit("Pineapple", R.drawable.pineapple_pic);
fruitList.add(pineapple);
Fruit strawberry = new Fruit("Strawberry", R.drawable.strawberry_pic);
fruitList.add(strawberry);
Fruit cherry = new Fruit("Cherry", R.drawable.cherry_pic);
fruitList.add(cherry);
Fruit mango = new Fruit("Mango", R.drawable.mango_pic);
fruitList.add(mango);
}
}
运行效果图
这样一个简单的ListView界面就完成了
以下为单个item点击事件
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
}
});
如果要实现子view点击事件 可以写接口实现
增加版的ListView优化Listview中的各种问题,扩展性要好。
没有添加build gradle 的 添加依赖库
版本号 可改
implementation 'com.android.support:recyclerview-v7:27.1.1'
添加RecyclerView
同上使用水果类就可以
新建Adapter
我这里用了ButterKnife 注解
package com.dak.administrator.firstcode.material_design;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v7.widget.CardView;
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 com.bumptech.glide.Glide;
import com.dak.administrator.firstcode.R;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
/**
* Created by Administrator on 2018/11/7.
*/
public class FruitAdapter extends RecyclerView.Adapter {
private Context mContext;
private List mFruitList;
public FruitAdapter(List fruitList) {
mFruitList = fruitList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (mContext == null) {
mContext = parent.getContext();
}
View view = LayoutInflater.from(mContext).inflate(R.layout.fruit_item, parent, false);
final ViewHolder holder = new ViewHolder(view);
holder.cardView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int postion = holder.getAdapterPosition();
Fruit fruit = mFruitList.get(postion);
Intent intent = new Intent(mContext, CollapseActivity.class);
intent.putExtra(CollapseActivity.FRUIT_NAME, fruit.getName());
intent.putExtra(CollapseActivity.FRUIT_IMAGE_ID, fruit.getImageId());
mContext.startActivity(intent);
}
});
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Fruit fruit = mFruitList.get(position);
holder.fruitName.setText(fruit.getName());
Glide.with(mContext).load(fruit.getImageId()).into(holder.fruitImage);
}
@Override
public int getItemCount() {
return mFruitList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder{
@BindView(R.id.fruit_image)
ImageView fruitImage;
@BindView(R.id.fruit_name)
TextView fruitName;
@BindView(R.id.card_view)
CardView cardView;
public ViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
}
}
}
Activity调用
adapter = new FruitAdapter(fruitsList);
GridLayoutManager layoutManager = new GridLayoutManager(this, 2);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
横向滚动只要把 之前GridLayoutManager 改成如下即可
LinearLayoutManager默认 竖向
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
瀑布流:
StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
当然瀑布流是存在着许多坑 请看
https://www.jianshu.com/p/b0f80b1c29d0
https://blog.csdn.net/lhk147852369/article/details/84346240
点击事件已经在上代码加上了 在ViewHolder当中 这是在adapter的
如果需要在Activity或其他地方 可以写接口实现,这里不说了。
http://www.jcodecraeer.com/plus/view.php?aid=7881
https://blog.csdn.net/lhk147852369/article/details/84346031
主要是在onBindViewHolder 判断传过来的信息是发送的还是接收的
通过Type值 去设置Visible 或者Gone
当然还有另外方法
通过getItemViewType方法
https://www.cnblogs.com/android-blogs/p/5690853.html
郭霖总结:
虽然本章的内容很多,但我觉得学习起来应该还是挺愉快的吧。不同于上一章中我们来来回回使用那几个按钮,本章可以说是使用了各种各样的控件,制作出了丰富多彩的界面。尤其是在实战环节,编写出了那么精美的聊天界面,你的满足感应该比上一章还要强吧?
本章从Android中的一些常见控件开始人手,依次介绍了基本布局的用法、自定义控件的方法、ListView 的详细用法以及RecyclerView的使用,基本已经将重要的UI知识点全部覆盖了。想想在开始的时候我说不推荐使用可视化的编辑工具,而是应该全部使用XML的方式来编写界面,现在你是不是已经感觉使用XML非常简单了呢?以后不管面对多么复杂的界面,我希望你都能够自信满满,因为真正理解了界面编写的原理之后,是没有什么能够难得倒你的。
不过到目前为止,我们还只是学习了Android 手机方面的开发技巧,下一章将会涉及一些Android平板方面的知识点,能够同时兼容手机和平板也是自Android4.0 系统开始就支持的特性。适当地放松和休息一段时间后, 我们再来继续前行吧!
我的总结:
这章还是比较重要的,因为在工作中接触到的很多都是和列表有关的。