1.0 内容涉及特别多,写的原因也是给自己捋思路。ListView使用好麻烦。
2.0 先看最终的运行结果:
image
image
3.0 第一界面是作为自己熟悉<ConstraintLayout>标签,练手做的,体会如下:
Guideline控件超级有用,它会提供一个可以设置百分比的虚线,其他控件可以基于这个控件来摆放,这样可以解决不同机型界面不兼容的问题。下面是我的手机(华为荣耀play)运行的画面:
image
3.1 这个界面总共加了6个控件:
ImageView :2张图片
EditText :2个文本输入框,虽然一个是密码输入框,但是因为学习资料没有介绍,就没用先。
Button :2个按钮控件,剩下的都是辅助线,<Guideline>组件相当于一个强制隐藏的view块控件:
image
这里加了9条辅助线,列的分别是25%,50%,75%,行的分别是30%,50%,70%
之前控件的大小控制百度到只能用权重,可是在这个新的ConstraintLayout标签中,权重没有意义……
因为Guideline控件是下面语句控制百分比(30%):
app:layout_constraintGuide_percent="0.3"
没有在其他控件尝试过这行语句在其他控件能不能用。
3.2 新建一个项目,名字叫什么无所谓,我的叫“Portable_Antitheft”
文件目录如下:
image
这里面我的上一篇博文也说了“ActivityCollector”类和“BaseActivity”类的作用,可以无视,也不贴代码了,作用一个是提供活动的一次性销毁方法,一个是随时监控返回栈栈顶的活动是什么,便于调试。
其中新建文件夹“.../res/drawable-xhdpi”,里面是这个程序开发所用的所有图片。
image
image
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:class="lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC" data-original="@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中鼠标的拖拽。下面图解里面的内容,便于理解:
image
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)代码什么意思,好些自己也没看懂,全靠拖拽。
image
这里的ListView控件最上面的边边,约束于8%的辅助线,这样就不会盖住线上面的东西——自制标题栏。大家看到源代码里面总共才插入三个标签,第二个是滚动列表,第三个是辅助线,第一个是重点,划线的那种。
<include android:id="@+id/include" layout="@layout/title" />
先不管这行代码,我们作为一个自创标题栏的尊严,首先不能每个界面都写一个自己的控件吧,当然希望只要想用自创标题栏的时候简单加载一下最好,也能更好的降低代码的耦合性。
在res/layout文件夹中新建title.xml布局文件,右击layout文件夹,newLayout 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。
拖拽加约束:
image
搞定,然后回到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); }
运行:
image
image
7.0 这时候,优化代码,找足够行数的图片,放在drawable-xhdpi目录下,做出一开始图片带文字的效果。
7.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%
7.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()。
7.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中。
不过没理解也没关系(因为我也没理解),这是标准写法,想用的时候,两个字,盘他!
7.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实例的数据加载到下拉列表中。
运行在开始已。
7.5 这里有个问题,在初始化方法initFruits()中,可见时一个一个数据加载的特别四班,可是图片id传入吗,没找到用参数传的办法,没办法一个个操作的。
8.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; }
作者:我睡醒刚刚
链接:https://www.jianshu.com/p/3dd37fd8d46e
共同學習,寫下你的評論
評論加載中...
作者其他優質文章