Tim

一枚野生程序员~

  • 主页
  • 分类
  • 标签
  • 归档
  • 关于
所有文章 工具

Tim

一枚野生程序员~

  • 主页
  • 分类
  • 标签
  • 归档
  • 关于

高级控件与屏幕适配

阅读数:次 2020-11-19
字数统计: 4.1k字   |   阅读时长≈ 21分

本篇文章主要是记录一下高级控件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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:orientation="horizontal">

<ImageView
android:id="@+id/app_icon_iv"
android:src="@mipmap/ic_launcher"
android:layout_width="40dp"
android:layout_height="40dp"/>

<TextView
android:id="@+id/app_name_tv"
android:textSize="20sp"
android:paddingLeft="10dp"
android:gravity="center_vertical"
android:text="@string/app_name"
android:layout_width="match_parent"
android:layout_height="40dp"/>
</LinearLayout>

AppListActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
public class AppListActivity extends AppCompatActivity {

private List<String> appNameList;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_app_list);

ListView listView = findViewById(R.id.app_lv);
appNameList = Arrays.asList("QQ", "微信", "牛客", "招商银行", "支付宝");

//listView.setAdapter(new AppListAdapterBase());
listView.setAdapter(new AppListAdapter(getAppInfo()));
}

// 获取所有的应用信息
private List<ResolveInfo> getAppInfo(){
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
return getPackageManager().queryIntentActivities(intent, 0);
}

public class AppListAdapter extends BaseAdapter {
private List<ResolveInfo> resolveInfoList;

public AppListAdapter(List<ResolveInfo> appInfo) {
this.resolveInfoList = appInfo;
}

@Override
public int getCount() {
return resolveInfoList.size();
}

@Override
public Object getItem(int position) {
return resolveInfoList.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater layoutInflater = getLayoutInflater();
convertView = layoutInflater.inflate(R.layout.item_app_list, null);
ImageView iv = convertView.findViewById(R.id.app_icon_iv);
TextView tv = convertView.findViewById(R.id.app_name_tv);
ResolveInfo resolveInfo = resolveInfoList.get(position);
tv.setText(resolveInfo.activityInfo.loadLabel(getPackageManager()));
iv.setImageDrawable(resolveInfo.activityInfo.loadIcon(getPackageManager()));

// 在这里给每一个条目设置点击事件
convertView.setOnClickListener((v) -> {
String packageName = resolveInfo.activityInfo.packageName;
String className = resolveInfo.activityInfo.name;
ComponentName componentName = new ComponentName(packageName, className);
Intent intent = new Intent();
intent.setComponent(componentName);
startActivity(intent);
});
return convertView;
}
}


// 最基础的数据展示,ImageView是固定的
public class AppListAdapterBase extends BaseAdapter {

@Override
public int getCount() {
return appNameList.size();
}

@Override
public Object getItem(int position) {
return appNameList.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater layoutInflater = getLayoutInflater();
convertView = layoutInflater.inflate(R.layout.item_app_list, null);
ImageView iv = convertView.findViewById(R.id.app_icon_iv);
TextView tv = convertView.findViewById(R.id.app_name_tv);
tv.setText(appNameList.get(position));
return convertView;
}
}
}

点击事件与长按事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
public class AppListActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_app_list);

ListView listView = findViewById(R.id.app_lv);
appNameList = Arrays.asList("QQ", "微信", "慕课网", "牛客");

List<ResolveInfo> resolveInfoList = getAppInfo();
listView.setAdapter(new AppListAdapter(resolveInfoList));

// 点击事件写法二
listView.setOnItemClickListener((parent, view, position, id) -> {
ResolveInfo resolveInfo = resolveInfoList.get(position);
String packageName = resolveInfo.activityInfo.packageName;
String className = resolveInfo.activityInfo.name;
ComponentName componentName = new ComponentName(packageName, className);
Intent intent = new Intent();
intent.setComponent(componentName);
startActivity(intent);
});

