当我们使用RecyclerView和ListView进行布局的时候,为了能够看到布局的实际情况我们需要不停的运行和构建app然后在手机或模拟器上查看布局效果,为了能够看到实际的布局效果我们还需要自己生成模拟数据,或者从网络获取数据,有时候我们只是轻微的修改了一下布局,为了看到具体的布局效果,我们也需要重新运行和构建app,这大大降低了我们的开发效率。更多的时候我们可能遇到的是UI设计师已经给出了UI,但是接口并没有写好,这个时候我们就只能在运行时自己用代码生成一些数据。那么有没有什么方式都够让我们不依赖接口提供数据而快速的搭建和预览RecyclerView和ListView的布局效果的方法呢。接下来我将分享一些我最近刚学习到的快速开发和预览ListView和RecyclerView布局的方法,希望能够帮助你在实际的开发中节省一些时间。
当我们使用RecyclerView或ListView进行布局的时候,让人心烦的问题是我们不能在Studio的布局预览中看到他的真实布局样式。比如说我们现在有一个显示用户个人信息的列表,在这个列表的每一个item中包含了该用户的头像,居住的城市,和加入服务的时间,以及一些用户的描述数据。它的布局像下面这样:
res/layout/item_part1.xml
-------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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="wrap_content">
<ImageView
android:id="@+id/avatar"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:contentDescription="@null"
app:layout_constraintDimensionRatio="h,1:1"
app:layout_constraintEnd_toStartOf="@id/name"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/name" />
<TextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constraintBottom_toTopOf="@+id/city"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="5"
app:layout_constraintStart_toEndOf="@id/avatar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed" />
<TextView
android:id="@+id/city"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constraintBottom_toTopOf="@id/description"
app:layout_constraintEnd_toStartOf="@id/date"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toEndOf="@id/avatar"
app:layout_constraintTop_toBottomOf="@+id/name" />
<TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:gravity="end"
app:layout_constraintBaseline_toBaselineOf="@id/city"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/city" />
<TextView
android:id="@+id/description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:ellipsize="end"
android:maxLines="3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/avatar"
app:layout_constraintTop_toBottomOf="@+id/city" />
</android.support.constraint.ConstraintLayout>
现在我们打开android studio的布局设计器和预览器将看到如下的效果:


res/layout/fragment_part.xml
-------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/item_part1" />
tools:listitem="@layout/item_part1"告诉RecyclerView使用布局item_part1作为它自己的item布局。添加这行代码后我们在android studio的预览器中看到的效果如下:

现在我们能够预览RecyclerView在预览器中的布局情况。但这依旧没有达到我们的实际期望。可能很多人都使用过tools:text="..."这个属性,他主要是协助我们在布局的时候快速预览TextView设置text属性的值的时候的显示效果。但是在这儿设置的text属性的值并不会被打包到真实的apk中。仅仅用于在android studio的布局预览器显示预览效果。下边我们给res/layout/item_part1.xml布局中的TextView都加上tools:text="..."属性代码如下:
res/layout/item_part1.xml
-----------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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="wrap_content">
<ImageView
android:id="@+id/avatar"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:contentDescription="@null"
app:layout_constraintDimensionRatio="h,1:1"
app:layout_constraintEnd_toStartOf="@id/name"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/name" />
<TextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constraintBottom_toTopOf="@+id/city"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="5"
app:layout_constraintStart_toEndOf="@id/avatar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="Mark Allison"/>
给RecyclerView的Item布局中的TextView添加tools:text="..."后的布局效果如下:

res/layout/item_part1.xml
-------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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="wrap_content">
<ImageView
android:id="@+id/avatar"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:contentDescription="@null"
app:layout_constraintDimensionRatio="h,1:1"
app:layout_constraintEnd_toStartOf="@id/name"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/name"
tools:src="@tools:sample/avatars" />
<TextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constraintBottom_toTopOf="@+id/city"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="5"
app:layout_constraintStart_toEndOf="@id/avatar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="@tools:sample/full_names" />
<TextView
android:id="@+id/city"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constraintBottom_toTopOf="@id/description"
app:layout_constraintEnd_toStartOf="@id/date"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toEndOf="@id/avatar"
app:layout_constraintTop_toBottomOf="@+id/name"
tools:text="@tools:sample/cities" />
<TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:gravity="end"
app:layout_constraintBaseline_toBaselineOf="@id/city"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/city"
tools:text="@tools:sample/date/ddmmyy" />
<TextView
android:id="@+id/description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:ellipsize="end"
android:maxLines="3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/avatar"
app:layout_constraintTop_toBottomOf="@+id/city"
tools:text="@tools:sample/lorem/random" />
</android.support.constraint.ConstraintLayout>
下边我们来看看在android studio的设计预览器中的最终效果

