使用Android提供的UI来编写程序界面。本章的内容就是学习UI方面的知识。
Android种编写程序界面的方式:
1. 可视化编辑器(不推荐)
2. 编写XML代码(推荐)
创建一个UIWidgetTest项目
TextView的用法:
修改activity_main.xm中的代码,如下:
<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"
android:orientation="vertical">
<TextView
android:id="@+id/tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="This is TextView"
android:textColor="#00ff00"
android:textSize="24sp" />
LinearLayout>
属性:
android:id 当前控件唯一标识
android:layout_width和android:layout_height 控件的宽度和高度(match_parent(fill_parent不推荐),wrap_content)
android:text 显示的文本内容
android:gravity 指定文字的对齐方式(center,top,bottom,right,left)可以用”|“同时指定多个值。center同等于center_vertical|center_horizontal垂直和水平方向都居中对齐
android:textSize 指文字的大小(sp)
android:textColor 指文字的颜色
在activity_main.xml中加入Button:
<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"
android:orientation="vertical">
...
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button"
android:textAllCaps="false" />
LinearLayout>
属性:
android:textAllCaps true(大)/false(小) 默认true,英文字母大小写转换
MainActivity中为Button的点击事件注册一个监听器:
public class MainActivity extends AppCompatActivity {
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn= (Button) findViewById(R.id.btn);
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//添加逻辑代码
}
});
}
使用接口的方式来进行注册,如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn= (Button) findViewById(R.id.btn);
btn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn:
//添加逻辑代码
break;
default:
break;
}
}
}
EditText是程序与用户交互,允许在控件里输入和编辑内容,并作相应的处理。
EditText应用场景非常普遍,发短信,发微博,聊QQ等等……
在activity_main.xml中加入EditText,如下:
<EditText
android:id="@+id/et"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Type something here"
android:maxLines="2" />
属性:
android:hint 指定提示性文本
android:maxLines 指定最大行数
接下来我们通过点击按钮获取EditText中输入的内容,修改MainActivity中的代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn;
private EditText et;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn= (Button) findViewById(R.id.btn);
et= (EditText) findViewById(R.id.et);
btn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn:
String inputText = et.getText().toString();
Toast.makeText(this, inputText, Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
}
ImageView在界面展示图片的控件。”drawable“开头的目录下放图片,这个目录没有指定分辨率,所以不使用它来放图片。新建drawable-xhdpi目录来放图片。
我们把准备好的两张美女图片放进新建的drawable-xhdpi目录下。
在activity_main.xml中添加ImageView:
<ImageView
android:id="@+id/iv"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/img_1" />
属性:
android:src 指定ImageView的图片
通过代码动态的修改ImageView中的图片,修改MainActivity中的代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn;
private EditText et;
private ImageView iv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn= (Button) findViewById(R.id.btn);
et= (EditText) findViewById(R.id.et);
iv= (ImageView) findViewById(R.id.iv);
btn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn:
iv.setImageResource(R.drawable.img_2);
break;
default:
break;
}
}
}
ProgressBar显示进度条,表示正在加载数据。
在activity_main.xml中的代码添加ProgressBar:
<ProgressBar
android:id="@+id/pb"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
可见属性:
android:visibility (visible可见,默认值,invisible不可见,占位,gone,不可见,不占位)
代码控制可见性,setVisibility()。
按钮点击切换显示隐藏进度条,修改MainActivity中的代码如下所示:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btn;
private EditText et;
private ImageView iv;
private ProgressBar pb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn= (Button) findViewById(R.id.btn);
et= (EditText) findViewById(R.id.et);
iv= (ImageView) findViewById(R.id.iv);
pb= (ProgressBar) findViewById(R.id.pb);
btn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn:
if (pb.getVisibility()==View.GONE){
pb.setVisibility(View.VISIBLE);
}else{
pb.setVisibility(View.GONE);
}
break;
default:
break;
}
}
}
给ProgressBar指定不同样式,修改activity_main.xml中的代码如下:
<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"
android:orientation="vertical">
......
<ProgressBar
android:id="@+id/pb"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="100" />
LinearLayout>
属性:
style 设置进度条的样式
android:max 设置进度条最大的
点击按钮动态更新进度条,修改MainActivity中的代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
......
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn:
int progress = pb.getProgress();
progress=progress+10;
pb.setProgress(progress);
break;
default:
break;
}
}
}
AlertDialog弹出一个对话框,提示一些非常重要内容或者警告信息。
修改MainActivity中的代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
......
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn:
AlertDialog.Builder dialog=new AlertDialog.Builder(MainActivity.this);
dialog.setTitle("This is Dialog");
dialog.setMessage("Something imporent.");
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;
}
}
}
通过AlertDialog.Builder创建AlertDialog的实例,设置标题,内容,等属性……
setPositiveButton() 确定按钮的点击事件
setNegativeButton() 取消按钮的点击
show() 显示对话框
ProgressDialog与AlertDialog不同的是:ProgressDialog会在对话框显示进度条。表示耗时操作,让用户等待。
修改MainActivity中的代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
......
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn:
ProgressDialog progressDialog=new ProgressDialog(MainActivity.this);
progressDialog.setTitle("This is a ProgressDialog");
progressDialog.setMessage("Something imporent");
progressDialog.setCancelable(true);
progressDialog.show();
break;
default:
break;
}
}
}
setCancelable true/false (可以通过Back键返回)/(不可以返回,加载完必须调用dismiss()来关闭对话框,ProgressDialog会一直存在)
布局是一种可用用放很多控件,同时也可以嵌套布局的使用,来完成一些复杂的布局。
新建UILayoutTest项目。
LinearLayout称线性布局,将它所包含的在线性方向上依此排列。
android:orientation 指定排列方向,vertical(垂直方向排列),horizontal(水平方向排列)
修改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">
<Button
android:id="@+id/btn_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1" />
<Button
android:id="@+id/btn_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button2" />
<Button
android:id="@+id/btn_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button3" />
LinearLayout>
修改activity_main.xml中的属性代码如下:
android:orientation="horizontal"
android:gravity和android:layout_gravity区别:
android:gravity 指文字在组件中的对齐方式
android:layout_gravity 指控件在布局中对齐方式
当排列方向为horizontal时,只有垂直方向对齐方式会生效。当为vertical时,只有水平方向对齐方式才会生效。
修改activity_main中的代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
android:id="@+id/btn_1"
android:layout_gravity="top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1" />
<Button
android:id="@+id/btn_2"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button2" />
<Button
android:id="@+id/btn_3"
android:layout_gravity="bottom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button3" />
LinearLayout>
android:layout_weight 比例方式控制组件的大小 。我们来编写消息发送界面,修改activity_main中的代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<EditText
android:id="@+id/et"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<Button
android:id="@+id/btn"
android:text="Send"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
LinearLayout>
RelativeLayout称相对布局,通过相对定位让控件出现在布局的任何位置。
相对于父布局进行定位,修改activity_main.xml中的代码如下所示:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn_1"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1" />
<Button
android:id="@+id/btn_2"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button2" />
<Button
android:layout_centerInParent="true"
android:id="@+id/btn_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button3" />
<Button
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true"
android:id="@+id/btn_4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button4" />
<Button
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:id="@+id/btn_5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button5" />
RelativeLayout>
属性:
layout_alignParentRight 该控件与父布局控件的右对齐吗?
layout_alignParentLeft 该控件与父布局控件的左对齐吗?
layout_alignParentTop 该控件与父布局控件的顶端对齐吗?
layout_alignParentBottom 该控件与父布局控件的底部对齐吗?
layout_centerInParent 该控件位于父布局控件的中心位置吗?
layout_centerVertical 该控件位于父布局控件的垂直中心位置吗?
layout_centerHorizontal 该控件位于父布局控件的水平中心位置吗?
相对于控件进行定位(1),修改activity_main.xml中的代码如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_centerInParent="true"
android:id="@+id/btn_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button3" />
<Button
android:id="@+id/btn_1"
android:layout_above="@id/btn_3"
android:layout_toLeftOf="@id/btn_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1" />
<Button
android:id="@+id/btn_2"
android:layout_toRightOf="@id/btn_3"
android:layout_above="@id/btn_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button2" />
<Button
android:layout_toLeftOf="@id/btn_3"
android:layout_below="@id/btn_3"
android:id="@+id/btn_4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button4" />
<Button
android:layout_toRightOf="@id/btn_3"
android:layout_below="@id/btn_3"
android:id="@+id/btn_5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button5" />
RelativeLayout>
属性:
layout_toRightOf 该控件在哪个控件的右侧
layout_toLeftOf 该控件在哪个控件的左侧
layout_above 该控件在哪个控件的上侧
layout_below 该控件在哪个控件的下侧
相对于控件定位(2),修改activity_main.xml中的代码如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_centerInParent="true"
android:id="@+id/btn_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button3" />
<Button
android:id="@+id/btn_1"
android:layout_alignLeft="@id/btn_3"
android:layout_above="@id/btn_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1" />
<Button
android:id="@+id/btn_2"
android:layout_alignTop="@id/btn_3"
android:layout_toRightOf="@id/btn_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button2" />
<Button
android:layout_alignBottom="@id/btn_3"
android:layout_toLeftOf="@id/btn_3"
android:id="@+id/btn_4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button4" />
<Button
android:layout_alignRight="@id/btn_3"
android:layout_below="@id/btn_3"
android:id="@+id/btn_5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button5" />
RelativeLayout>
属性:
layout_alignRight 该控件与哪个控件的右对齐
layout_alignLeft 该控件与哪个控件的左对齐
layout_alignTop 该控件与哪个控件的顶对齐
layout_alignBottom 该控件与哪个控件的底对齐
FrameLayout称帧布局(简单布局)。没有定位方式,所以控件默认摆放左上角。
接下来我们来修改activity_main.xml中的文件如下:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv"
android:text="This is TextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/iv"
android:src="@mipmap/ic_launcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
FrameLayout>
文字和图片都位于左上角,ImageView在TextView后,因此图片压在文字上面。
使用 android:layout_gravity 属性指定控件在布局中的对齐方式。修改activity_main中的代码如下:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv"
android:text="This is TextView"
android:layout_gravity="left"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:id="@+id/iv"
android:layout_gravity="right"
android:src="@mipmap/ic_launcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
FrameLayout>
百分比布局属性新增布局,提供了PercentFrameLayout和PercentRelativeLayout两种全新的布局,它俩是FrameLayout和RelativeLayout的功能,继承了所有的属性。
百分比布局的使用:
添加依赖
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:24.2.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
testCompile 'junit:junit:4.12'
compile 'com.android.support:percent:24.2.1'
}
修改activity_main中的布局:
<android.support.percent.PercentFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Button
app:layout_widthPercent="50%"
app:layout_heightPercent="50%"
android:layout_gravity="left|top"
android:id="@+id/btn_1"
android:text="Button1" />
<Button
app:layout_widthPercent="50%"
app:layout_heightPercent="50%"
android:layout_gravity="right|top"
android:id="@+id/btn_2"
android:text="Button2" />
<Button
app:layout_widthPercent="50%"
app:layout_heightPercent="50%"
android:layout_gravity="left|bottom"
android:id="@+id/btn_3"
android:text="Button3" />
<Button
app:layout_widthPercent="50%"
app:layout_heightPercent="50%"
android:layout_gravity="right|bottom"
android:id="@+id/btn_4"
android:text="Button4" />
android.support.percent.PercentFrameLayout>
PercentRelativeLayout 用法非常相似,继承了RelativeLayout的所有属性。
Android 中还有AbsoluteLayout,TableLayout等属性(几乎不用)
新建UICustomViews项目。
标题栏,引入布局。新建title_layout.xml代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#c2c2c2">
<Button
android:text="Back"
android:textColor="#FFFFFF"
android:layout_gravity="center"
android:layout_margin="5dp"
android:id="@+id/btn_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:textSize="24sp"
android:layout_gravity="center"
android:text="This is Title"
android:gravity="center"
android:textColor="#FFFFFF"
android:id="@+id/tv_title"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content" />
<Button
android:text="Edit"
android:layout_margin="5dp"
android:textColor="#FFFFFF"
android:layout_gravity="center"
android:id="@+id/btn_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
LinearLayout>
修改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">
<include layout="@layout/title_layout"/>
LinearLayout>
include 引入标题栏布局。
在MainActivity中隐藏系统自带的标题栏,代码如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActionBar actionBar=getSupportActionBar();
if (actionBar!=null){
actionBar.hide();
}
}
}
自定义控件解决重复性代码。
新建TitleLayout类继承自LinearLayout,代码如下:
public class TitleLayout extends LinearLayout {
public TitleLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.title_layout,this);
}
}
重修2个参数的构造函数,动态加载布局:LayoutInflater.from(上下文对象).inflate(加载布局的文件Id,加载好的布局再添加父布局);
修改activity_main中的代码如下:
"1.0" encoding="utf-8"?>
"http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.hjw.uilayouttest.TitleLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">com.example.hjw.uilayouttest.TitleLayout>
效果与引用布局方式的效果一样。
为标题栏中的按钮注册点击事件,TitleLayout中的代码如下:
public class TitleLayout extends LinearLayout {
private Button btn_back,btn_edit;
public TitleLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.title_layout,this);
btn_back= (Button) findViewById(R.id.btn_back);
btn_edit= (Button) findViewById(R.id.btn_edit);
btn_back.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
((Activity)getContext()).finish();
}
});
btn_edit.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(getContext(), "You clicked Edit button", Toast.LENGTH_SHORT).show();
}
});
}
}
ListView是Android最常用的控件之一。我们每天都在使用这个控件:查看QQ聊天记录,微博等等……
新建ListViewTest项目,修改activity_main.xml中的布局如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/mListView"
android:layout_width="match_parent"
android:layout_height="match_parent">ListView>
LinearLayout>
修改MainActivity中的代码如下:
public class MainActivity extends AppCompatActivity {
//数据源
private String[] data={"Apple","Banana","Orange","Watermelon",
"Pear","Grape","Pineapple","Strawberry","Cherry","Mango",
"Apple","Banana","Orange","Watermelon",
"Pear","Grape","Pineapple","Strawberry","Cherry","Mango"};
private ListView mListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView= (ListView) findViewById(R.id.mListView);
//创建适配器
ArrayAdapter adapter=new ArrayAdapter(this,android.R.layout.simple_list_item_1,data);
//关联适配器
mListView.setAdapter(adapter);
}
}
每一种水果的旁边对应相应的图片。
定义实体类Fruit,代码如下:
public class Fruit {
private String name;
private int imgId;
public Fruit(String name, int imgId) {
this.name = name;
this.imgId = imgId;
}
public String getName() {
return name;
}
public int getImgId() {
return imgId;
}
}
自定义布局fruit_item.xml文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_parent">
<ImageView
android:id="@+id/img_fruit"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_fruit"
android:layout_gravity="center_vertical"
android:layout_marginLeft="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
LinearLayout>
创建自定义适配器FruitAdapter继承自ArrayAdapter,泛型指定为Fruit类。代码如下:
public class FruitAdapter extends ArrayAdapter<Fruit> {
private int resourceId;
private ImageView img_fruit;
private TextView tv_fruit;
public FruitAdapter(@NonNull Context context, @LayoutRes int textViewResourceId, @NonNull List objects) {
super(context, textViewResourceId, objects);
resourceId=textViewResourceId;
}
@NonNull
@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);
img_fruit= (ImageView) view.findViewById(R.id.img_fruit);
tv_fruit= (TextView) view.findViewById(R.id.tv_fruit);
img_fruit.setImageResource(fruit.getImgId());
tv_fruit.setText(fruit.getName());
return view;
}
}
接下来我们来修改MainActivity中的代码,如下:
public class MainActivity extends AppCompatActivity {
private ListView mListView;
private List mData=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView= (ListView) findViewById(R.id.mListView);
//添加数据源
addData();
//创建适配器
FruitAdapter adapter=new FruitAdapter(this,R.layout.fruit_item,mData);
//关联适配器
mListView.setAdapter(adapter);
}
private void addData() {
for (int i = 0; i < 2; i++) {
Fruit apple=new Fruit("Apple",R.drawable.apple_pic);
mData.add(apple);
Fruit banana=new Fruit("Banana",R.drawable.banana_pic);
mData.add(banana);
Fruit orange=new Fruit("Orange",R.drawable.orange_pic);
mData.add(orange);
Fruit watermelon=new Fruit("Watermelon",R.drawable.watermelon_pic);
mData.add(watermelon);
Fruit pear=new Fruit("Pear",R.drawable.pear_pic);
mData.add(pear);
Fruit grape=new Fruit("Grape",R.drawable.grape_pic);
mData.add(grape);
Fruit pineapple=new Fruit("Pineapple",R.drawable.pineapple_pic);
mData.add(pineapple);
Fruit strawberry=new Fruit("Strawberry",R.drawable.strawberry_pic);
mData.add(strawberry);
Fruit cherry=new Fruit("Cherry",R.drawable.cherry_pic);
mData.add(cherry);
Fruit mango=new Fruit("Mango",R.drawable.mango_pic);
mData.add(mango);
}
}
}
修改FruitAdapter中的代码如下:
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
Fruit fruit=getItem(position); //获取当前项的Fruit实例
ViewHolder viewHolder;
View view;
if (convertView==null){
view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
viewHolder=new ViewHolder();
viewHolder.img_fruit= (ImageView) view.findViewById(R.id.img_fruit);
viewHolder.tv_fruit= (TextView) view.findViewById(R.id.tv_fruit);
view.setTag(viewHolder); //将ViewHolder储存在View中
}else{
view=convertView;
viewHolder= (ViewHolder) view.getTag(); //重新获取ViewHolder
}
viewHolder.img_fruit.setImageResource(fruit.getImgId());
viewHolder.tv_fruit.setText(fruit.getName());
return view;
}
class ViewHolder{
ImageView img_fruit;
TextView tv_fruit;
}
如果getView()中的convertView为空则去使用LayoutInflater加载布局,否则直接对convertView进行重用。创建ViewHolder对象,用于存放所有控件的实例,调用View的seTag()方法,将ViewHolder对象储存在View中,当convertView不为null的时候,则调用view的getTag(),重新取出ViewHolder。
修改MainActivity中的点击时间,代码如下:
public class MainActivity extends AppCompatActivity {
private ListView mListView;
private List mData=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView= (ListView) findViewById(R.id.mListView);
//添加数据源
addData();
//创建适配器
FruitAdapter adapter=new FruitAdapter(this,R.layout.fruit_item,mData);
//关联适配器
mListView.setAdapter(adapter);
//添加监听事件
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view, int position, long id) {
Fruit fruit=mData.get(position);
Toast.makeText(MainActivity.this, fruit.getName(), Toast.LENGTH_SHORT).show();
}
});
}
......
}
}
使用setOnItemClickListener()为ListView注册了一个监听器,当用户点击子项时就会调用onItemClick()方法。
RecyclerView时增强版的ListView。(Android官方推荐使用RecyclerView)。
新建RecyclerViewTest项目:
使用RecyclerView,首先我们需要添加它的依赖库:
compile 'com.android.support:recyclerview-v7:24.2.1'
修改activity_main.xml中的代码:
<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="com.example.hjw.recyclerviewtest.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/mRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent">android.support.v7.widget.RecyclerView>
LinearLayout>
实现与ListView同样的效果,我们把ListViewTest项目中的图片,Fruit类和fruit_item.xml复制过来。
新建FruitAdapter类,继承自RecyclerView.Adapter,指定泛型为FruitAdapter.ViewHolder,ViewHolder是内部类,必须重写3个方法onCreateViewHolder(),onBindViewHolder(),getItemCount()。代码如下:
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
private List mData;
public FruitAdapter(List mData) {
this.mData = mData;
}
@Override
public 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(ViewHolder holder, int position) {
//对组件进行赋值
Fruit fruit=mData.get(position);
holder.img_fruit.setImageResource(fruit.getImgId());
holder.tv_fruit.setText(fruit.getName());
}
@Override
public int getItemCount() {
return mData.size();
}
static class ViewHolder extends RecyclerView.ViewHolder{
//初始化控件
ImageView img_fruit;
TextView tv_fruit;
public ViewHolder(View itemView) {
super(itemView);
img_fruit= (ImageView) itemView.findViewById(R.id.img_fruit);
tv_fruit= (TextView) itemView.findViewById(R.id.tv_fruit);
}
}
}
修改MainActivity中的代码如下:
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private List mData=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView= (RecyclerView) findViewById(R.id.mRecyclerView);
//添加数据
initFruits();
//设置布局
LinearLayoutManager manager=new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(manager);
//添加适配器
FruitAdapter adapter=new FruitAdapter(mData);
mRecyclerView.setAdapter(adapter);
}
private void initFruits() {
for (int i = 0; i < 2; i++) {
Fruit apple=new Fruit("Apple",R.drawable.apple_pic);
mData.add(apple);
Fruit banana=new Fruit("Banana",R.drawable.banana_pic);
mData.add(banana);
Fruit orange=new Fruit("Orange",R.drawable.orange_pic);
mData.add(orange);
Fruit watermelon=new Fruit("Watermelon",R.drawable.watermelon_pic);
mData.add(watermelon);
Fruit pear=new Fruit("Pear",R.drawable.pear_pic);
mData.add(pear);
Fruit grape=new Fruit("Grape",R.drawable.grape_pic);
mData.add(grape);
Fruit pineapple=new Fruit("Pineapple",R.drawable.pineapple_pic);
mData.add(pineapple);
Fruit strawberry=new Fruit("Strawberry",R.drawable.strawberry_pic);
mData.add(strawberry);
Fruit cherry=new Fruit("Cherry",R.drawable.cherry_pic);
mData.add(cherry);
Fruit mango=new Fruit("Mango",R.drawable.mango_pic);
mData.add(mango);
}
}
}
实现横向滚动的效果:
首先修改fruit_item.xml中的代码:
<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/img_fruit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<TextView
android:id="@+id/tv_fruit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp" />
LinearLayout>
修改MainActivity中的代码如下:
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private List mData=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView= (RecyclerView) findViewById(R.id.mRecyclerView);
//添加数据
initFruits();
//设置布局
LinearLayoutManager manager=new LinearLayoutManager(this);
//设置布局的方向
manager.setOrientation(LinearLayoutManager.HORIZONTAL);
mRecyclerView.setLayoutManager(manager);
//添加适配器
FruitAdapter adapter=new FruitAdapter(mData);
mRecyclerView.setAdapter(adapter);
}
......
}
}
瀑布流布局的实现:
修改fruit_item.xml中的代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_margin="5dp">
<ImageView
android:id="@+id/img_fruit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" />
<TextView
android:id="@+id/tv_fruit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:layout_marginTop="10dp" />
LinearLayout>
修改MainActivity中的代码:
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private List mData=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRecyclerView= (RecyclerView) findViewById(R.id.mRecyclerView);
//添加数据
initFruits();
//设置布局
StaggeredGridLayoutManager manager=new StaggeredGridLayoutManager(3,StaggeredGridLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(manager);
//添加适配器
FruitAdapter adapter=new FruitAdapter(mData);
mRecyclerView.setAdapter(adapter);
}
private void initFruits() {
for (int i = 0; i < 2; i++) {
Fruit apple=new Fruit(getRandowLenthName("Apple"),R.drawable.apple_pic);
mData.add(apple);
Fruit banana=new Fruit(getRandowLenthName("Banana"),R.drawable.banana_pic);
mData.add(banana);
Fruit orange=new Fruit(getRandowLenthName("Orange"),R.drawable.orange_pic);
mData.add(orange);
Fruit watermelon=new Fruit(getRandowLenthName("Watermelon"),R.drawable.watermelon_pic);
mData.add(watermelon);
Fruit pear=new Fruit(getRandowLenthName("Pear"),R.drawable.pear_pic);
mData.add(pear);
Fruit grape=new Fruit(getRandowLenthName("Grape"),R.drawable.grape_pic);
mData.add(grape);
Fruit pineapple=new Fruit(getRandowLenthName("Pineapple"),R.drawable.pineapple_pic);
mData.add(pineapple);
Fruit strawberry=new Fruit(getRandowLenthName("Strawberry"),R.drawable.strawberry_pic);
mData.add(strawberry);
Fruit cherry=new Fruit(getRandowLenthName("Cherry"),R.drawable.cherry_pic);
mData.add(cherry);
Fruit mango=new Fruit(getRandowLenthName("Mango"),R.drawable.mango_pic);
mData.add(mango);
}
}
private String getRandowLenthName(String name){
Random random=new Random();
int lenth=random.nextInt(20)+1;
StringBuilder builder=new StringBuilder();
for (int i = 0; i < lenth; i++) {
builder.append(name);
}
return builder.toString();
}
}
效果图:
StaggeredGridLayoutManager 就收2个参数,第一个参数是布局的列数,第二个参数是布局的排序方向。getRandowLenthName()获取1-20之间的随机数。
RecyclerView中的点击事件,修改FruitAdapter中的代码:
public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder> {
private List mData;
public FruitAdapter(List mData) {
this.mData = mData;
}
@Override
public ViewHolder onCreateViewHolder(final 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 v) {
int position = holder.getAdapterPosition();
Fruit fruit=mData.get(position);
Toast.makeText(v.getContext(),"you clicked view "+ fruit.getName(), Toast.LENGTH_SHORT).show();
}
});
holder.img_fruit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = holder.getAdapterPosition();
Fruit fruit=mData.get(position);
Toast.makeText(v.getContext(), "you clicked image "+fruit.getName(), Toast.LENGTH_SHORT).show();
}
});
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
//对组件进行赋值
Fruit fruit=mData.get(position);
holder.img_fruit.setImageResource(fruit.getImgId());
holder.tv_fruit.setText(fruit.getName());
}
@Override
public int getItemCount() {
return mData.size();
}
static class ViewHolder extends RecyclerView.ViewHolder{
//初始化控件
View fruitView;
ImageView img_fruit;
TextView tv_fruit;
public ViewHolder(View itemView) {
super(itemView);
fruitView=itemView;
img_fruit= (ImageView) itemView.findViewById(R.id.img_fruit);
tv_fruit= (TextView) itemView.findViewById(R.id.tv_fruit);
}
}
}
在ViewHolder中添加子项最外层fruitView布局的实例,在onCreateViewHolder()中注册点击事件。设置了图片和每个子项点击事件。运行效果图:
编写聊天界面,创建UIBestPractive项目。
特殊处理过的png图片。
编写聊天界面,准备好png图片,作为接受发消息的背景图。
添加RecyclerView依赖:
compile 'com.android.support:recyclerview-v7:24.2.1'
放置RecyclerView来显示聊天布局的内容,EditText用于输入消息,Button用于发送消息,修改activity_main.xml中的代码如下:
<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"
android:background="#d8e0e8"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/mRecyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">android.support.v7.widget.RecyclerView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/et_input_msg"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button
android:id="@+id/btn_send"
android:text="Send"
android:textAllCaps="false"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
LinearLayout>
LinearLayout>
定义消息实体类,Msg类,只有两个字段,content消息的内容,type消息的类型,TYPE_RECEIVED 接收消息,TYPE_SENT发送消息,代码如下:
public class Msg {
public static final int TYPE_RECEIVED=0;
public static final int TYPE_SENT=1;
private String content;
private int type;
public Msg(String content, int type) {
this.content = content;
this.type = type;
}
public String getContent() {
return content;
}
public int getType() {
return type;
}
}
编写RecyclerView子选项的布局,接收消息居左对齐,发送消息居右对齐,新建msg_item.xml,代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout
android:id="@+id/left_layout"
android:layout_width="wrap_content"
android:background="@drawable/message_left"
android:layout_gravity="left"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_left_msg"
android:textColor="#FFFFFF"
android:layout_margin="10dp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
LinearLayout>
<LinearLayout
android:id="@+id/right_layout"
android:layout_width="wrap_content"
android:background="@drawable/message_right"
android:layout_gravity="right"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_right_msg"
android:textColor="#FFFFFF"
android:layout_margin="10dp"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
LinearLayout>
LinearLayout>
创建MsgAdapter适配器,代码如下:
public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.ViewHolder> {
private List mData;
private Context context;
public MsgAdapter(Context context , List mData) {
this.context = context;
this.mData = mData;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view= LayoutInflater.from(context).inflate(R.layout.msg_item,parent,false);
ViewHolder holder=new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
Msg msg=mData.get(position);
if (msg.getType()==Msg.TYPE_RECEIVED){
//如果是收消息,显示左边布局,隐藏右边的布局
holder.left_layout.setVisibility(View.VISIBLE);
holder.right_layout.setVisibility(View.GONE);
holder.tv_left_msg.setText(msg.getContent());
}else if(msg.getType()==Msg.TYPE_SENT){
//如果是发消息,显示右边布局,隐藏左边的布局
holder.left_layout.setVisibility(View.GONE);
holder.right_layout.setVisibility(View.VISIBLE);
holder.tv_right_msg.setText(msg.getContent());
}
}
@Override
public int getItemCount() {
return mData.size();
}
static class ViewHolder extends RecyclerView.ViewHolder{
LinearLayout left_layout,right_layout;
TextView tv_left_msg,tv_right_msg;
public ViewHolder(View itemView) {
super(itemView);
left_layout= (LinearLayout) itemView.findViewById(R.id.left_layout);
right_layout= (LinearLayout) itemView.findViewById(R.id.right_layout);
tv_left_msg= (TextView) itemView.findViewById(R.id.tv_left_msg);
tv_right_msg= (TextView) itemView.findViewById(R.id.tv_right_msg);
}
}
}
修改MainActivity中的代码如下:
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private EditText et_input_msg;
private Button btn_send;
private List mData=new ArrayList<>();
private Msg msg;
private MsgAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化控件
mRecyclerView= (RecyclerView) findViewById(R.id.mRecyclerView);
et_input_msg= (EditText) findViewById(R.id.et_input_msg);
btn_send= (Button) findViewById(R.id.btn_send);
//添加数据源
addData();
//设置布局样式
LinearLayoutManager layoutManager=new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(layoutManager);
//添加适配器
adapter = new MsgAdapter(this,mData);
mRecyclerView.setAdapter(adapter);
//添加监听器
btn_send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String content = et_input_msg.getText().toString();
if (!"".equals(content)){
msg=new Msg(content,Msg.TYPE_SENT);
mData.add(msg);
adapter.notifyItemInserted(mData.size()-1); //当有新消息时,刷新RecyclerListView
mRecyclerView.scrollToPosition(mData.size()-1); //将RecyclerListView定义到最后一行
et_input_msg.setText(""); //清空文本输入框
}
}
});
}
private void addData() {
msg = new Msg("Hello,ZhangSan",Msg.TYPE_RECEIVED);
mData.add(msg);
msg =new Msg("Hello,LiSi",Msg.TYPE_SENT);
mData.add(msg);
msg = new Msg("How are you?",Msg.TYPE_RECEIVED);
mData.add(msg);
}
}
掌握了基本控件,布局,自定义控件,以及ListView和RecyclerView的使用。