// 长按的事件
listView.setOnItemLongClickListener((parent, view, position, id) -> {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示");
builder.setMessage("确定删除吗?");
builder.setPositiveButton("确定", (dialog, which) -> {
// 移除此条目
resolveInfoList.remove(position);
listView.setAdapter(new AppListAdapter(resolveInfoList));
});
builder.setNegativeButton("取消", null);
builder.show();
return false;
});
}

// 获取所有的应用信息
private List<ResolveInfo> getAppInfo(){
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
return getPackageManager().queryIntentActivities(intent, 0);
}

public class AppListAdapter extends BaseAdapter {
private List<ResolveInfo> resolveInfoList;

public AppListAdapter(List<ResolveInfo> appInfo) {
this.resolveInfoList = appInfo;
}

@Override
public int getCount() {
return resolveInfoList.size();
}

@Override
public Object getItem(int position) {
return resolveInfoList.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater layoutInflater = getLayoutInflater();
convertView = layoutInflater.inflate(R.layout.item_app_list, null);
ImageView iv = convertView.findViewById(R.id.app_icon_iv);
TextView tv = convertView.findViewById(R.id.app_name_tv);
ResolveInfo resolveInfo = resolveInfoList.get(position);
tv.setText(resolveInfo.activityInfo.loadLabel(getPackageManager()));
iv.setImageDrawable(resolveInfo.activityInfo.loadIcon(getPackageManager()));
// 点击事件写法一
convertView.setOnClickListener((v) -> {
String packageName = resolveInfo.activityInfo.packageName;
String className = resolveInfo.activityInfo.name;
ComponentName componentName = new ComponentName(packageName, className);
Intent intent = new Intent();
intent.setComponent(componentName);
startActivity(intent);
});
return convertView;
}
}
}

设置HeaderView与FooterView

header_app_list.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:gravity="center"
android:textSize="20sp"
android:text="This is listView's header."
android:id="@+id/header_app_list_iv"
android:background="@color/colorAccent"
android:layout_width="match_parent"
android:layout_height="80dp"/>

</LinearLayout>

AppListActivity.java(其实只需要在setAdapter之前做一个addHeaderView的操作即可)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public class AppListActivity extends AppCompatActivity {

private List<String> appNameList;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_app_list);

ListView listView = findViewById(R.id.app_lv);
appNameList = Arrays.asList("QQ", "微信", "慕课网", "牛客", "招商银行");

// 增加头Header
listView.addHeaderView(getLayoutInflater().inflate(R.layout.header_app_list, null));

List<ResolveInfo> resolveInfoList = getAppInfo();
listView.setAdapter(new AppListAdapter(resolveInfoList));

// 点击事件写法二
listView.setOnItemClickListener((parent, view, position, id) -> {
ResolveInfo resolveInfo = resolveInfoList.get(position);
String packageName = resolveInfo.activityInfo.packageName;
String className = resolveInfo.activityInfo.name;
ComponentName componentName = new ComponentName(packageName, className);
Intent intent = new Intent();
intent.setComponent(componentName);
startActivity(intent);
});

// 长按的事件
listView.setOnItemLongClickListener((parent, view, position, id) -> {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("提示");
builder.setMessage("确定删除吗?");
builder.setPositiveButton("确定", (dialog, which) -> {
resolveInfoList.remove(position);
listView.setAdapter(new AppListAdapter(resolveInfoList));
});
builder.setNegativeButton("取消", null);
builder.show();
return false;
});
}

// 获取所有的应用信息
private List<ResolveInfo> getAppInfo(){
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
return getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_ALL);
}

public class AppListAdapter extends BaseAdapter {
private List<ResolveInfo> resolveInfoList;

public AppListAdapter(List<ResolveInfo> appInfo) {
this.resolveInfoList = appInfo;
}

@Override
public int getCount() {
return resolveInfoList.size();
}

@Override
public Object getItem(int position) {
return resolveInfoList.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater layoutInflater = getLayoutInflater();
convertView = layoutInflater.inflate(R.layout.item_app_list, null);
ImageView iv = convertView.findViewById(R.id.app_icon_iv);
TextView tv = convertView.findViewById(R.id.app_name_tv);
ResolveInfo resolveInfo = resolveInfoList.get(position);
tv.setText(resolveInfo.activityInfo.loadLabel(getPackageManager()));
iv.setImageDrawable(resolveInfo.activityInfo.loadIcon(getPackageManager()));
return convertView;
}
}
}

