第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴

本章要点

使用Android提供的UI来编写程序界面。本章的内容就是学习UI方面的知识。

3.1 如何编写程序界面

Android种编写程序界面的方式:
1. 可视化编辑器(不推荐)
2. 编写XML代码(推荐)


3.2 常用控件的使用方法

创建一个UIWidgetTest项目

3.2.1 TextView

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 指文字的颜色

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第1张图片

3.2.2 Button

在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;
        }
    }
}

3.2.3 EditText

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;
        }
    }
}

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第2张图片

3.2.4 ImageView

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;
        }
    }
}

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第3张图片

3.2.5 ProgressBar

ProgressBar显示进度条,表示正在加载数据。

在activity_main.xml中的代码添加ProgressBar:

   <ProgressBar
        android:id="@+id/pb"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第4张图片

可见属性:
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;
        }
    }
}

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第5张图片

给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;
        }
    }
}

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第6张图片

3.2.6 AlertDialog

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() 显示对话框

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第7张图片

3.2.7 ProgressDialog

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会一直存在)

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第8张图片


3.3 详解4种基本布局

布局是一种可用用放很多控件,同时也可以嵌套布局的使用,来完成一些复杂的布局。

布局和控件的关系:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第9张图片

新建UILayoutTest项目。

3.3.1 线性布局

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>

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第10张图片

修改activity_main.xml中的属性代码如下:

android:orientation="horizontal"

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第11张图片

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>

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第12张图片

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>

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第13张图片

3.3.2 相对布局

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 该控件位于父布局控件的水平中心位置吗?

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第14张图片

相对于控件进行定位(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 该控件在哪个控件的下侧

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第15张图片

相对于控件定位(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 该控件与哪个控件的底对齐

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第16张图片

3.3.3 帧布局

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>

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第17张图片

文字和图片都位于左上角,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>

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第18张图片

3.3.4 百分比布局

百分比布局属性新增布局,提供了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>

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第19张图片

PercentRelativeLayout 用法非常相似,继承了RelativeLayout的所有属性。

Android 中还有AbsoluteLayout,TableLayout等属性(几乎不用)


3.4 系统控件不够用?创建自定义控件

常用控件和布局的继承结构:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第20张图片

新建UICustomViews项目。

3.4.1 引入布局

标题栏,引入布局。新建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();
        }
    }
}

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第21张图片

3.4.2 创建自定义控件

自定义控件解决重复性代码。
新建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();
            }
        });
    }

}

点击返回按钮销毁当前活动,点击修改按钮弹出文本。效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第22张图片


3.5 最常用和最难用的控件——ListView

ListView是Android最常用的控件之一。我们每天都在使用这个控件:查看QQ聊天记录,微博等等……

3.5.1 ListView的简单用法

新建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);
    }
}

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第23张图片

3.5.2 定制ListView的界面

每一种水果的旁边对应相应的图片。

定义实体类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);


        }
    }
}

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第24张图片

3.5.3 提升ListView的运行效率

修改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。

3.5.4 ListView的点击事件

修改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()方法。

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第25张图片


3.6 更强大的滚动控件——RecyclerView

RecyclerView时增强版的ListView。(Android官方推荐使用RecyclerView)。

新建RecyclerViewTest项目:

3.6.1 RecyclerView的基本用法

使用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);


        }
    }
}

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第26张图片

3.6.2 实现横向滚动和瀑布流布局

实现横向滚动的效果:
首先修改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);
    }
    ......
    }
}

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第27张图片

瀑布流布局的实现:
修改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();
    }
}

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第28张图片
StaggeredGridLayoutManager 就收2个参数,第一个参数是布局的列数,第二个参数是布局的排序方向。getRandowLenthName()获取1-20之间的随机数。

3.6.3 RecyclerView的点击事件

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()中注册点击事件。设置了图片和每个子项点击事件。运行效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第29张图片
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第30张图片


3.7 编写界面的最佳实践

编写聊天界面,创建UIBestPractive项目。

3.7.1 制作Nine-Path图片

特殊处理过的png图片。

3.7.2 编写精美的聊天布局

编写聊天界面,准备好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);
    }
}

效果图:
第二行代码学习笔记——第三章:软件也要拼脸蛋——UI开发的点点滴滴_第31张图片


3.8 小结与点评

掌握了基本控件,布局,自定义控件,以及ListView和RecyclerView的使用。

你可能感兴趣的:(第二行代码学习笔记)