1.常用控件:
Button:
android:textAllCaps="false"
—— 用于设定文本是否大写
EditText:
android:hint="Something"
—— 指定一段提示性文本
android:inputType="password"
—— 设定输入类型
android:maxLines="2"
—— 设定最大行数
ImageView:
android:src="@drawable/img_1"
—— 指定一张图片
setImageResource(R.drawable.img_2)
—— 设定图片资源
ProgressBar:
android:visibility="visible"/"invisible"/"gone"
—— 设定可见属性
setVisibility(View.VISIBLE/View.INVISIBLE/View.GONE)
—— 设定可见属性
getVisibility()
—— 获取当前可见属性
style="?android:attr/progressBarStyleHorizontal"
android:max="100"
—— 设定水平进度条,并限制最大值为 100
getProgress()
setProgress()
—— 获取当前进度和设置进度
AlertDialog:
new AlertDialog.Builder(Context context)
—— 创建警告对话框
setTitle()
—— 设定标题
setMessage
—— 设定内容
setCancelable
—— 设定是否能返回取消对话框
setPositiveButton()
—— 设置确定按钮
setNegativeButton()
—— 设置取消按钮
show()
—— 将对话框显示出来
ProgressDialog:
new ProgressDialog(Context context)
—— 创建进度对话框
setTitle()
—— 设定标题
setMessage
—— 设定内容
setCancelable
—— 设定是否能返回取消对话框
show()
—— 将对话框显示出来
dismiss()
—— 关闭对话框
setIndeterminate()
—— 设定不确定状态
2.详解基本布局:
RelativeLayout:
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_centerInParent="true"
—— 根据父布局来摆放控件
android:layout_above="@id/button"
android:layout_below="@id/button"
android:layout_toLeftOf="@id/button"
android:layout_toRightOf="@id/button"
—— 根据控件来摆放
android:layout_alignLeft="@id/button"
android:layout_alignTop="@id/button"
—— 对齐控件边缘,当一个控件去引用另一个控件的 id 时,该控件一定要定义在引用控件的后面,不然会出现找不到 id 的情况
PercentLayout:
implementation 'com.android.support:percent:24.2.1'
—— 在 app/build.gradle 的 dependencies 闭包中添加依赖声明
android.support.percent.PercentFrameLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
—— 在布局文件中添加完整包名和 app命名空间
app:layout_widthPercent="50%"
app:layout_heightPercent="50%"
—— 设定空间百分比大小
3.自定义 View:
所有控件都是直接或间接继承自 View,所用的所有布局都是直接或间接继承自 ViewGroup。View 是 Android 中最基本的一种 UI组件,而 ViewGroup 是一种特殊的 View,它可以包含很多 子View 和 子ViewGroup,是一个用于放置控件和布局的容器
引入布局:
重新定义一个 title.xml 标题栏布局,在 activity_main.xml 中引入
<include layout="@layout/title"/>
将系统自带的标题栏隐藏
ActionBar actionBar = getSupportActionBar();
if(actionBar != null){
actionBar.hide();
}
- 创建自定义控件:
——新建一个 java 文件,让其作为标题栏控件,并编写具体逻辑操作
Public class TitleLayout extends LinearLayout implements View.OnClickListener{
public TitleLayout(Context context, AttributeSet attrs){
super(context, attrs);
/**
* inflate() 第二个参数是给加载好的布局再添加一个父布局
* 这里指定为 TitleLayout
*/
LayoutInflater.from(context).inflate(R.layout.title, this);
Button titleBack = findViewById(R.id.title_back);
Button titleEdit = findViewById(R.id.title_edit);
titleBack.setOnClickListener(this);
titleEdit.setOnClickListener(this);
}
@Override
public void onClick(View v){
switch (v.getId()){
case R.id.title_back:
// 编写逻辑
break;
case R.id.title_edit:
// 编写逻辑
break;
}
}
}
——在 activity_main.xml 中添加此自定义控件
<com.example.uitest.TitleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
4.探究 ListView:
简单用法:
- 直接在 activity_main.xml 中加入控件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
- 修改 MainActivity.java
public class MainActivity extends AppCompatActivity {
/**
* 简单使用 String 类型数组来测试
*/
private String[] data = {"Apple", "Pear", "Grape", "Banana", "Orange", "Cherry",
"Apple", "Pear", "Grape", "Banana", "Orange", "Cherry", "Watermelon",
"Apple", "Pear", "Grape", "Banana", "Orange", "Cherry", "Watermelon",
"Apple", "Pear", "Grape", "Banana", "Orange", "Cherry", "Watermelon",};
/**
* 数组中的数据无法直接传递给 ListView ,因此需要借助适配器来完成,
* 新建一个数组适配器,泛型指定为 String ,这里使用了系统内置的布局
* android.R.layout.simple_list_item_1 作为 ListView 子项布局的 id ,
* 最后调用 ListView 的 setAdapter() 方法将构建好的适配器对象传入,
* 这样 ListView 和数据之间的关联就建立完成了。
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ArrayAdapter<String> adapter = new ArrayAdapter<String>
(this,android.R.layout.simple_list_item_1, data);
ListView listView = findViewById(R.id.list_view);
listView.setAdapter(adapter);
}
}
步骤:
- 添加 ListView 控件
- 添加需要适配的数据
- 生成适配器对象,泛型指定为数据类型
- 生成 ListView 的实例
- 调用 ListView 的
setAdapter()
方法,将构建好的适配器对象传入
定制 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子项布局:
<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_height="wrap_content"
android:layout_width="wrap_content"/>
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="10dp"/>
</LinearLayout>
- 创建一个自定义适配器:
public class FruitAdapter extends ArrayAdapter<Fruit>{
// ListView 子项布局id
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);
View view;
ViewHolder viewHolder;
if(convertView == null){
view = LayoutInflater.from(getContext())
.inflate(resourceId, parent, false);
viewHolder = new ViewHolder();
viewHolder.fruitImage = view.findViewById(R.id.fruit_image);
viewHolder.fruitName = view.findViewById(R.id.fruit_name);
view.setTag(viewHolder);
}else{
view = convertView;
viewHolder = (ViewHolder)view.getTag();
}
viewHolder.fruitImage.setImageResource(fruit.getImageId());
viewHolder.fruitName.setText(fruit.getName());
return view;
}
class ViewHolder{
ImageView fruitImage;
TextView fruitName;
}
}
—— 对 convertView 进行重用,并且使用 ViewHolder 对控件的实例进行缓存,以便提升 ListView 的运行效率
- 修改 MainActivity 的代码:
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);
initFruit(); // 初始化水果数据
FruitAdapter adapter = new FruitAdapter(this,R.layout.fruit_item, fruitList);
ListView listView = findViewById(R.id.list_view);
listView.setAdapter(adapter);
}
private void initFruit(){
for(int i = 0; i < 2; i++){
Fruit apple = new Fruit("Apple", R.drawable.apple_pic);
fruitList.add(apple);
Fruit banana = new Fruit("Banana", R.drawable.banana_pic);
fruitList.add(banana);
// 省略以下重复代码
}
}
}
ListView 的点击事件:
- 参数:
- parent 用于识别是哪个 ListView
- view 是当前 ListView 的 item 的布局,可以使用这个 view,获取里面的控件 id 后操作控件
- position 是当前 item 在 fruitList 中的位置
- id 是当前 item 在 ListView 里的第几行的位置
ListView listView = findViewById(R.id.list_view);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent,View view,int position,long id) {
Fruit fruit = fruitList.get(position);
Toast.makeText(MainActivity.this,
fruit.getName(),Toast.LENGTH_SHORT).show();
}
});
步骤:
- 创建适配器的适配类,定义子项布局
- 创建自定义适配器,并提升运行效率
- 修改 MainActivity 代码,添加点击事件
5. 探究 RecyclerView:
- 相较于 ListView,RecyclerView 的扩展性更好,可以轻松实现纵向布局和横向布局等,同时还可以轻松实现子项中任意控件或布局的点击事件,优化了 ListView 的不足之处,代码的语义也更加清晰
基本用法:
- 在
app/build.gradle
的dependencies
中添加依赖库
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support:recyclerview-v7:26.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
- 在
activity_main.xml
中添加控件,由于RecyclerView
并不是内置在系统 SDK 中,所以需要写完整包路径
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_height="match_parent"
android:layout_width="match_parent"/>
- 定义一个和 ListView 中同样的实体类和子项布局,此处略过
- 自定义一个适配器,继承自
RecyclerView.Adapter
,并将泛型指定为FruitAdapter.ViewHolder
,ViewHolder 是定义在 FruitAdapter 中的内部类
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{
private List<Fruit> mFruitList;
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView fruitImage;
TextView fruitName;
/**
* @param view View 参数通常是 RecyclerView 子项的最外层布局,
* 因此可以通过 findViewById() 来获取布局内的控件实例。
*/
ViewHolder(View view){
super(view);
fruitImage = view.findViewById(R.id.fruit_image);
fruitName = view.findViewById(R.id.fruit_name);
}
}
FruitAdapter(List<Fruit> fruitList){
mFruitList = fruitList;
}
/**
* 此方法用于创建 ViewHolder 实例,在方法中将 fruit_item 布局加载出来,
* 然后创建一个 ViewHolder 实例,并把加载出来的布局传入到构造函数中,
* 最后将 ViewHolder 实例返回。
*
* @param parent 将新视图绑定到适配器位置后添加到其中的父布局,
* 在这里指 RecyclerView 的布局。
* @param viewType 新视图的视图类型,可以通过此参数扩展
* 不同类型的子项视图。
*/
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
// 为子项加载传入的 R.layout.fruit_item 这个子项布局
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.fruit_item, parent, false);
return new ViewHolder(view);
}
/**
* 此方法用于对子项的数据进行赋值,会在每个子项被滚动到屏幕内
* 的时候执行,这里通过 position 参数得到当前项的 Fruit 实例,
* 然后再将数据设置到 ViewHolder 的 ImageView 和 TextView 当中。
*
* @param holder 由 onCreateViewHolder() 方法中传来的返回值
* @param position 子项在适配器中的位置
*/
@Override
public void onBindViewHolder(ViewHolder holder, int position){
Fruit fruit = mFruitList.get(position);
holder.fruitImage.setImageResource(fruit.getImageId());
holder.fruitName.setText(fruit.getName());
}
/**
* 此方法用于告诉 RecyclerView 一共有多少子项
*/
@Override
public int getItemCount(){
return mFruitList.size();
}
}
- 修改 MainActivity 中的代码,在获取布局管理器之后可以调用布局管理器的方法
setOrientation()
来改变方向排列,传入LinearLayoutManager.HORIZONTAL
即可修改为水平方向排列
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 = findViewById(R.id.recycler_view);
/**
* 使用 LayoutManager 来指定 RecyclerView 的布局方式,这里使用线性布局,
* 可以实现和 ListView 一样的效果。
*/
LinearLayoutManager manager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(manager);
FruitAdapter adapter = new FruitAdapter(fruitList);
recyclerView.setAdapter(adapter);
}
private void initFruits(){
for(int i = 0; i < 100; i++){
Fruit apple = new Fruit("Apple", R.drawable.apple_pic);
fruitList.add(apple);
Fruit orange = new Fruit("Orange", R.drawable.orange_pic);
fruitList.add(orange);
Fruit banana = new Fruit("Banana", R.drawable.banana_pic);
fruitList.add(banana);
Fruit lemon = new Fruit("Lemon", R.drawable.lemon_pic);
fruitList.add(lemon);
Fruit strawberry = new Fruit("Strawberry", R.drawable.sstrawberry_pic);
fruitList.add(strawberry);
}
}
}
- 网格布局 & 瀑布流布局
GridLayoutManager manager = new GridLayoutManager();
(Context context, int spanCount);
—— 网格布局
StaggeredGridLayoutManager manager = new StaggeredGridLayoutManager();
(int spanCount, int orientation);
—— 瀑布流布局
点击事件
- 修改
FruitAdapter.java
即可
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{
private List<Fruit> mFruitList;
static class ViewHolder extends RecyclerView.ViewHolder{
View fruitView;
ImageView fruitImage;
TextView fruitName;
/**
* @param view View 参数通常是 RecyclerView 子项的最外层布局,
* 因此可以通过 findViewById() 来获取布局内的控件实例。
*/
ViewHolder(View view){
super(view);
fruitView = view;
fruitImage = view.findViewById(R.id.fruit_image);
fruitName = view.findViewById(R.id.fruit_name);
}
}
/**
* 此方法用于创建 ViewHolder 实例,在方法中将 fruit_item 布局加载出来,
* 然后创建一个 ViewHolder 实例,并把加载出来的布局传入到构造函数中,
* 最后将 ViewHolder 实例返回。
*
* @param parent 将新视图绑定到适配器位置后添加到其中的父布局,
* 在这里指 RecyclerView 的布局。
* @param viewType 新视图的视图类型,可以通过此参数扩展
* 不同类型的子项视图。
*/
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
// 为子项加载传入的 R.layout.fruit_item 这个子项布局
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) {
int position = holder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Toast.makeText(v.getContext(),"You clicked view " +
fruit.getName(), Toast.LENGTH_SHORT).show();
}
});
holder.fruitImage.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
int position = holder.getAdapterPosition();
Fruit fruit = mFruitList.get(position);
Toast.makeText(v.getContext(),"You clicked image " +
fruit.getName(), Toast.LENGTH_SHORT).show();
}
});
return holder;
}
}