ListView的优化

真正意义上的优化: http://www.xuanyusong.com/archives/1252

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
public class AppListActivity extends AppCompatActivity {

private List<String> appNameList;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_app_list);

ListView listView = findViewById(R.id.app_lv);
appNameList = Arrays.asList("QQ", "微信", "慕课网", "牛客", "招商银行", "支付宝");

// 增加头Header
listView.addHeaderView(getLayoutInflater().inflate(R.layout.header_app_list, null));

List<ResolveInfo> resolveInfoList = getAppInfo();
listView.setAdapter(new AppListAdapter(resolveInfoList));
}

// 获取所有的应用信息
private List<ResolveInfo> getAppInfo(){
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
return getPackageManager().queryIntentActivities(intent, 0);
}

public class AppListAdapter extends BaseAdapter {
private List<ResolveInfo> resolveInfoList;

public AppListAdapter(List<ResolveInfo> appInfo) {
this.resolveInfoList = appInfo;
}

@Override
public int getCount() {
return resolveInfoList.size();
}

@Override
public Object getItem(int position) {
return resolveInfoList.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if(convertView == null){
LayoutInflater layoutInflater = getLayoutInflater();
convertView = layoutInflater.inflate(R.layout.item_app_list, null);
viewHolder = new ViewHolder();
viewHolder.imageView = convertView.findViewById(R.id.app_icon_iv);
viewHolder.textView = convertView.findViewById(R.id.app_name_tv);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
ResolveInfo resolveInfo = resolveInfoList.get(position);
viewHolder.textView.setText(resolveInfo.activityInfo.loadLabel(getPackageManager()));
viewHolder.imageView.setImageDrawable(resolveInfo.activityInfo.loadIcon(getPackageManager()));
return convertView;
}
}

// ViewHolder
private static class ViewHolder {
public ImageView imageView;
public TextView textView;
}
}

条目布局分类加载

item_left_chat.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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">

<TextView
android:id="@+id/time_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="21:52"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="MissingConstraints" />

<ImageView
android:id="@+id/icon_iv"
android:src="@mipmap/ic_launcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/time_tv"
tools:ignore="MissingConstraints"
/>

<TextView
android:id="@+id/name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tim"
app:layout_constraintEnd_toEndOf="@+id/icon_iv"
app:layout_constraintStart_toStartOf="@+id/icon_iv"
app:layout_constraintTop_toBottomOf="@+id/icon_iv" />

<TextView
android:id="@+id/content_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, how are you?"
android:paddingStart="10sp"
app:layout_constraintBottom_toBottomOf="@+id/icon_iv"
app:layout_constraintStart_toEndOf="@+id/icon_iv"
app:layout_constraintTop_toTopOf="@+id/icon_iv"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>

item_right_chat.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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">

<TextView
android:id="@+id/time_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="21:52"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:ignore="MissingConstraints" />

<TextView
android:id="@+id/name_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tim"
app:layout_constraintEnd_toEndOf="@+id/icon_iv"
app:layout_constraintStart_toStartOf="@+id/icon_iv"
app:layout_constraintTop_toBottomOf="@+id/icon_iv" />

<TextView
android:id="@+id/content_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, how are you?"
android:paddingEnd="10sp"
app:layout_constraintBottom_toBottomOf="@+id/icon_iv"
app:layout_constraintEnd_toStartOf="@+id/icon_iv"
app:layout_constraintTop_toTopOf="@+id/icon_iv"
tools:ignore="MissingConstraints" />

<ImageView
android:id="@+id/icon_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/time_tv"
tools:ignore="MissingConstraints" />
</androidx.constraintlayout.widget.ConstraintLayout>