首先我们需要在项目中创建一个sample data目录:


然后我们在sampledata目录下创建一个名称叫"names"的文件用以存放用户的名字(这里文件名称你可以任意取一个,并不一定非得叫"names")然后我们在这个文件里边输入一些人的名字,像下边这样:
sampledata/names
-------------------------------------------------------------------------
Mark Allison
Sir Reginald Fortescue Crumplington-Smythe
Pablo Diego José Francisco de Paula Juan Nepomuceno María de los Remedios Cipriano de la Santísima Trinidad Ruiz y Picasso
Millicent Marbles
然后我们将item布局中用于显示用户名的TextView的tools:text的值设为tools:text="@tools:sample/names"具体的代码如下:
<TextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constraintBottom_toTopOf="@+id/city"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="5"
app:layout_constraintStart_toEndOf="@id/avatar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="@sample/names"/>
同理我们在sampledata目录下在新建一个目录取名叫"avatars"(这个名字是任意的)然后我们在avatars目录下存放几个VectorDrawables资源文件。如下:

<ImageView
android:id="@+id/avatar"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:contentDescription="@null"
app:layout_constraintDimensionRatio="h,1:1"
app:layout_constraintEnd_toStartOf="@id/name"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/name"
tools:src="@sample/avatars" />
然后我们此时在android studio 的预览器中预览一下RecyclerView的效果如下:

RecyclerView的实际显示效果就出来了,但是呢大家可能有注意到了,在上边我们为用户的用户名提供了一个names文件来提供用户的姓名数据,那我要给用户的地址提供数据不是得在新建一个为提供地址的文件,如果我有很多TextView那我不是要新建很多文件,这个一点都不高雅。别急其实呢sampledata是支持json格式的文件的。我们可以像我们的实际接口数据那样提供一些json格式的数据。
下边我们在sampledata目录中新建一个名为users.json文件,就像下边这样

然后呢我们在users.json文件中编辑一段json数据,就像下边这样:
{
"data": [
{
"city": "Hemel Hempstead, Hertfordshire, UK",
"avatar": "@sample/avatars"
},
{
"city": "Brokenwind, Aberdeenshire, UK",
"avatar": "@sample/avatars"
},
{
"city": "Málaga, España",
"avatar": "@sample/avatars"
},
{
"city": "Batchelors Bump, Essex, UK",
"avatar": "@sample/avatars"
}
]
}
然后我们可以在RecyclerView的item布局中引用这个json文件中的数据,像下边这样
res/layout/item_part1.xml
-------------------------------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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="wrap_content">
<ImageView
android:id="@+id/avatar"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:contentDescription="@null"
app:layout_constraintDimensionRatio="h,1:1"
app:layout_constraintEnd_toStartOf="@id/name"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/name"
tools:src="@sample/users.json/data/avatar" />
<TextView
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constraintBottom_toTopOf="@+id/city"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="5"
app:layout_constraintStart_toEndOf="@id/avatar"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"
tools:text="@sample/names" />
<TextView
android:id="@+id/city"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
app:layout_constraintBottom_toTopOf="@id/description"
app:layout_constraintEnd_toStartOf="@id/date"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toEndOf="@id/avatar"
app:layout_constraintTop_toBottomOf="@+id/name"
tools:text="@sample/users.json/data/city" />
<TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:gravity="end"
app:layout_constraintBaseline_toBaselineOf="@id/city"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/city"
tools:text="@tools:sample/date/ddmmyy" />
<TextView
android:id="@+id/description"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:ellipsize="end"
android:maxLines="3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/avatar"
app:layout_constraintTop_toBottomOf="@+id/city"
tools:text="@tools:sample/lorem/random" />
</android.support.constraint.ConstraintLayout>
我们来看看在android studio的设计器中的预览效果

源码地址:https://github.com/StylingAndroid/ToolTime/tree/Part2
参考文章: https://blog.stylingandroid.com/tool-time-part-1-2 https://blog.stylingandroid.com/tool-time-part-2