高级控件与屏幕适配
本篇文章主要是记录一下高级控件ListView和CardView的使用方式和注意事项,虽然目前都已经用RecyclerView替代了ListView但是了解其中的原理和优化还是有必要的,关于ListView的原理和真正意义上的优化在后面会专门写一片文章来讲述,本篇只谈其具体使用与必须优化的方式。至于CardView其实用的还是比较多的,可以看到我的小Demo实现的效果还是很不错!最后涉及到了一些Android屏幕适配问题的解决方案。
ListView
Displays a vertically-scrollable collection of views, where each view is positioned immediatelybelow the previous view in the list. For a more modern, flexible, and performant approach to displaying lists, use android.support.v7.widget.RecyclerView.
ListView的基本使用
ListView使用步骤如下:
1、在Layout中创建ListView 2、创建每一行的layout 3、创建每一行的数据 4、用adapter将数据填充到每一行的视图中
条目布局文件 item_app_list.xml
1<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout
3 xmlns:android="http://schemas.android.com/apk/res/android"
4 xmlns:tools="http://schemas.android.com/tools"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent"
7 android:padding="10dp"
8 android:orientation="horizontal">
9
10 <ImageView
11 android:id="@+id/app_icon_iv"
12 android:src="@mipmap/ic_launcher"
13 android:layout_width="40dp"
14 android:layout_height="40dp"/>
15
16 <TextView
17 android:id="@+id/app_name_tv"
18 android:textSize="20sp"
19 android:paddingLeft="10dp"
20 android:gravity="center_vertical"
21 android:text="@string/app_name"
22 android:layout_width="match_parent"
23 android:layout_height="40dp"/>
24</LinearLayout>
AppListActivity.java
1public class AppListActivity extends AppCompatActivity {
2
3 private List<String> appNameList;
4
5 @Override
6 protected void onCreate(Bundle savedInstanceState) {
7 super.onCreate(savedInstanceState);
8 setContentView(R.layout.activity_app_list);
9
10 ListView listView = findViewById(R.id.app_lv);
11 appNameList = Arrays.asList("QQ", "微信", "牛客", "招商银行", "支付宝");
12
13 //listView.setAdapter(new AppListAdapterBase());
14 listView.setAdapter(new AppListAdapter(getAppInfo()));
15 }
16
17 // 获取所有的应用信息
18 private List<ResolveInfo> getAppInfo(){
19 Intent intent = new Intent(Intent.ACTION_MAIN, null);
20 intent.addCategory(Intent.CATEGORY_LAUNCHER);
21 return getPackageManager().queryIntentActivities(intent, 0);
22 }
23
24 public class AppListAdapter extends BaseAdapter {
25 private List<ResolveInfo> resolveInfoList;
26
27 public AppListAdapter(List<ResolveInfo> appInfo) {
28 this.resolveInfoList = appInfo;
29 }
30
31 @Override
32 public int getCount() {
33 return resolveInfoList.size();
34 }
35
36 @Override
37 public Object getItem(int position) {
38 return resolveInfoList.get(position);
39 }
40
41 @Override
42 public long getItemId(int position) {
43 return position;
44 }
45
46 @Override
47 public View getView(int position, View convertView, ViewGroup parent) {
48 LayoutInflater layoutInflater = getLayoutInflater();
49 convertView = layoutInflater.inflate(R.layout.item_app_list, null);
50 ImageView iv = convertView.findViewById(R.id.app_icon_iv);
51 TextView tv = convertView.findViewById(R.id.app_name_tv);
52 ResolveInfo resolveInfo = resolveInfoList.get(position);
53 tv.setText(resolveInfo.activityInfo.loadLabel(getPackageManager()));
54 iv.setImageDrawable(resolveInfo.activityInfo.loadIcon(getPackageManager()));
55
56 // 在这里给每一个条目设置点击事件
57 convertView.setOnClickListener((v) -> {
58 String packageName = resolveInfo.activityInfo.packageName;
59 String className = resolveInfo.activityInfo.name;
60 ComponentName componentName = new ComponentName(packageName, className);
61 Intent intent = new Intent();
62 intent.setComponent(componentName);
63 startActivity(intent);
64 });
65 return convertView;
66 }
67 }
68
69
70 // 最基础的数据展示,ImageView是固定的
71 public class AppListAdapterBase extends BaseAdapter {
72
73 @Override
74 public int getCount() {
75 return appNameList.size();
76 }
77
78 @Override
79 public Object getItem(int position) {
80 return appNameList.get(position);
81 }
82
83 @Override
84 public long getItemId(int position) {
85 return position;
86 }
87
88 @Override
89 public View getView(int position, View convertView, ViewGroup parent) {
90 LayoutInflater layoutInflater = getLayoutInflater();
91 convertView = layoutInflater.inflate(R.layout.item_app_list, null);
92 ImageView iv = convertView.findViewById(R.id.app_icon_iv);
93 TextView tv = convertView.findViewById(R.id.app_name_tv);
94 tv.setText(appNameList.get(position));
95 return convertView;
96 }
97 }
98}
点击事件与长按事件
1public class AppListActivity extends AppCompatActivity {
2
3 @Override
4 protected void onCreate(Bundle savedInstanceState) {
5 super.onCreate(savedInstanceState);
6 setContentView(R.layout.activity_app_list);
7
8 ListView listView = findViewById(R.id.app_lv);
9 appNameList = Arrays.asList("QQ", "微信", "慕课网", "牛客");
10
11 List<ResolveInfo> resolveInfoList = getAppInfo();
12 listView.setAdapter(new AppListAdapter(resolveInfoList));
13
14 // 点击事件写法二
15 listView.setOnItemClickListener((parent, view, position, id) -> {
16 ResolveInfo resolveInfo = resolveInfoList.get(position);
17 String packageName = resolveInfo.activityInfo.packageName;
18 String className = resolveInfo.activityInfo.name;
19 ComponentName componentName = new ComponentName(packageName, className);
20 Intent intent = new Intent();
21 intent.setComponent(componentName);
22 startActivity(intent);
23 });
24
25 // 长按的事件
26 listView.setOnItemLongClickListener((parent, view, position, id) -> {
27 AlertDialog.Builder builder = new AlertDialog.Builder(this);
28 builder.setTitle("提示");
29 builder.setMessage("确定删除吗?");
30 builder.setPositiveButton("确定", (dialog, which) -> {
31 // 移除此条目
32 resolveInfoList.remove(position);
33 listView.setAdapter(new AppListAdapter(resolveInfoList));
34 });
35 builder.setNegativeButton("取消", null);
36 builder.show();
37 return false;
38 });
39 }
40
41 // 获取所有的应用信息
42 private List<ResolveInfo> getAppInfo(){
43 Intent intent = new Intent(Intent.ACTION_MAIN, null);
44 intent.addCategory(Intent.CATEGORY_LAUNCHER);
45 return getPackageManager().queryIntentActivities(intent, 0);
46 }
47
48 public class AppListAdapter extends BaseAdapter {
49 private List<ResolveInfo> resolveInfoList;
50
51 public AppListAdapter(List<ResolveInfo> appInfo) {
52 this.resolveInfoList = appInfo;
53 }
54
55 @Override
56 public int getCount() {
57 return resolveInfoList.size();
58 }
59
60 @Override
61 public Object getItem(int position) {
62 return resolveInfoList.get(position);
63 }
64
65 @Override
66 public long getItemId(int position) {
67 return position;
68 }
69
70 @Override
71 public View getView(int position, View convertView, ViewGroup parent) {
72 LayoutInflater layoutInflater = getLayoutInflater();
73 convertView = layoutInflater.inflate(R.layout.item_app_list, null);
74 ImageView iv = convertView.findViewById(R.id.app_icon_iv);
75 TextView tv = convertView.findViewById(R.id.app_name_tv);
76 ResolveInfo resolveInfo = resolveInfoList.get(position);
77 tv.setText(resolveInfo.activityInfo.loadLabel(getPackageManager()));
78 iv.setImageDrawable(resolveInfo.activityInfo.loadIcon(getPackageManager()));
79 // 点击事件写法一
80 convertView.setOnClickListener((v) -> {
81 String packageName = resolveInfo.activityInfo.packageName;
82 String className = resolveInfo.activityInfo.name;
83 ComponentName componentName = new ComponentName(packageName, className);
84 Intent intent = new Intent();
85 intent.setComponent(componentName);
86 startActivity(intent);
87 });
88 return convertView;
89 }
90 }
91}
设置HeaderView与FooterView
header_app_list.xml
1<?xml version="1.0" encoding="utf-8"?>
2<LinearLayout
3 xmlns:android="http://schemas.android.com/apk/res/android"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent"
6 android:orientation="vertical">
7
8 <TextView
9 android:gravity="center"
10 android:textSize="20sp"
11 android:text="This is listView's header."
12 android:id="@+id/header_app_list_iv"
13 android:background="@color/colorAccent"
14 android:layout_width="match_parent"
15 android:layout_height="80dp"/>
16
17</LinearLayout>
AppListActivity.java(其实只需要在setAdapter之前做一个addHeaderView的操作即可)
1public class AppListActivity extends AppCompatActivity {
2
3 private List<String> appNameList;
4
5 @Override
6 protected void onCreate(Bundle savedInstanceState) {
7 super.onCreate(savedInstanceState);
8 setContentView(R.layout.activity_app_list);
9
10 ListView listView = findViewById(R.id.app_lv);
11 appNameList = Arrays.asList("QQ", "微信", "慕课网", "牛客", "招商银行");
12
13 // 增加头Header
14 listView.addHeaderView(getLayoutInflater().inflate(R.layout.header_app_list, null));
15
16 List<ResolveInfo> resolveInfoList = getAppInfo();
17 listView.setAdapter(new AppListAdapter(resolveInfoList));
18
19 // 点击事件写法二
20 listView.setOnItemClickListener((parent, view, position, id) -> {
21 ResolveInfo resolveInfo = resolveInfoList.get(position);
22 String packageName = resolveInfo.activityInfo.packageName;
23 String className = resolveInfo.activityInfo.name;
24 ComponentName componentName = new ComponentName(packageName, className);
25 Intent intent = new Intent();
26 intent.setComponent(componentName);
27 startActivity(intent);
28 });
29
30 // 长按的事件
31 listView.setOnItemLongClickListener((parent, view, position, id) -> {
32 AlertDialog.Builder builder = new AlertDialog.Builder(this);
33 builder.setTitle("提示");
34 builder.setMessage("确定删除吗?");
35 builder.setPositiveButton("确定", (dialog, which) -> {
36 resolveInfoList.remove(position);
37 listView.setAdapter(new AppListAdapter(resolveInfoList));
38 });
39 builder.setNegativeButton("取消", null);
40 builder.show();
41 return false;
42 });
43 }
44
45 // 获取所有的应用信息
46 private List<ResolveInfo> getAppInfo(){
47 Intent intent = new Intent(Intent.ACTION_MAIN, null);
48 intent.addCategory(Intent.CATEGORY_LAUNCHER);
49 return getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_ALL);
50 }
51
52 public class AppListAdapter extends BaseAdapter {
53 private List<ResolveInfo> resolveInfoList;
54
55 public AppListAdapter(List<ResolveInfo> appInfo) {
56 this.resolveInfoList = appInfo;
57 }
58
59 @Override
60 public int getCount() {
61 return resolveInfoList.size();
62 }
63
64 @Override
65 public Object getItem(int position) {
66 return resolveInfoList.get(position);
67 }
68
69 @Override
70 public long getItemId(int position) {
71 return position;
72 }
73
74 @Override
75 public View getView(int position, View convertView, ViewGroup parent) {
76 LayoutInflater layoutInflater = getLayoutInflater();
77 convertView = layoutInflater.inflate(R.layout.item_app_list, null);
78 ImageView iv = convertView.findViewById(R.id.app_icon_iv);
79 TextView tv = convertView.findViewById(R.id.app_name_tv);
80 ResolveInfo resolveInfo = resolveInfoList.get(position);
81 tv.setText(resolveInfo.activityInfo.loadLabel(getPackageManager()));
82 iv.setImageDrawable(resolveInfo.activityInfo.loadIcon(getPackageManager()));
83 return convertView;
84 }
85 }
86}
ListView的优化
真正意义上的优化: http://www.xuanyusong.com/archives/1252
1public class AppListActivity extends AppCompatActivity {
2
3 private List<String> appNameList;
4
5 @Override
6 protected void onCreate(Bundle savedInstanceState) {
7 super.onCreate(savedInstanceState);
8 setContentView(R.layout.activity_app_list);
9
10 ListView listView = findViewById(R.id.app_lv);
11 appNameList = Arrays.asList("QQ", "微信", "慕课网", "牛客", "招商银行", "支付宝");
12
13 // 增加头Header
14 listView.addHeaderView(getLayoutInflater().inflate(R.layout.header_app_list, null));
15
16 List<ResolveInfo> resolveInfoList = getAppInfo();
17 listView.setAdapter(new AppListAdapter(resolveInfoList));
18 }
19
20 // 获取所有的应用信息
21 private List<ResolveInfo> getAppInfo(){
22 Intent intent = new Intent(Intent.ACTION_MAIN, null);
23 intent.addCategory(Intent.CATEGORY_LAUNCHER);
24 return getPackageManager().queryIntentActivities(intent, 0);
25 }
26
27 public class AppListAdapter extends BaseAdapter {
28 private List<ResolveInfo> resolveInfoList;
29
30 public AppListAdapter(List<ResolveInfo> appInfo) {
31 this.resolveInfoList = appInfo;
32 }
33
34 @Override
35 public int getCount() {
36 return resolveInfoList.size();
37 }
38
39 @Override
40 public Object getItem(int position) {
41 return resolveInfoList.get(position);
42 }
43
44 @Override
45 public long getItemId(int position) {
46 return position;
47 }
48
49 @Override
50 public View getView(int position, View convertView, ViewGroup parent) {
51 ViewHolder viewHolder;
52 if(convertView == null){
53 LayoutInflater layoutInflater = getLayoutInflater();
54 convertView = layoutInflater.inflate(R.layout.item_app_list, null);
55 viewHolder = new ViewHolder();
56 viewHolder.imageView = convertView.findViewById(R.id.app_icon_iv);
57 viewHolder.textView = convertView.findViewById(R.id.app_name_tv);
58 convertView.setTag(viewHolder);
59 }else{
60 viewHolder = (ViewHolder) convertView.getTag();
61 }
62 ResolveInfo resolveInfo = resolveInfoList.get(position);
63 viewHolder.textView.setText(resolveInfo.activityInfo.loadLabel(getPackageManager()));
64 viewHolder.imageView.setImageDrawable(resolveInfo.activityInfo.loadIcon(getPackageManager()));
65 return convertView;
66 }
67 }
68
69 // ViewHolder
70 private static class ViewHolder {
71 public ImageView imageView;
72 public TextView textView;
73 }
74}
条目布局分类加载
item_left_chat.xml
1<?xml version="1.0" encoding="utf-8"?>
2<androidx.constraintlayout.widget.ConstraintLayout
3 xmlns:android="http://schemas.android.com/apk/res/android"
4 xmlns:app="http://schemas.android.com/apk/res-auto"
5 xmlns:tools="http://schemas.android.com/tools"
6 android:layout_width="match_parent"
7 android:layout_height="match_parent">
8
9 <TextView
10 android:id="@+id/time_tv"
11 android:layout_width="wrap_content"
12 android:layout_height="wrap_content"
13 android:text="21:52"
14 app:layout_constraintEnd_toEndOf="parent"
15 app:layout_constraintStart_toStartOf="parent"
16 tools:ignore="MissingConstraints" />
17
18 <ImageView
19 android:id="@+id/icon_iv"
20 android:src="@mipmap/ic_launcher"
21 android:layout_width="wrap_content"
22 android:layout_height="wrap_content"
23 app:layout_constraintTop_toBottomOf="@+id/time_tv"
24 tools:ignore="MissingConstraints"
25 />
26
27 <TextView
28 android:id="@+id/name_tv"
29 android:layout_width="wrap_content"
30 android:layout_height="wrap_content"
31 android:text="Tim"
32 app:layout_constraintEnd_toEndOf="@+id/icon_iv"
33 app:layout_constraintStart_toStartOf="@+id/icon_iv"
34 app:layout_constraintTop_toBottomOf="@+id/icon_iv" />
35
36 <TextView
37 android:id="@+id/content_tv"
38 android:layout_width="wrap_content"
39 android:layout_height="wrap_content"
40 android:text="Hello, how are you?"
41 android:paddingStart="10sp"
42 app:layout_constraintBottom_toBottomOf="@+id/icon_iv"
43 app:layout_constraintStart_toEndOf="@+id/icon_iv"
44 app:layout_constraintTop_toTopOf="@+id/icon_iv"
45 tools:ignore="MissingConstraints" />
46</androidx.constraintlayout.widget.ConstraintLayout>
item_right_chat.xml
1<?xml version="1.0" encoding="utf-8"?>
2<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:app="http://schemas.android.com/apk/res-auto"
4 xmlns:tools="http://schemas.android.com/tools"
5 android:layout_width="match_parent"
6 android:layout_height="match_parent">
7
8 <TextView
9 android:id="@+id/time_tv"
10 android:layout_width="wrap_content"
11 android:layout_height="wrap_content"
12 android:text="21:52"
13 app:layout_constraintEnd_toEndOf="parent"
14 app:layout_constraintStart_toStartOf="parent"
15 tools:ignore="MissingConstraints" />
16
17 <TextView
18 android:id="@+id/name_tv"
19 android:layout_width="wrap_content"
20 android:layout_height="wrap_content"
21 android:text="Tim"
22 app:layout_constraintEnd_toEndOf="@+id/icon_iv"
23 app:layout_constraintStart_toStartOf="@+id/icon_iv"
24 app:layout_constraintTop_toBottomOf="@+id/icon_iv" />
25
26 <TextView
27 android:id="@+id/content_tv"
28 android:layout_width="wrap_content"
29 android:layout_height="wrap_content"
30 android:text="Hello, how are you?"
31 android:paddingEnd="10sp"
32 app:layout_constraintBottom_toBottomOf="@+id/icon_iv"
33 app:layout_constraintEnd_toStartOf="@+id/icon_iv"
34 app:layout_constraintTop_toTopOf="@+id/icon_iv"
35 tools:ignore="MissingConstraints" />
36
37 <ImageView
38 android:id="@+id/icon_iv"
39 android:layout_width="wrap_content"
40 android:layout_height="wrap_content"
41 android:src="@mipmap/ic_launcher"
42 app:layout_constraintEnd_toEndOf="parent"
43 app:layout_constraintTop_toBottomOf="@+id/time_tv"
44 tools:ignore="MissingConstraints" />
45</androidx.constraintlayout.widget.ConstraintLayout>
现在拥有item_left_chat.xml和item_right_chat.xml两个布局,所以只需要做好分类布局加载就好了:
1public class MainActivity extends AppCompatActivity {
2
3 @Override
4 protected void onCreate(Bundle savedInstanceState) {
5 super.onCreate(savedInstanceState);
6 setContentView(R.layout.activity_main);
7 ListView listView = findViewById(R.id.main_lv);
8 List<ChatMessage> chatMessages = Arrays.asList(
9 new ChatMessage(1, 2, "Tim", "08:20", "I'm Tim.", true),
10 new ChatMessage(1, 2, "Tim", "08:25", "Jone, how are you?", true),
11 new ChatMessage(2, 1, "Jone", "08:30", "I'm fine, thinks", false),
12 new ChatMessage(1, 2, "Tim", "08:31", "No thinks.", true),
13 new ChatMessage(2, 1, "Jone", "08:32", "What can I do for you ?", false),
14 new ChatMessage(1, 2, "Tim", "08:59", "Please give me some money.", true)
15 );
16 listView.setAdapter(new ChatMessageAdapter(chatMessages, MainActivity.this));
17
18 }
19
20 static class ChatMessage {
21 public int mId;
22 public int mFriendId;
23 public String mName;
24 public String mDate;
25 public String mContent;
26 public boolean mIsComeMessage;
27
28 public ChatMessage(int mId, int mFriendId,
29 String mName, String mDate,
30 String mContent, boolean mIsComeMessage) {
31 this.mId = mId;
32 this.mFriendId = mFriendId;
33 this.mName = mName;
34 this.mDate = mDate;
35 this.mContent = mContent;
36 this.mIsComeMessage = mIsComeMessage;
37 }
38 }
39
40 static class ChatMessageAdapter extends BaseAdapter {
41 List<ChatMessage> chatMessages;
42 Context context;
43
44 interface IMessageViewType {
45 int COM_MESSAGE = 1;
46 int TO_MESSAGE = 2;
47 }
48
49 public ChatMessageAdapter(List<ChatMessage> chatMessages, Context context) {
50 this.chatMessages = chatMessages;
51 this.context = context;
52 }
53
54 @Override
55 public int getCount() {
56 return chatMessages.size();
57 }
58
59 @Override
60 public Object getItem(int position) {
61 return chatMessages.get(position);
62 }
63
64 @Override
65 public long getItemId(int position) {
66 return position;
67 }
68
69 @Override
70 public View getView(int position, View convertView, ViewGroup parent) {
71 LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
72 ChatMessage chatMessage = chatMessages.get(position);
73 if(convertView == null){
74 if(chatMessage.mIsComeMessage){
75 convertView = layoutInflater.inflate(R.layout.item_left_chat, null);
76 }else{
77 convertView = layoutInflater.inflate(R.layout.item_right_chat, null);
78 }
79 TextView timeTv = convertView.findViewById(R.id.time_tv);
80 ImageView iconIv = convertView.findViewById(R.id.icon_iv);
81 TextView nameTv = convertView.findViewById(R.id.name_tv);
82 TextView contentTv = convertView.findViewById(R.id.content_tv);
83 timeTv.setText(chatMessage.mDate);
84 nameTv.setText(chatMessage.mName);
85 contentTv.setText(chatMessage.mContent);
86 }
87 return convertView;
88 }
89
90 @Override
91 public int getItemViewType(int position) {
92 ChatMessage chatMessage = chatMessages.get(position);
93 return chatMessage.mIsComeMessage ?
94 IMessageViewType.COM_MESSAGE : IMessageViewType.TO_MESSAGE;
95 }
96
97 @Override
98 public int getViewTypeCount() {
99 return 2; // IMessageViewType 两种类型
100 }
101 }
102}
CardView
CardView是用于实现卡片式布局效果的重要控件,实际上也是一个FrameLayout,只是额外提供了圆角和阴影,看上去有立体效果。
CardView是什么?
- Android5.0之后新增
- com.android.support:cardview-v7:26.1.0独立引入
- 继承自FrameLayout,方便作为其他控件容器,添加3D阴影和圆角效果
CardView常用属性
- cardBackgroundColor设置背景色
- cardCornerRadius设置圆角半径
- contentPadding 设置内部padding
- cardElevation设置阴影大小
- cardUseCompatPadding 默认为false,用于5.0及以上,true则添加额外的padding绘制阴影
- cardPreventCornerOverlap 默认为true,用于5.0以下,添加额外的padding,防止内容和圆角重叠
CardView的常用属性
引入CardView的依赖
1implementation 'androidx.cardview:cardview:1.0.0'
一个VardView的小Demo:
1<?xml version="1.0" encoding="utf-8"?>
2<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 xmlns:tools="http://schemas.android.com/tools"
4 android:layout_width="match_parent"
5 android:layout_height="match_parent"
6 xmlns:app="http://schemas.android.com/apk/res-auto"
7 tools:context=".MainActivity">
8
9 <!--
10 cardBackgroundColor:设置背景色
11 cardCornerRadius:设置圆角
12 cardElevation:设置阴影
13 contentPadding:设置内部padding
14 -->
15 <androidx.cardview.widget.CardView
16 android:layout_gravity="center"
17 app:cardBackgroundColor="@color/colorAccent"
18 app:cardCornerRadius="10dp"
19 app:cardElevation="5dp"
20 app:contentPadding="10dp"
21 android:layout_width="wrap_content"
22 android:layout_height="wrap_content">
23
24 <TextView
25 android:layout_width="200dp"
26 android:layout_height="50dp"
27 android:text="Hello World!"
28 android:gravity="center"
29 android:layout_gravity="center"
30 />
31 </androidx.cardview.widget.CardView>
32</FrameLayout>
其实可以看到CardView还真的是有种卡片效果的。常用的属性如下:
属性 | 作用 |
---|---|
card_view:cardElevation | 阴影的大小 |
card_view:cardMaxElevation | 阴影最大高度 |
card_view:cardBackgroundColor | 卡片的背景色 |
card_view:cardCornerRadius | 卡片的圆角大小 |
card_view:contentPadding | 卡片内容于边距的间隔 |
card_view:contentPaddingBottom | 卡片内容与底部的边距 |
card_view:contentPaddingTop | 卡片内容与顶部的边距 |
card_view:contentPaddingLeft | 卡片内容与左边的边距 |
card_view:contentPaddingRight | 卡片内容与右边的边距 |
card_view:contentPaddingStart | 卡片内容于边距的间隔起始 |
card_view:contentPaddingEnd | 卡片内容于边距的间隔终止 |
card_view:cardUseCompatPadding | 设置内边距,V21+的版本和之前的版本仍旧具有一样的计算方式 |
card_view:cardPreventCornerOverlap | 在V20和之前的版本中添加内边距,这个属性为了防止内容和边角的重叠 |
CardView使用示例
先把展示的图片发放在drawable下的xxhdpi下:分别是img01-img05。
item_msg.xml ,这是ListView的条目布局:
1<?xml version="1.0" encoding="utf-8"?>
2<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="match_parent"
4 android:layout_height="wrap_content"
5 xmlns:tools="http://schemas.android.com/tools"
6 xmlns:app="http://schemas.android.com/apk/res-auto">
7
8 <androidx.cardview.widget.CardView
9 app:cardCornerRadius="8dp"
10 app:cardElevation="5dp"
11 app:cardUseCompatPadding="false"
12 android:layout_marginLeft="16dp"
13 android:layout_marginRight="16dp"
14 android:layout_marginTop="8dp"
15 android:layout_marginBottom="8dp"
16 android:layout_width="match_parent"
17 android:layout_height="wrap_content">
18 <LinearLayout
19 android:orientation="vertical"
20 android:layout_width="match_parent"
21 android:layout_height="wrap_content">
22 <ImageView
23 android:id="@+id/item_icon_iv"
24 android:scaleType="centerCrop"
25 tools:src="@drawable/img01"
26 android:layout_width="match_parent"
27 android:layout_height="wrap_content"/>
28
29 <TextView
30 android:id="@+id/item_title_tv"
31 android:layout_margin="8dp"
32 android:textColor="#000000"
33 android:textSize="16sp"
34 android:textStyle="bold"
35 tools:text="一起来学习Android技术"
36 android:layout_width="match_parent"
37 android:layout_height="wrap_content"/>
38
39 <TextView
40 android:id="@+id/item_content_tv"
41 android:layout_margin="8dp"
42 android:textColor="#000000"
43 android:layout_marginLeft="8dp"
44 android:layout_marginRight="8dp"
45 android:layout_marginBottom="8dp"
46 tools:text="一起来学习Android技术, 一起来学习Android技术。"
47 android:layout_width="match_parent"
48 android:layout_height="wrap_content"/>
49 </LinearLayout>
50 </androidx.cardview.widget.CardView>
51</FrameLayout>
main_activity.xml
1<?xml version="1.0" encoding="utf-8"?>
2<ListView
3 xmlns:android="http://schemas.android.com/apk/res/android"
4 xmlns:app="http://schemas.android.com/apk/res-auto"
5 xmlns:tools="http://schemas.android.com/tools"
6 android:layout_width="match_parent"
7 android:layout_height="match_parent"
8 android:id="@+id/id_listview_msg_list"
9 android:divider="@null"
10 android:background="#ffffff"
11 android:paddingTop="8dp"
12 tools:context=".MainActivity">
13
14
15</ListView>
MainActivity.java
1public class MainActivity extends AppCompatActivity {
2
3 @Override
4 protected void onCreate(Bundle savedInstanceState) {
5 super.onCreate(savedInstanceState);
6 this.setTitle("CardView测试");
7 setContentView(R.layout.activity_main);
8 ListView msgListView = findViewById(R.id.id_listview_msg_list);
9
10 List<Msg> messageList = Arrays.asList(
11 new Msg(1, R.drawable.img01, "如何才能不错过人工智能的时代?", "下一个时代就是机器学习的时代,与你一起预见未来!"),
12 new Msg(2, R.drawable.img02, "关于你的面试、实习心路历程", "奖品丰富,更设有参与奖,随机抽取5名幸运用户,获得付费面试课程中的任意一门!"),
13 new Msg(3, R.drawable.img03, "狗粮不是你想吃,就能吃的!", "你的朋友圈开始了吗?一半秀恩爱,一半扮感伤!不怕,陪你坚强地走下去!"),
14 new Msg(4, R.drawable.img04, "前端跳槽面试那些事儿~", "工作有几年了,项目偏简单有点拿不出手怎么办?目前还没毕业,正在自学前端,请问可以找到一份前端工作吗,我该怎么办?"),
15 new Msg(5, R.drawable.img05, "图解程序员怎么过七夕?", "图解程序员怎么过七夕,哈哈哈哈,活该单身25年!")
16 );
17
18 msgListView.setAdapter(new MoocAdapter(messageList));
19 }
20
21 class MoocAdapter extends BaseAdapter {
22 private List<Msg> msgList;
23
24 public MoocAdapter(List<Msg> msgList) {
25 this.msgList = msgList;
26 }
27
28 @Override
29 public int getCount() {
30 return msgList.size();
31 }
32
33 @Override
34 public Object getItem(int position) {
35 return msgList.get(position);
36 }
37
38 @Override
39 public long getItemId(int position) {
40 return position;
41 }
42
43 @Override
44 public View getView(int position, View convertView, ViewGroup parent) {
45 ViewHolder viewHolder;
46 if(convertView == null){
47 convertView = View.inflate(MainActivity.this, R.layout.item_msg, null);
48 //convertView = getLayoutInflater().inflate(R.layout.item_msg, null);
49 viewHolder = new ViewHolder();
50 viewHolder.iconImageView = convertView.findViewById(R.id.item_icon_iv);
51 viewHolder.titleTextView = convertView.findViewById(R.id.item_title_tv);
52 viewHolder.contentTextView = convertView.findViewById(R.id.item_content_tv);
53 convertView.setTag(viewHolder);
54 }else{
55 viewHolder = (ViewHolder) convertView.getTag();
56 }
57 Msg msg = msgList.get(position);
58 viewHolder.contentTextView.setText(msg.getContent());
59 viewHolder.titleTextView.setText(msg.getTitle());
60 viewHolder.iconImageView.setImageResource(msg.getImgResId());
61
62 return convertView;
63 }
64 }
65
66 static class ViewHolder {
67 ImageView iconImageView;
68 TextView titleTextView;
69 TextView contentTextView;
70 }
71}
72
73@Data
74@AllArgsConstructor
75@NoArgsConstructor
76class Msg {
77 private int id;
78 private int imgResId;
79 private String title;
80 private String content;
81}
看看最终的展示效果:
这里用到了lombok这款插件,那就顺便说一下lombok在Android开发中如何使用吧。
使用tools工具预览
1<!-- 引入tools命令空间 -->
2xmlns:tools="http://schemas.android.com/tools"
3
4<TextView
5 android:id="@+id/item_title_tv"
6 android:layout_margin="8dp"
7 android:textColor="#000000"
8 android:textSize="16sp"
9 android:textStyle="bold"
10 tools:text="一起来学习Android技术"
11 android:layout_width="match_parent"
12 android:layout_height="wrap_content"/>
使用tools工具可以进行控件效果预览,如果直接写了android:text=XXX,那么很可能在数据无法正确加载的情况下显示出我们定义的android:text属性,所以无论是ImageView还是TextView等需要添加数据才可以预览的情况都可以使用tools这个命名空间。
Lombok在Android中的使用
引入lombok的依赖:
1// 这是CardView的依赖
2implementation 'androidx.cardview:cardview:1.0.0'
3// 配置Lombok注解处理器
4annotationProcessor group: 'org.projectlombok', name: 'lombok', version: '1.18.12'
5// 声明lombok的依赖作用域
6compileOnly(group: 'org.projectlombok', name: 'lombok', version: '1.18.12')
安装Lombok的插件:
安装好插件后重启AndroidStudio即可使用Lombok插件。
最后别忘了在moudle或者project底下新建一个lombok.config:
1lombok.anyConstructor.suppressConstructorProperties=true
然后开始愉快的写代码吧 ~
编译时编码错误解决方案
1android {
2 compileSdkVersion ...
3 buildToolsVersion "..."
4
5 // 指定编码为UTF-8
6 compileOptions {
7 encoding "UTF-8"
8 }
9 ...
10}
Android屏幕适配
这个专门放置一篇博客!