现在拥有item_left_chat.xml和item_right_chat.xml两个布局,所以只需要做好分类布局加载就好了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = findViewById(R.id.main_lv);
List<ChatMessage> chatMessages = Arrays.asList(
new ChatMessage(1, 2, "Tim", "08:20", "I'm Tim.", true),
new ChatMessage(1, 2, "Tim", "08:25", "Jone, how are you?", true),
new ChatMessage(2, 1, "Jone", "08:30", "I'm fine, thinks", false),
new ChatMessage(1, 2, "Tim", "08:31", "No thinks.", true),
new ChatMessage(2, 1, "Jone", "08:32", "What can I do for you ?", false),
new ChatMessage(1, 2, "Tim", "08:59", "Please give me some money.", true)
);
listView.setAdapter(new ChatMessageAdapter(chatMessages, MainActivity.this));

}

static class ChatMessage {
public int mId;
public int mFriendId;
public String mName;
public String mDate;
public String mContent;
public boolean mIsComeMessage;

public ChatMessage(int mId, int mFriendId,
String mName, String mDate,
String mContent, boolean mIsComeMessage) {
this.mId = mId;
this.mFriendId = mFriendId;
this.mName = mName;
this.mDate = mDate;
this.mContent = mContent;
this.mIsComeMessage = mIsComeMessage;
}
}

static class ChatMessageAdapter extends BaseAdapter {
List<ChatMessage> chatMessages;
Context context;

interface IMessageViewType {
int COM_MESSAGE = 1;
int TO_MESSAGE = 2;
}

public ChatMessageAdapter(List<ChatMessage> chatMessages, Context context) {
this.chatMessages = chatMessages;
this.context = context;
}

@Override
public int getCount() {
return chatMessages.size();
}

@Override
public Object getItem(int position) {
return chatMessages.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ChatMessage chatMessage = chatMessages.get(position);
if(convertView == null){
if(chatMessage.mIsComeMessage){
convertView = layoutInflater.inflate(R.layout.item_left_chat, null);
}else{
convertView = layoutInflater.inflate(R.layout.item_right_chat, null);
}
TextView timeTv = convertView.findViewById(R.id.time_tv);
ImageView iconIv = convertView.findViewById(R.id.icon_iv);
TextView nameTv = convertView.findViewById(R.id.name_tv);
TextView contentTv = convertView.findViewById(R.id.content_tv);
timeTv.setText(chatMessage.mDate);
nameTv.setText(chatMessage.mName);
contentTv.setText(chatMessage.mContent);
}
return convertView;
}

@Override
public int getItemViewType(int position) {
ChatMessage chatMessage = chatMessages.get(position);
return chatMessage.mIsComeMessage ?
IMessageViewType.COM_MESSAGE : IMessageViewType.TO_MESSAGE;
}

@Override
public int getViewTypeCount() {
return 2; // IMessageViewType 两种类型
}
}
}

CardView

CardView是用于实现卡片式布局效果的重要控件,实际上也是一个FrameLayout,只是额外提供了圆角和阴影,看上去有立体效果。

CardView是什么?

  1. Android5.0之后新增
  2. com.android.support:cardview-v7:26.1.0独立引入
  3. 继承自FrameLayout,方便作为其他控件容器,添加3D阴影和圆角效果

CardView常用属性

  1. cardBackgroundColor设置背景色
  2. cardCornerRadius设置圆角半径
  3. contentPadding 设置内部padding
  4. cardElevation设置阴影大小
  5. cardUseCompatPadding 默认为false,用于5.0及以上,true则添加额外的padding绘制阴影
  6. cardPreventCornerOverlap 默认为true,用于5.0以下,添加额外的padding,防止内容和圆角重叠

CardView的常用属性

引入CardView的依赖

1
implementation 'androidx.cardview:cardview:1.0.0'

一个VardView的小Demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity">

<!--
cardBackgroundColor:设置背景色
cardCornerRadius:设置圆角
cardElevation:设置阴影
contentPadding:设置内部padding
-->
<androidx.cardview.widget.CardView
android:layout_gravity="center"
app:cardBackgroundColor="@color/colorAccent"
app:cardCornerRadius="10dp"
app:cardElevation="5dp"
app:contentPadding="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<TextView
android:layout_width="200dp"
android:layout_height="50dp"
android:text="Hello World!"
android:gravity="center"
android:layout_gravity="center"
/>
</androidx.cardview.widget.CardView>
</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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">

<androidx.cardview.widget.CardView
app:cardCornerRadius="8dp"
app:cardElevation="5dp"
app:cardUseCompatPadding="false"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/item_icon_iv"
android:scaleType="centerCrop"
tools:src="@drawable/img01"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

<TextView
android:id="@+id/item_title_tv"
android:layout_margin="8dp"
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="bold"
tools:text="一起来学习Android技术"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

<TextView
android:id="@+id/item_content_tv"
android:layout_margin="8dp"
android:textColor="#000000"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
tools:text="一起来学习Android技术, 一起来学习Android技术。"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</FrameLayout>

main_activity.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<ListView
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:id="@+id/id_listview_msg_list"
android:divider="@null"
android:background="#ffffff"
android:paddingTop="8dp"
tools:context=".MainActivity">


</ListView>

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setTitle("CardView测试");
setContentView(R.layout.activity_main);
ListView msgListView = findViewById(R.id.id_listview_msg_list);

List<Msg> messageList = Arrays.asList(
new Msg(1, R.drawable.img01, "如何才能不错过人工智能的时代?", "下一个时代就是机器学习的时代,与你一起预见未来!"),
new Msg(2, R.drawable.img02, "关于你的面试、实习心路历程", "奖品丰富,更设有参与奖,随机抽取5名幸运用户,获得付费面试课程中的任意一门!"),
new Msg(3, R.drawable.img03, "狗粮不是你想吃,就能吃的!", "你的朋友圈开始了吗?一半秀恩爱,一半扮感伤!不怕,陪你坚强地走下去!"),
new Msg(4, R.drawable.img04, "前端跳槽面试那些事儿~", "工作有几年了,项目偏简单有点拿不出手怎么办?目前还没毕业,正在自学前端,请问可以找到一份前端工作吗,我该怎么办?"),
new Msg(5, R.drawable.img05, "图解程序员怎么过七夕?", "图解程序员怎么过七夕,哈哈哈哈,活该单身25年!")
);

msgListView.setAdapter(new MoocAdapter(messageList));
}

class MoocAdapter extends BaseAdapter {
private List<Msg> msgList;

public MoocAdapter(List<Msg> msgList) {
this.msgList = msgList;
}

@Override
public int getCount() {
return msgList.size();
}

@Override
public Object getItem(int position) {
return msgList.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if(convertView == null){
convertView = View.inflate(MainActivity.this, R.layout.item_msg, null);
//convertView = getLayoutInflater().inflate(R.layout.item_msg, null);
viewHolder = new ViewHolder();
viewHolder.iconImageView = convertView.findViewById(R.id.item_icon_iv);
viewHolder.titleTextView = convertView.findViewById(R.id.item_title_tv);
viewHolder.contentTextView = convertView.findViewById(R.id.item_content_tv);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
Msg msg = msgList.get(position);
viewHolder.contentTextView.setText(msg.getContent());
viewHolder.titleTextView.setText(msg.getTitle());
viewHolder.iconImageView.setImageResource(msg.getImgResId());

return convertView;
}
}

static class ViewHolder {
ImageView iconImageView;
TextView titleTextView;
TextView contentTextView;
}
}

@Data
@AllArgsConstructor
@NoArgsConstructor
class Msg {
private int id;
private int imgResId;
private String title;
private String content;
}

看看最终的展示效果:

这里用到了lombok这款插件,那就顺便说一下lombok在Android开发中如何使用吧。

使用tools工具预览

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 引入tools命令空间 -->
xmlns:tools="http://schemas.android.com/tools"

<TextView
android:id="@+id/item_title_tv"
android:layout_margin="8dp"
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="bold"
tools:text="一起来学习Android技术"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

使用tools工具可以进行控件效果预览,如果直接写了android:text=XXX,那么很可能在数据无法正确加载的情况下显示出我们定义的android:text属性,所以无论是ImageView还是TextView等需要添加数据才可以预览的情况都可以使用tools这个命名空间。

Lombok在Android中的使用

引入lombok的依赖:

1
2
3
4
5
6
// 这是CardView的依赖
implementation 'androidx.cardview:cardview:1.0.0'
// 配置Lombok注解处理器
annotationProcessor group: 'org.projectlombok', name: 'lombok', version: '1.18.12'
// 声明lombok的依赖作用域
compileOnly(group: 'org.projectlombok', name: 'lombok', version: '1.18.12')

安装Lombok的插件:

安装好插件后重启AndroidStudio即可使用Lombok插件。

最后别忘了在moudle或者project底下新建一个lombok.config:

1
lombok.anyConstructor.suppressConstructorProperties=true

然后开始愉快的写代码吧 ~

编译时编码错误解决方案

1
2
3
4
5
6
7
8
9
10
android {
compileSdkVersion ...
buildToolsVersion "..."

// 指定编码为UTF-8
compileOptions {
encoding "UTF-8"
}
...
}

Android屏幕适配

这个专门放置一篇博客!

赏

谢谢你请我喝咖啡

支付宝
微信
  • 本文作者: Tim
  • 本文链接: https://zouchanglin.cn/58995.html
  • 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 许可协议。转载请注明出处!
  • Android
  • 移动开发

扫一扫,分享到微信

手写一个Hexo评论系统(一)
UI片段——Fragment
  1. 1. ListView
    1. 1.1. ListView的基本使用
    2. 1.2. 点击事件与长按事件
    3. 1.3. 设置HeaderView与FooterView
    4. 1.4. ListView的优化
    5. 1.5. 条目布局分类加载
  2. 2. CardView
    1. 2.1. CardView的常用属性
    2. 2.2. CardView使用示例
  3. 3. 使用tools工具预览
  4. 4. Lombok在Android中的使用
  5. 5. 编译时编码错误解决方案
  6. 6. Android屏幕适配
© 2017-2021 Tim
本站总访问量次 | 本站访客数人
  • 所有文章
  • 工具

tag:

  • 生活
  • Android
  • 索引
  • MySQL
  • 组件通信
  • Nginx
  • JavaSE
  • JUC
  • JavaWeb
  • 模板引擎
  • 前端
  • Linux
  • 计算机网络
  • Docker
  • C/C++
  • JVM
  • 上传下载
  • JavaEE
  • SpringCloud
  • Golang
  • Gradle
  • 网络安全
  • 非对称加密
  • IDEA
  • SpringBoot
  • Jenkins
  • 字符串
  • vim
  • 存储
  • 文件下载
  • Mac
  • Windows
  • NIO
  • RPC
  • 集群
  • 微服务
  • SSH
  • 配置中心
  • XML
  • Chrome
  • 压力测试
  • Git
  • 博客
  • 概率论
  • 排序算法
  • 分布式
  • 异常处理
  • 文件系统
  • 哈希
  • openCV
  • 栈
  • 回溯
  • SpringCore
  • 流媒体
  • rtmp
  • 面向对象
  • Vue
  • ElementUI
  • 软件工程
  • 异步
  • 自定义UI
  • ORM框架
  • 模块化
  • 交互式
  • Jsoup
  • Http Client
  • LRUCache
  • RabbitMQ
  • 消息通信
  • 服务解耦
  • 负载均衡
  • 权限
  • 多线程
  • 单例模式
  • Protobuf
  • 序列化
  • Python
  • m3u8
  • 堆
  • 二叉树
  • 自定义View
  • 观察者模式
  • 设计模式
  • 线程池
  • 动态扩容
  • 高可用
  • GC
  • ffmpeg
  • SpringMVC
  • REST
  • Redis
  • 缓存中间件
  • UML
  • Maven
  • Netty
  • 高性能网络
  • IPC通信
  • IO
  • Stream
  • 发布订阅
  • SQLite
  • Hash
  • 集合框架
  • 链表
  • Lambda
  • 汇编语言
  • 组件化
  • Router
  • 开发工具

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia-plus根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 思维导图
  • PDF工具
  • 无损放大
  • 代码转图
  • HTTPS证书