************************
转载请注明出处:https://www.cnblogs.com/xiaofu007/p/10342462.html
************************
本篇内容看不懂的请先看上一篇博文写的:
【Android】10.0 UI开发(一)——如何编写程序界面、常见控件的使用
https://www.cnblogs.com/xiaofu007/p/10331880.html
1.0 内容涉及特别多,写的原因也是给自己捋思路。ListView使用好麻烦。
2.0 先看最终的运行结果:
3.0 第一界面是作为自己熟悉<ConstraintLayout>标签,练手做的,体会如下:
Guideline控件超级有用,它会提供一个可以设置百分比的虚线,其他控件可以基于这个控件来摆放,这样可以解决不同机型界面不兼容的问题。下面是我的手机(华为荣耀play)运行的画面:
3.1 这个界面总共加了6个控件:
ImageView :2张图片
EditText :2个文本输入框,虽然一个是密码输入框,但是因为学习资料没有介绍,就没用先。
Button :2个按钮控件,剩下的都是辅助线,<Guideline>组件相当于一个强制隐藏的view块控件:
这里加了9条辅助线,列的分别是25%,50%,75%,行的分别是30%,50%,70%
之前控件的大小控制百度到只能用权重,可是在这个新的ConstraintLayout标签中,权重没有意义……
因为Guideline控件是下面语句控制百分比(30%):
app:layout_constraintGuide_percent="0.3"
没有在其他控件尝试过这行语句在其他控件能不能用。
3.2 新建一个项目,名字叫什么无所谓,我的叫“Portable_Antitheft”
文件目录如下:
这里面我的上一篇博文也说了“ActivityCollector”类和“BaseActivity”类的作用,可以无视,也不贴代码了,作用一个是提供活动的一次性销毁方法,一个是随时监控返回栈栈顶的活动是什么,便于调试。
其中新建文件夹“.../res/drawable-xhdpi”,里面是这个程序开发所用的所有图片。
3.3 先看第一个布局文件的代码:
<?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="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@drawable/background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<ImageView
android:id="@+id/imageView2"
android:layout_width="149dp"
android:layout_height="140dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:src="@drawable/logo"
app:layout_constraintBottom_toTopOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline"
app:layout_constraintHorizontal_bias="0.503"
app:layout_constraintStart_toStartOf="@+id/guideline"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<EditText
android:id="@+id/username"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="邮箱/手机号"
android:maxLines="1"
app:layout_constraintBottom_toTopOf="@+id/guideline9"
app:layout_constraintEnd_toStartOf="@+id/guideline7"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/guideline6"
app:layout_constraintTop_toTopOf="@+id/guideline8"
app:layout_constraintVertical_bias="0.161" />
<EditText
android:id="@+id/passward"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:hint="密码 "
android:maxLines="1"
app:layout_constraintBottom_toTopOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline7"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/guideline6"
app:layout_constraintTop_toBottomOf="@+id/username"
app:layout_constraintVertical_bias="0.09" />
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<android.support.constraint.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.5" />
<Button
android:id="@+id/loginbutton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:text="登 录"
app:layout_constraintBottom_toTopOf="@+id/guideline9"
app:layout_constraintEnd_toStartOf="@+id/guideline7"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="@+id/guideline6"
app:layout_constraintTop_toTopOf="@+id/guideline2"
app:layout_constraintVertical_bias="0.2" />
<Button
android:id="@+id/registerbutton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="注 册"
app:layout_constraintEnd_toStartOf="@+id/guideline7"
app:layout_constraintStart_toStartOf="@+id/guideline6"
app:layout_constraintTop_toBottomOf="@+id/loginbutton" />
<android.support.constraint.Guideline
android:id="@+id/guideline6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.25" />
<android.support.constraint.Guideline
android:id="@+id/guideline7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.75" />
<android.support.constraint.Guideline
android:id="@+id/guideline8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.3" />
<android.support.constraint.Guideline
android:id="@+id/guideline9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.7" />
</android.support.constraint.ConstraintLayout>
这里用了一张普通图片当成背景图,也是通过xml文件的特性,简单点说,代码的先后顺序决定图片的叠加顺序。
这里手动改的只有一个id和app:layout_constraintGuide_percent="0.什么",因为辅助线加的时候默认多少dp,其他实现全靠Design中鼠标的拖拽。下面图解里面的内容,便于理解:
4.0 MainActivity.java
package com.example.portable_anti_theft;
import android.content.Intent;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.Button;
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
// 隐藏系统标题栏
ActionBar actionbar = getSupportActionBar();
if (actionbar != null){
actionbar.hide();
}
// 以下代码也可行,实现同样的效果
// if (getSupportActionBar() != null){
// getSupportActionBar().hide();
// }
Button loginbutton = (Button) findViewById(R.id.loginbutton);
loginbutton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,Main2Activity.class);
startActivity(intent);
}
});
}
}
这里简单的实现了两个功能:去掉了系统标题栏,再简单对“登录”按钮做了一个跳转,跳到第二个活动界面。
5.0 重点来了,activity_main2.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="match_parent"
tools:context=".Main2Activity">
<include
android:id="@+id/include"
layout="@layout/title" />
<ListView
android:id="@+id/list_view"
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="@+id/include"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline3"
app:layout_constraintVertical_bias="1.0" />
<android.support.constraint.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.08" />
</android.support.constraint.ConstraintLayout>
不要问我(o(╥﹏╥)o)代码什么意思,好些自己也没看懂,全靠拖拽。
这里的ListView控件最上面的边边,约束于8%的辅助线,这样就不会盖住线上面的东西——自制标题栏。大家看到源代码里面总共才插入三个标签,第二个是滚动列表,第三个是辅助线,第一个是重点,划线的那种。
<include
android:id="@+id/include"
layout="@layout/title" />
先不管这行代码,我们作为一个自创标题栏的尊严,首先不能每个界面都写一个自己的控件吧,当然希望只要想用自创标题栏的时候简单加载一下最好,也能更好的降低代码的耦合性。
在res/layout文件夹中新建title.xml布局文件,右击layout文件夹,new→Layout Resource File,
<?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="match_parent">
<Button
android:id="@+id/title_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_marginStart="8dp"
android:layout_marginTop="4dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:gravity="center"
android:text="后退"
android:textColor="#ffffff"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/title_edit"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<TextView
android:id="@+id/title_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:gravity="center"
android:text="随身监控"
android:textColor="#6A8759"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/title_edit"
app:layout_constraintHorizontal_bias="0.506"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<Button
android:id="@+id/title_edit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:gravity="center"
android:text="设置"
android:textColor="#ffffff"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
</android.support.constraint.ConstraintLayout>
3个控件:"后退"Button、"随身监控"TextView、"设置"Button。
拖拽加约束:
搞定,然后回到activity_main2.xml文件添加载入代码即可。
<include
android:id="@+id/include"
layout="@layout/title" />
没错,用include关键词就导入了,相当方便。
6.0 没有用数据库来读取,用数组模拟。Main2Activity.java
package com.example.portable_anti_theft;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class Main2Activity extends AppCompatActivity {
private List<Fruit> fruitList = new ArrayList<>();
private String[] data = {
"广西壮族自治区", "内蒙古自治区", "宁夏回族自治区", "西藏藏族自治区", "新疆维吾尔自治区", "香港特别行政区", "澳门特别行政区",
"北京市", "天津市", "上海市", "重庆市", "吉林省", "辽宁省", "黑龙江省",
"河北省", "河南省", "安徽省", "甘肃省", "山东省",
"湖南省", "湖北省", "江苏省", "浙江省", "江西省",
"云南省", "广西省", "贵州省", "海南省", "台湾省",};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ActionBar actionbar = getSupportActionBar();
if (actionbar != null) {
actionbar.hide();
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
Main2Activity.this,android.R.layout.simple_list_item_1,data
);
ListView listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(adapter);
}
运行:
6.0 这时候,优化代码,找足够行数的图片,放在drawable-xhdpi目录下,做出一开始图片带文字的效果。
6.1 新建布局文件fruit_item.xml,里面就1个图片控件,1个文字控件,两根辅助线:
<?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="match_parent">
<ImageView
android:id="@+id/fruit_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline4"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.016" />
<TextView
android:id="@+id/fruit_name"
android:layout_width="wrap_content"
android:layout_height="50sp"
android:layout_marginStart="16dp"
android:gravity="center_vertical"
app:layout_constraintBottom_toBottomOf="@+id/fruit_image"
app:layout_constraintStart_toStartOf="@+id/guideline4"
app:layout_constraintTop_toTopOf="@+id/fruit_image"
app:layout_constraintVertical_bias="0.0" />
<android.support.constraint.Guideline
android:id="@+id/guideline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.15" />
<android.support.constraint.Guideline
android:id="@+id/guideline5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.4" />
</android.support.constraint.ConstraintLayout>
辅助线都是垂直方向的15%、40%,能放进内容。
然后将图片约束于父节点到15%,将文本约束到图片、父节点、15%和40%
6.2 在src/main/java/com/example/portable_anti_theft目录下,新建Fruit.java,水果的构造函数:
package com.example.portable_anti_theft;
public class Fruit {
private String name;
private int imageId;
public Fruit(String name,int imageId){
this.imageId =imageId;
this.name = name;
}
public String getName(){
return name;
}
public int getImageId(){
return imageId;
}
}
因为原来的学习代码用的是水果作为内容,我这边改成省份而已。
代码里面可以看出,构造函数提供一个双参,名字和图片,并提供调用方法getName()和getImageId()。
6.3 同层目录下新建FruitAdapter.java
package com.example.portable_anti_theft;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class FruitAdapter extends ArrayAdapter<Fruit> {
private int resourceId;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Fruit fruit = getItem(position);//获取当前项的Fruit实例
View view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
ImageView fruitImage = (ImageView) view.findViewById(R.id.fruit_image);
TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);
fruitImage.setImageResource(fruit.getImageId());
fruitName.setText(fruit.getName());
return view;
}
public FruitAdapter(Context context, int textViewResourceId, List<Fruit> objects) {
super(context, textViewResourceId, objects);
resourceId = textViewResourceId;
}
}
这是个自定义适配器,继承自ArrayAdapter,并将泛型指向Fruit类
可见,提供一个三参的构造函数,第一个是活动或者说上下文,第二个是ListView子项布局的id,第三份传一个list数组,具体水果名称/数据。下面还将id赋值给resourceId。
Adapter是什么 :适配器,因为 ListView 是一个 View ,不能添加子项,因此在呈现数据的时候就需要某种工具将数据呈现在 ListView 上,而 Adapter 就能充当此角色。常用的 Adapter:ArrayAdapter、BaseAdapter等。
重写方法getView(),通过getItem()方法得到实例Fruit。然后LayoutInflater为这个子项加载传入的布局。 这里的LayoutInflater的inflate()方法接收3个参数,第3个意思是只让在父布局中声明的layout属性生效,但不会为这个View添加父布局。因为一旦View有了父布局之后,就不会添加到ListView中。
不过没理解也没关系(因为我也没理解),这是标准写法,想用的时候,两个字,盘他!
6.4 修改Main2Activity.java代码:
package com.example.portable_anti_theft;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
public class Main2Activity extends AppCompatActivity {
private List<Fruit> fruitList = new ArrayList<>();
private String[] data = {
"广西壮族自治区", "内蒙古自治区", "宁夏回族自治区", "西藏藏族自治区", "新疆维吾尔自治区", "香港特别行政区", "澳门特别行政区",
"北京市", "天津市", "上海市", "重庆市", "吉林省", "辽宁省", "黑龙江省",
"河北省", "河南省", "安徽省", "甘肃省", "山东省",
"湖南省", "湖北省", "江苏省", "浙江省", "江西省",
"云南省", "广西省", "贵州省", "海南省", "台湾省",};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
ActionBar actionbar = getSupportActionBar();
if (actionbar != null) {
actionbar.hide();
}
initFruits();//初始化水果数据
FruitAdapter adapter = new FruitAdapter(Main2Activity.this, R.layout.fruit_item, fruitList);
ListView listview = (ListView) findViewById(R.id.list_view);
listview.setAdapter(adapter);
}
private void initFruits() {
Fruit apple1 = new Fruit(data[0], R.drawable.png001);
fruitList.add(apple1);
Fruit apple2 = new Fruit(data[1], R.drawable.png002);
fruitList.add(apple2);
Fruit apple3 = new Fruit(data[2], R.drawable.png003);
fruitList.add(apple3);
Fruit apple4 = new Fruit(data[3], R.drawable.png004);
fruitList.add(apple4);
Fruit apple5 = new Fruit(data[4], R.drawable.png005);
fruitList.add(apple5);
Fruit apple6 = new Fruit(data[5], R.drawable.png006);
fruitList.add(apple6);
Fruit apple7 = new Fruit(data[6], R.drawable.png007);
fruitList.add(apple7);
Fruit apple8 = new Fruit(data[7], R.drawable.png008);
fruitList.add(apple8);
Fruit apple = new Fruit(data[8], R.drawable.png009);
fruitList.add(apple);
Fruit apple9 = new Fruit(data[9], R.drawable.png0010);
fruitList.add(apple9);
Fruit apple10 = new Fruit(data[10], R.drawable.png0011);
fruitList.add(apple10);
Fruit apple11 = new Fruit(data[11], R.drawable.png0012);
fruitList.add(apple11);
Fruit apple12 = new Fruit(data[12], R.drawable.png0013);
fruitList.add(apple12);
Fruit apple13 = new Fruit(data[13], R.drawable.png0014);
fruitList.add(apple13);
Fruit apple14 = new Fruit(data[14], R.drawable.png0015);
fruitList.add(apple14);
Fruit apple15 = new Fruit(data[15], R.drawable.png0016);
fruitList.add(apple15);
Fruit apple16 = new Fruit(data[16], R.drawable.png0017);
fruitList.add(apple16);
Fruit apple17 = new Fruit(data[17], R.drawable.png0018);
fruitList.add(apple17);
Fruit apple18 = new Fruit(data[18], R.drawable.png0019);
fruitList.add(apple18);
Fruit apple19 = new Fruit(data[19], R.drawable.png0020);
fruitList.add(apple19);
Fruit apple20 = new Fruit(data[20], R.drawable.png0021);
fruitList.add(apple20);
Fruit apple21 = new Fruit(data[21], R.drawable.png0022);
fruitList.add(apple21);
Fruit apple22 = new Fruit(data[22], R.drawable.png0023);
fruitList.add(apple22);
Fruit apple23 = new Fruit(data[23], R.drawable.png0024);
fruitList.add(apple23);
Fruit apple24 = new Fruit(data[24], R.drawable.png0025);
fruitList.add(apple24);
Fruit apple25 = new Fruit(data[25], R.drawable.png0026);
fruitList.add(apple25);
Fruit apple26 = new Fruit(data[26], R.drawable.png0027);
fruitList.add(apple26);
Fruit apple27 = new Fruit(data[27], R.drawable.png0028);
fruitList.add(apple27);
Fruit apple28 = new Fruit(data[28], R.drawable.png0029);
fruitList.add(apple28);
}
}
这里新建了一个方法initFruits(),作用就是初始化数据化载入,将名字和图片id传入。
初始化数据,然后创建FruitAdapter实例,传入3个参数,1个是活动本身,1个是摆放布局,1个空数据。
创建下拉列表,加载下拉列表数据,接着将FruitAdapter实例的数据加载到下拉列表中。
运行在开始已。
6.5 这里有个问题,在初始化方法initFruits()中,可见时一个一个数据加载的特别四班,可是图片id传入吗,没找到用参数传的办法,没办法一个个操作的。
7.0 这里需要对ListView的运行效率进行优化,在代码中,FruitAdapter中的getView()方法中,每次布局都用重新加载一遍,当列表快速滚动时,将会出现性能的瓶颈。
在getView()方法中还有一个convertView参数,这个参数用于将之前加载好的布局进行缓存,以便以后可以重用,修改FruitAdapter中getView()方法的代码:
public View getView(int position, View convertView, ViewGroup parent) {
Fruit fruit = getItem(position);
View view;
if (convertView != null){
view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
}else{
view = convertView;
}
TextView fruitName = (TextView) view.findViewById(R.id.fruit_name);
fruitImage.setImageResource(fruit.getImageId());
fruitName.setText(fruit.getName());
return view;
}
8.0 虽然在快速滚动中可以表现出更好的性能,但我们还可以更加优化,借助ViewHolder对每次调用getview()方法调用findViewById()方法来获取一次控件进行优化。
这里可以先参考:
Android ViewHolder 的基本使用
https://www.jianshu.com/p/a14feb480804
修改FruitAdapter中的代码: