前言

  • 本文是根据上海应用技术大学余艳芳老师的移动应用课程写的上课笔记。
  • 部分素材和代码没有给出(例如drawable中的文件代码),请读者自己补全或者删除,或者可以到本人github下载完整素材和代码。
  • 完整的项目在本人的GitHub仓库中,以下是相关链接:https://github.com/ufovsmba/TodayApplication

AdapterView与Adapter

  • AdapterView实现过程类似于MVC架构

image-20220405203208912

  • AdapterView实现过程
  1. 控制层: Adapter适配器承担了控制层的角色
  2. 视图层: AdapterView将前端显示和后端数据分离
  3. 模型层: 数组、XML文件、List(ArrayList,LinkList)等形式的数据

AdapterView组件

  • AdapterView特征

    • AdapterView继承了ViewGroup,其本质上是容器

    • AdapterView可以包括多个“列表项”,并将“列表项”以合适的形式显示出来

    • AdapterView所显示的“列表项”是由Adapter提供,通过AdapterView的setAdapter()方法来设置Adapter适配器

  • AdapterView及其子类的继承关系

image-20220405204201334

ps:通常将ListView、GridView、Spinner和Gallery等AdapterView子类作为容器,然后使用Adapter为容器提供“列表项”,AdapterView负责采用合适的方式显示这些列表项。

  • Adapter的常用子接口

    • ListAdapter接口

    • SimpleAdapter类

    • SimpleCursorAdapter类

    • ArrayAdapter类

    • BaseAdapter抽象类

ListView

ListView列表视图

  • ListView通常具有两个职责:
    • 将数据填充到布局,以列表的方式来显示数据
    • 处理用户的选择、点击等操作Adapter类
  • 通常创建ListView有以下两种方式:

    • 直接使用ListView进行创建
    • 使用Activity继承ListActivity,实现ListView对象的获取
  • ListView的独有属性

XML属性 功能描述
android:divider 设置列表的分隔条
android:dividerHeight 用来指定分隔条的高度
android:entries 指定一个数组资源
android:footerDividersEnabled 各个footer之间绘制分隔条
android:headerDividersEnabled 各个header之间绘制分隔条
  • ListView从AbsListView中继承的属性
XML属性 功能描述
android:cacheColorHint 用于设置该列表的背景始终以单一、固定的颜色绘制
android:choiceMode 为视图指定选择的行为
android:drawSelectorOnTop 如果为true,选中的列表项将会显示在上面
android:fastScrollEnabled 用于设置是否允许使用快速滚动滑块
android:listSelector 设置选中项显示的可绘制对象
android:scrollingCache 设置在滚动时是否使用绘制缓存,默认为true。
android:smoothScrollbar 列表会使用更精确的基于条目在屏幕上的可见像素高度的计算方法
android:stackFromBottom 设置是否将列表项从底部开始显示
android:textFilterEnabled 设置是否对列表项进行过滤
android:transcriptMode 设置该组件的滚动模式

使用ListView步骤

  1. 准备ListView所要显示的数据
  2. 使用数组或List集合存储数据
  3. 创建适配器(Adapter),作为列表项数据源
  4. 将适配器对象(Adapter)添加到ListView,并进行展示
  • 自定义的ListView

    ListView组件id为用户自定义字段

复杂ListView的使用

  • 实现图文混排步骤:
    • 定义行选项的布局格式
    • 自定义一个Adapter,并重写其中的关键方法
    • 注册列表选项的单击事件
    • 创建Activity并加载对应的布局文件

ArrayAdapter

用ArrayAdapter实现ListView步骤

  • 步骤其实和使用ListView是一样的,这里简写成三步
  1. 准备ListView所要显示的数据
  2. 将数据和适配器(Adapter)相关联
  3. 将适配器对象(Adapter)添加到ListView,并进行展示

测试样例代码

image-20220405222105584

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
package com.gallifrey.todayapplication.listview;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import com.gallifrey.todayapplication.R;

import java.util.LinkedList;
import java.util.List;

public class ListViewActivity extends AppCompatActivity {
private ListView mlv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);

mlv=findViewById(R.id.lv1);
// ArrayAdapter创建方式一
// ArrayAdapter<CharSequence> adapter=ArrayAdapter.createFromResource(this,R.array.car, android.R.layout.simple_expandable_list_item_1);
// mlv.setAdapter(adapter);

// ArrayAdapter创建方式二
List<String> datalist=new LinkedList<>();
datalist.add("大众");
datalist.add("丰田");
datalist.add("福特");
datalist.add("比亚迪");
datalist.add("哈弗");
// ArrayAdapter adapter=new ArrayAdapter(this, android.R.layout.simple_list_item_1,datalist);
ArrayAdapter adapter=new ArrayAdapter(this, android.R.layout.simple_list_item_single_choice,datalist);
mlv.setAdapter(adapter);
mlv.addHeaderView(LayoutInflater.from(this).inflate(R.layout.viewhead,null));
mlv.addFooterView(LayoutInflater.from(this).inflate(R.layout.viewfoot,null));

mlv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
Toast.makeText(ListViewActivity.this,i+" Clicked",Toast.LENGTH_LONG).show();
}
});
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?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"
android:padding="5dp"
tools:context=".listview.ListViewActivity">

<ListView
android:id="@+id/lv1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@color/purple_200"
android:dividerHeight="5dp"
android:listSelector="@drawable/listseletor"
android:stackFromBottom="true"
android:choiceMode="multipleChoice"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="-68dp" />
<!--android:entries="@array/car" 设置静态数组-->

</androidx.constraintlayout.widget.ConstraintLayout>
  • viewfoot.xml
1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:layout_width="match_parent"
android:layout_height="100dp"
android:gravity="center"
android:background="@drawable/school"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
  • viewhead.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"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<TextView
android:layout_width="match_parent"
android:layout_height="48dp"
android:text="表头"
android:textSize="26sp"
android:background="#FF5722"
android:textStyle="bold"
android:textColor="@color/white"
android:gravity="center"
app:layout_constraintTop_toTopOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>
  • 假如使用静态加载数组/链表 ,可以在value目录下创建资源文件,以下以arrays.xml为例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="car">
<item>别克</item>
<item>宝马</item>
<item>奥迪</item>
<item>奔驰</item>
<item>保时捷</item>
<item>凯迪拉克</item>
<item>劳斯莱斯</item>
<item>法拉利</item>
<item>宾利</item>

</string-array>
</resources>

BaseAdapter

用baseAdapter实现图文混排步骤

  • 定义行选项的布局格式
  • 自定义一个Adapter,并重写其中的关键方法(四个方法,其中getCout(),getView()是重点)
  • 注册列表选项的单击事件
  • 创建Activity并加载对应的布局文件
1
ps:Layout下的<android:descendantFocusability="blocksDescendants" >可以设置不抢占焦点

测试样例代码

效果图

新增(绿)与修改(蓝)的文件

  • Flower实体类
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
package com.gallifrey.todayapplication.listview;

public class Flower {
private int imageId;
private String name;
private String content;
private Boolean checkStatus;
public Flower(int imageId,String name,String content){
this.imageId=imageId;
this.name=name;
this.content=content;
checkStatus=false;
}

public int getImageId() {
return imageId;
}

public void setImageId(int imageId) {
this.imageId = imageId;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}

public Boolean getCheckStatus() {
return checkStatus;
}

public void setCheckStatus(Boolean checkStatus) {
this.checkStatus=checkStatus;
}
}
  • FolwerAdapter类和对应xml布局文件(继承自BaseAadpter类)
  • 对getView()方法进行了优化,详情请看代码
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package com.gallifrey.todayapplication.listview;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;

import com.gallifrey.todayapplication.R;

import java.nio.channels.ClosedByInterruptException;
import java.util.LinkedList;

public class FlowerAdapter extends BaseAdapter {
private LinkedList<Flower> mDatalist;
private Context mContext;
private int count=0;//添加一个计数器看看,优化后view的创建次数
public FlowerAdapter(LinkedList<Flower> datalist, Context context){
mDatalist=datalist;
mContext=context;
}

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

@Override
public Object getItem(int i) {
return mDatalist.get(i);
}

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


/**
*这是优化前的代码,可重用性低,view不断新建,组件也不断查找
*
public View getView(int i, View view, ViewGroup viewGroup) {
view = LayoutInflater.from(mContext).inflate(R.layout.listitem, viewGroup, false);
ImageView item_iv=view.findViewById(R.id.item_iv);
TextView item_name=view.findViewById(R.id.item_name);
TextView item_content=view.findViewById(R.id.item_content);


item_iv.setImageResource(mDatalist.get(i).getImageId());
item_name.setText(mDatalist.get(i).getName());
item_content.setText(mDatalist.get(i).getContent());
return view;
}

**/
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder=null;
//优化,为空才构造view;那样只有创建第一页能显示的花的view,之后的直接重用好了
//实际测试效果是创建了7个view
if(view==null) {
//动态构造
view = LayoutInflater.from(mContext).inflate(R.layout.listitem, viewGroup, false);
viewHolder=new ViewHolder();

viewHolder.item_iv=view.findViewById(R.id.item_iv);
viewHolder.item_name=view.findViewById(R.id.item_name);
viewHolder.item_content=view.findViewById(R.id.item_content);
viewHolder.item_check=view.findViewById(R.id.item_check);
view.setTag(viewHolder);//用view记录数据,不用重复查找
count++;//view的创建数+1
}else {
viewHolder=(ViewHolder)view.getTag();//重新赋值
}
Log.i("Flower", "getView: 测试一下优化效果 "+count);
//记录一下位置
viewHolder.item_check.setTag(i);
viewHolder.item_check.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
//重新获取位置并设置状态
int index=(int)compoundButton.getTag();
mDatalist.get(index).setCheckStatus(b);
}
});
//重新设置
viewHolder.item_check.setChecked(mDatalist.get(i).getCheckStatus());
viewHolder.item_iv.setImageResource(mDatalist.get(i).getImageId());
viewHolder.item_name.setText(mDatalist.get(i).getName());
viewHolder.item_content.setText(mDatalist.get(i).getContent());
return view;
}

//优化,添加一个静态类记录数据,增加重用性
static class ViewHolder{
ImageView item_iv;
TextView item_name;
TextView item_content;
CheckBox item_check;

}

//添加点击删除功能
public void remove(int position){
if(mDatalist!=null){
mDatalist.remove(position);
}
//更新变化的信息
notifyDataSetChanged();

}
}
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
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants"
android:paddingHorizontal="10dp">
<CheckBox
android:layout_width="wrap_content"
android:layout_height="100dp"
android:gravity="center_vertical"
android:button="@drawable/checkbox_bg_round"
android:buttonTint="@drawable/checkbox_color_round"
android:id="@+id/item_check"/>

<ImageView
android:id="@+id/item_iv"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginStart="15dp"
android:layout_toEndOf="@id/item_check"
android:scaleType="centerCrop" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:id="@+id/item_name"
android:layout_toEndOf="@id/item_iv"
android:layout_marginStart="15dp"
android:textSize="26sp"
android:textStyle="bold"/>

<TextView
android:id="@+id/item_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/item_name"
android:layout_marginTop="15dp"
android:layout_alignStart="@id/item_name"
android:textSize="26sp" />



</RelativeLayout>
  • 在ListView中添加FlowerAdapter
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
package com.gallifrey.todayapplication.listview;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import com.gallifrey.todayapplication.R;

import java.util.LinkedList;
import java.util.List;

public class ListViewActivity extends AppCompatActivity {
private ListView mlv;
private List<Flower> flowerList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_list_view);

mlv=findViewById(R.id.lv1);

initFlower();
FlowerAdapter flowerAdapter=new FlowerAdapter((LinkedList<Flower>) flowerList,this);
mlv.setAdapter(flowerAdapter);
mlv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
flowerAdapter.remove(i);
Toast.makeText(ListViewActivity.this,i+" Clicked",Toast.LENGTH_LONG).show();
}
});
}

private void initFlower() {
flowerList=new LinkedList<>();
flowerList.add(new Flower(R.drawable.baihe,"百合","百年好合"));
flowerList.add(new Flower(R.drawable.rose,"红玫瑰","富有热情"));
flowerList.add(new Flower(R.drawable.yinghua,"樱花","幸福永远"));
flowerList.add(new Flower(R.drawable.sunflower,"向日葵","光辉忠诚"));
flowerList.add(new Flower(R.drawable.ziluolan,"紫罗兰","永恒的美与爱"));
flowerList.add(new Flower(R.drawable.jidanhua,"鸡蛋花","孕育希望复活"));

flowerList.add(new Flower(R.drawable.baihe,"百合22","百年好合"));
flowerList.add(new Flower(R.drawable.rose,"红玫瑰22","富有热情"));
flowerList.add(new Flower(R.drawable.yinghua,"樱花22","幸福永远"));
flowerList.add(new Flower(R.drawable.sunflower,"向日葵22","光辉忠诚"));
flowerList.add(new Flower(R.drawable.ziluolan,"紫罗兰22","永恒的美与爱"));
flowerList.add(new Flower(R.drawable.jidanhua,"鸡蛋花22","孕育希望复活"));
}
}

ListView多布局

  • 实现多布局步骤:
    1. 定义行选项的布局格式
    2. 自定义一个Adapter,并重写其中的关键方法
    3. 为ListView设置适配器

测试样例代码

image-20220425021855874

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
package com.gallifrey.todayapplication.listview;

public class PersonChat {
private int imageId;
private String words;
private Boolean status;
public PersonChat(int imageId,String words,Boolean status){
this.imageId=imageId;
this.words=words;
this.status=status;
}

public int getImageId() {
return imageId;
}

public void setImageId(int imageId) {
this.imageId = imageId;
}

public String getWords() {
return words;
}

public void setWords(String words) {
this.words = words;
}

public Boolean getStatus() {
return status;
}

public void setStatus(Boolean status) {
this.status = status;
}
}
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
package com.gallifrey.todayapplication.listview;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.gallifrey.todayapplication.R;

import java.util.List;

public class MultiLayoutAdapter extends BaseAdapter {
private static final int TYPE_LEFT=0;
private static final int TYPE_RIGHT=1;
private List<PersonChat> mData;
private Context mContext;
public MultiLayoutAdapter(List<PersonChat> data,Context context){
mData=data;
mContext=context;
}

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

@Override
public Object getItem(int i) {
return mData.get(i);
}

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


static class ViewHolder{
ImageView imageView;
TextView textView;
}

@Override
public View getView(int i, View view, ViewGroup viewGroup) {
int type=getItemViewType(i);
ViewHolder viewHolder=null;
if(view==null){
switch (type){
case TYPE_LEFT:
view= LayoutInflater.from(mContext).inflate(R.layout.listitem_left,viewGroup,false);
break;
case TYPE_RIGHT:
view= LayoutInflater.from(mContext).inflate(R.layout.listitem_right,viewGroup,false);
break;
}
viewHolder =new ViewHolder();
viewHolder.imageView=view.findViewById(R.id.item_iv);
viewHolder.textView=view.findViewById(R.id.item_tv);
view.setTag(viewHolder);
}else{
viewHolder= (ViewHolder) view.getTag();
}
viewHolder.imageView.setImageResource(mData.get(i).getImageId());
viewHolder.textView.setText(mData.get(i).getWords());
return view;
}

//行选项布局的数量
@Override
public int getViewTypeCount() {
return 2;
}

//行选项布局的类型
@Override
public int getItemViewType(int position) {
if(mData.get(position).getStatus()){
return TYPE_RIGHT;
}else {
return TYPE_LEFT;
}
}
}
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
package com.gallifrey.todayapplication.listview;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import com.gallifrey.todayapplication.R;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class ListViewActivity extends AppCompatActivity {
private ListView mlv;
private List<Flower> flowerList;
private List<PersonChat> personChatList;
private static final int TYPE_LEFT=0;
private static final int TYPE_RIGHT=1;

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

mlv=findViewById(R.id.lv1);
intiPersonChat();
mlv.setAdapter(new MultiLayoutAdapter(personChatList,this));

}

private void intiPersonChat(){
personChatList=new ArrayList<>();
for (int i=0;i<20;i++){
switch ((int)(Math.random()*2)){
case TYPE_LEFT:
personChatList.add(new PersonChat(R.drawable.left_img,"LE"+i,false));
break;
case TYPE_RIGHT:
personChatList.add(new PersonChat(R.drawable.right_img,"RE"+i,true));
break;

};
}
};


}

listitem_right布局和listitem_left只有位置上有镜像区别,这里就不重复给出了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="64dp"
android:layout_height="64dp"
android:id="@+id/item_iv"
android:scaleType="centerCrop"/>

<TextView
android:id="@+id/item_tv"
android:layout_width="158dp"
android:layout_height="62dp"
android:layout_marginStart="3dp"

android:layout_toEndOf="@id/item_iv"
android:background="@mipmap/left_dialog"
android:gravity="center"
android:textSize="26sp"/>

</RelativeLayout>

GridView

GridView网格视图

  • 用于按行和列的分布方式来显示多个组件
  • 通过Adapter来提供显示数据
XML属性 功能描述
android:numColumns 设置列数
android:columnWidth 设置每一列的宽度
android:stretchMode 设置拉伸模式
android:verticalSpacing 设置各个元素之间的垂直边距
android:horizontalSpacing 设置各个元素之间的水平边距

GridView本地数据显示

  • 创建GridView的步骤:
    1. ·在布局文件中使用<GridView>元素来定义GridView组件
    2. 自定义一个Adapter,并重写其中的关键方法
    3. 为GridView设置适配器

测试样例代码

image-20220425041304228

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
package com.gallifrey.todayapplication.gridview;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.GridView;

import com.gallifrey.todayapplication.R;
import com.gallifrey.todayapplication.listview.Flower;

import java.util.LinkedList;
import java.util.List;

public class GridViewActivity extends AppCompatActivity {
private GridView mGv;
private List<Flower> flowerList;

public GridViewActivity() {
}

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

mGv=findViewById(R.id.gv);
initFlower();
mGv.setAdapter(new GridFlowerAdapter(flowerList,this));
}


private void initFlower() {
flowerList=new LinkedList<>();
flowerList.add(new Flower(R.drawable.baihe,"百合","百年好合"));
flowerList.add(new Flower(R.drawable.rose,"红玫瑰","富有热情"));
flowerList.add(new Flower(R.drawable.yinghua,"樱花","幸福永远"));
flowerList.add(new Flower(R.drawable.sunflower,"向日葵","光辉忠诚"));
flowerList.add(new Flower(R.drawable.ziluolan,"紫罗兰","永恒的美与爱"));
flowerList.add(new Flower(R.drawable.jidanhua,"鸡蛋花","孕育希望复活"));

flowerList.add(new Flower(R.drawable.baihe,"百合22","百年好合"));
flowerList.add(new Flower(R.drawable.rose,"红玫瑰22","富有热情"));
flowerList.add(new Flower(R.drawable.yinghua,"樱花22","幸福永远"));
flowerList.add(new Flower(R.drawable.sunflower,"向日葵22","光辉忠诚"));
flowerList.add(new Flower(R.drawable.ziluolan,"紫罗兰22","永恒的美与爱"));
flowerList.add(new Flower(R.drawable.jidanhua,"鸡蛋花22","孕育希望复活"));
}
}
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
package com.gallifrey.todayapplication.gridview;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.gallifrey.todayapplication.R;
import com.gallifrey.todayapplication.listview.Flower;

import java.util.List;

public class GridFlowerAdapter extends BaseAdapter {
private List<Flower> mData;
private Context mContext;

public GridFlowerAdapter(List<Flower> data,Context context){
mData=data;
mContext=context;
}
@Override
public int getCount() {
return mData.size();
}

@Override
public Object getItem(int i) {
return mData.get(i);
}

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

@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder=null;
if (view==null){
view= LayoutInflater.from(mContext).inflate(R.layout.griditem,viewGroup,false);
viewHolder=new ViewHolder();
viewHolder.imageView=view.findViewById(R.id.gv_iv);
viewHolder.textView=view.findViewById(R.id.gv_tv);
view.setTag(viewHolder);
}else{
viewHolder= (ViewHolder) view.getTag();
}
viewHolder.imageView.setImageResource(mData.get(i).getImageId());
viewHolder.textView.setText(mData.get(i).getName());
return view;
}

static class ViewHolder{
ImageView imageView;
TextView textView;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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"
tools:context=".gridview.GridViewActivity">
<GridView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/gv"
android:numColumns="3"
android:horizontalSpacing="10dp"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
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
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:id="@+id/gv_iv"
android:src="@drawable/baihe"
app:layout_constraintTop_toTopOf="parent"
android:scaleType="centerCrop"
app:layout_constraintBottom_toTopOf="@id/gv_tv"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/gv_tv"
android:textSize="26sp"
android:text="test"
android:gravity="center"
android:layout_marginTop="10dp"
app:layout_constraintTop_toBottomOf="@id/gv_iv"
app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

GridView网络数据显示

  • 使用步骤:

    1. 设置网络权限,在AndroidManifest.xml文件中添加<uses-permission android:name="android.permission.INTERNET"/>

    2. 添加glide依赖,并同步,GitHub链接bumptech/glide

      1
      2
      3
      4
      dependencies {
      implementation 'com.github.bumptech.glide:glide:4.13.0'
      annotationProcessor 'com.github.bumptech.glide:compiler:4.13.0'
      }
    3. 使用Glide类添加图片

测试样例代码

image-20220425050626201

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
package com.gallifrey.todayapplication.gridview;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.GridView;

import com.gallifrey.todayapplication.R;
import com.gallifrey.todayapplication.listview.Flower;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

public class GridViewActivity extends AppCompatActivity {
private GridView mGv;
private List<Flower> flowerList;
private List<String> imgNetList;
public GridViewActivity() {
}

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

mGv=findViewById(R.id.gv);
initImageNet();
mGv.setAdapter(new GridFlowerAdapter(imgNetList,this));
}

//网络资源的加载
private void initImageNet() {
imgNetList=new ArrayList<>();
imgNetList.add("https://gallifrey.asia/img/kyueki01.webp");
imgNetList.add("https://gallifrey.asia/img/kyueki02.webp");
imgNetList.add("https://gallifrey.asia/img/kyueki03.webp");
imgNetList.add("https://gallifrey.asia/img/kyueki04.webp");
imgNetList.add("https://gallifrey.asia/img/kyueki05.webp");
imgNetList.add("https://gallifrey.asia/img/kyueki06.webp");
imgNetList.add("https://gallifrey.asia/img/kyueki07.webp");
imgNetList.add("https://gallifrey.asia/img/kyueki08.webp");
imgNetList.add("https://gallifrey.asia/img/kyueki09.webp");

}

}
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
package com.gallifrey.todayapplication.gridview;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.gallifrey.todayapplication.R;
import com.gallifrey.todayapplication.listview.Flower;

import java.util.List;

public class GridFlowerAdapter extends BaseAdapter {
private List<String> mData;
private Context mContext;

public GridFlowerAdapter(List<String> data,Context context){
mData=data;
mContext=context;
}
@Override
public int getCount() {
return mData.size();
}

@Override
public Object getItem(int i) {
return mData.get(i);
}

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

@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder=null;
if (view==null){
view= LayoutInflater.from(mContext).inflate(R.layout.griditem,viewGroup,false);
viewHolder=new ViewHolder();
viewHolder.imageView=view.findViewById(R.id.gv_iv);
viewHolder.textView=view.findViewById(R.id.gv_tv);
view.setTag(viewHolder);
}else{
viewHolder= (ViewHolder) view.getTag();
}


Glide.with(mContext)
.load(mData.get(i))
.centerCrop()
.placeholder(R.mipmap.ic_launcher)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.into(viewHolder.imageView);
viewHolder.textView.setText("图片"+i);
return view;
}

static class ViewHolder{
ImageView imageView;
TextView textView;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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"
tools:context=".gridview.GridViewActivity">
<GridView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/gv"
android:numColumns="2"
android:horizontalSpacing="10dp"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
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"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:id="@+id/gv_iv"
app:layout_constraintTop_toTopOf="parent"
android:scaleType="centerCrop"
app:layout_constraintBottom_toTopOf="@id/gv_tv"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/gv_tv"
android:textSize="26sp"
android:gravity="center"
android:layout_marginTop="10dp"
app:layout_constraintTop_toBottomOf="@id/gv_iv"
app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

RecyclerView

简介

  • 使用:

    1. 设置Adapter
    2. 设置LayoutManager
  • RecyclerView提供了三种布局管理器:

    1. LinerLayoutManager 以垂直或者水平列表方式展示Item
    2. GridLayoutManager 以网格方式展示Item
    3. StaggeredGridLayoutManager 以瀑布流方式展示Item

测试样例代码

image-20220505105128931

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
package com.gallifrey.todayapplication.recyclerview;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.gallifrey.todayapplication.R;
import com.gallifrey.todayapplication.listview.Flower;

import java.util.List;

public class RecyclerFlowerAdapter extends RecyclerView.Adapter<RecyclerFlowerAdapter.ViewHolder>{
private List<Flower> mData;
private Context mContext;

public RecyclerFlowerAdapter(List<Flower> mData, Context mContext) {
this.mData = mData;
this.mContext = mContext;
}

static class ViewHolder extends RecyclerView.ViewHolder{
ImageView imageView;
TextView textView;
public ViewHolder(@NonNull View itemView) {
super(itemView);
imageView=itemView.findViewById(R.id.rv_iv);
textView=itemView.findViewById(R.id.rv_tv);
}
}


@NonNull
@Override
public RecyclerFlowerAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// View view= LayoutInflater.from(mContext).inflate(R.layout.recyclerlinearitem,parent,false); //测试线性布局管理器和网格布局管理器
// View view=LayoutInflater.from(mContext).inflate(R.layout.recyclersvitem,parent,false);//测试瀑布流布局管理器
View view=LayoutInflater.from(mContext).inflate(R.layout.recyclershitem,parent,false);//测试瀑布流布局管理器
ViewHolder viewHolder =new ViewHolder(view);



return viewHolder;
}

@Override
public void onBindViewHolder(@NonNull RecyclerFlowerAdapter.ViewHolder holder, int position) {
holder.imageView.setImageResource(mData.get(position).getImageId());
holder.textView.setText(mData.get(position).getName());

}

@Override
public int getItemCount() {
return mData.size();
}
}
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
package com.gallifrey.todayapplication.recyclerview;

import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import android.os.Bundle;
import android.widget.GridLayout;
import android.widget.LinearLayout;

import com.gallifrey.todayapplication.R;
import com.gallifrey.todayapplication.listview.Flower;

import java.util.LinkedList;
import java.util.List;

public class RecyclerViewActivity extends AppCompatActivity {
private RecyclerView mRv;
private List<Flower> flowerList;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycle_view);
initFlower();
mRv=findViewById(R.id.rv);

// 测试线性布局管理器
// LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);
// linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
// mRv.setLayoutManager(linearLayoutManager);

// 测试网格布局管理器
// GridLayoutManager gridLayoutManager=new GridLayoutManager(this,2);
// gridLayoutManager.setOrientation(GridLayoutManager.HORIZONTAL);
// mRv.setLayoutManager(gridLayoutManager);

// 测试瀑布流布局管理器 垂直方向
// StaggeredGridLayoutManager staggeredGridLayoutManager=new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.VERTICAL);
// mRv.setLayoutManager(staggeredGridLayoutManager);
// 测试瀑布流布局管理器 水平方向
StaggeredGridLayoutManager staggeredGridLayoutManager=new StaggeredGridLayoutManager(2,StaggeredGridLayoutManager.HORIZONTAL);
mRv.setLayoutManager(staggeredGridLayoutManager);


// 设置适配器
mRv.setAdapter(new RecyclerFlowerAdapter(flowerList,this));

}


private void initFlower() {
flowerList=new LinkedList<>();
flowerList.add(new Flower(R.drawable.baihe,"百合","百年好合"));
flowerList.add(new Flower(R.drawable.rose,"红玫瑰","富有热情"));
flowerList.add(new Flower(R.drawable.yinghua,"樱花","幸福永远"));
flowerList.add(new Flower(R.drawable.sunflower,"向日葵","光辉忠诚"));
flowerList.add(new Flower(R.drawable.ziluolan,"紫罗兰","永恒的美与爱"));
flowerList.add(new Flower(R.drawable.jidanhua,"鸡蛋花","孕育希望复活"));

flowerList.add(new Flower(R.drawable.baihe,"百合22","百年好合"));
flowerList.add(new Flower(R.drawable.rose,"红玫瑰22","富有热情"));
flowerList.add(new Flower(R.drawable.yinghua,"樱花22","幸福永远"));
flowerList.add(new Flower(R.drawable.sunflower,"向日葵22","光辉忠诚"));
flowerList.add(new Flower(R.drawable.ziluolan,"紫罗兰22","永恒的美与爱"));
flowerList.add(new Flower(R.drawable.jidanhua,"鸡蛋花22","孕育希望复活"));
}
}
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
package com.gallifrey.todayapplication.listview;

public class Flower {
private int imageId;
private String name;
private String content;
private Boolean checkStatus;
public Flower(int imageId,String name,String content){
this.imageId=imageId;
this.name=name;
this.content=content;
checkStatus=false;
}

public int getImageId() {
return imageId;
}

public void setImageId(int imageId) {
this.imageId = imageId;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}

public Boolean getCheckStatus() {
return checkStatus;
}

public void setCheckStatus(Boolean checkStatus) {
this.checkStatus=checkStatus;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
<?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"
tools:context=".recyclerview.RecyclerViewActivity">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/rv"/>

</androidx.constraintlayout.widget.ConstraintLayout>
  • recyclerlinearitem.xml 线性布局/网格布局
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?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">
<ImageView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/rv_iv"
android:src="@drawable/baihe"
android:scaleType="centerCrop"

/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/rv_tv"
android:text="test"
android:textSize="26sp"
android:gravity="center"
android:layout_marginTop="10dp"/>
</LinearLayout>
  • recyclershitem.xml 瀑布流布局 水平方向
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
android:id="@+id/rv_iv"
android:src="@drawable/baihe"
android:scaleType="centerCrop" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/rv_tv"
android:text="test"
android:layout_gravity="center"
android:textSize="26sp"
android:gravity="center"
android:layout_marginTop="10dp"/>
</LinearLayout>
  • recyclersvitem.xml 瀑布流布局 垂直方向
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/rv_iv"
android:src="@drawable/baihe"
android:scaleType="centerCrop"

/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/rv_tv"
android:text="test"
android:textSize="26sp"
android:gravity="center"
android:layout_marginTop="10dp"/>
</LinearLayout>

TabHost与TabLayout

TabHost

  • 实现在窗口中放置多个标签页
  • 通常需要与TabWidget、TabSpec组件结合使用
    • TabWidget:显示TabHost标签页中上部和下部的按钮
    • TabSpec:选项卡界面
  • TabHost创建、添加选项卡的方法:
    • newTabSpec(String tag):创建选项卡
    • addTab(tabSpec):添加选项卡

image-20220505113237304

继承TabActivity使用TabHost

  • 继承TabActivity时使用TabHost的步骤:
    1. 创建一个Activity:继承TabActivity
    2. 定义布局: id必须使用系统ID
    3. 获取组件: getTabHost()
    4. 创建选项卡

不继承TabActivity使用TabHost

  • 不继承TabActivity时使用TabHost的步骤:
    1. 创建Activity:不继承TabActivity
    2. 定义布局:id可以自定义
    3. 获取组件:findViewById()
    4. 创建选项卡

TabActivity在Android 3.0以后已过时,推荐使用“不继承TabActivity的方式”使用TabHost

TabLayout

Tabhost因为无法实现滑动已经不常用了,现在的实现标签选项卡的方式是TabLayout+ViewPager

TabLayout + ViewPager

  • 什么是TabLayout:
    • 一个水平的布局用来展示Tabs
  • 怎么使用:
    1. 定义布局,为TabLayout添加tab
    2. 定义适配器PagerAdapter
    3. ViewPager设置适配器
    4. TabLayout加载ViewPager
  • 属性和方法
属性 方法
tabIndicatorFullWidth addTab()
tabRippleColor getTabAt()
tabTextAppearance getTabCount()
tabMode newTab()
tabIndicatorColor removeAllTabs()
tabIndicatorHeight removeTab()
tabIndicatorGravity

上表中tablayout的属性和方法没有对应关系

测试样例代码

viewPager已经停止维护了,这里使用官方推荐的viewPager2

image-20220505211737934

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package com.gallifrey.todayapplication.tablayout;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager2.widget.ViewPager2;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.gallifrey.todayapplication.R;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;

import java.util.ArrayList;
import java.util.List;

public class TabLayoutActivity extends AppCompatActivity {
private TabLayout mTabLayout;
private List<IconRelation> iconRelationList;
private List<Fragment> fragmentList;
// private ViewPager viewPager;
// viewPage已经停止维护,改为使用viewPage2
private ViewPager2 viewPager2;
@Override

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tab_layout);
mTabLayout=findViewById(R.id.tab_layout);
// viewPager=findViewById(R.id.view_pager);
viewPager2=findViewById(R.id.view_pager2);


//通过代码动态添加选项卡
// mTabLayout.addTab(mTabLayout.newTab().setText("tab1"));
// mTabLayout.addTab(mTabLayout.newTab().setText("tab2"));
// mTabLayout.addTab(mTabLayout.newTab().setText("tab3"));

//初始化图标
initIcon();
//初始化fragment
intiFragment();
//viewPager设置适配器
// viewPager.setAdapter(new ImageAdapter(getSupportFragmentManager(), FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT,fragmentList));
// mTabLayout.setupWithViewPager(viewPager);

// viewPage2设置适配器
viewPager2.setAdapter(new ImageStateAdapter(this,fragmentList));
// 实现viewPage2和tabLayout联动
new TabLayoutMediator(mTabLayout, viewPager2, new TabLayoutMediator.TabConfigurationStrategy() {
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
tab.setCustomView(getTabView(iconRelationList,position));
}
}).attach();

// for (int i = 0; i <iconRelationList.size(); i++) {
//// mTabLayout.addTab(mTabLayout.newTab());
// mTabLayout.getTabAt(i).setCustomView(getTabView(iconRelationList,i));
// }
//设置默认选项
mTabLayout.getTabAt(2).select();

//设置监听
mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
View view=tab.getCustomView();
ImageView imageView=view.findViewById(R.id.tab_iv);
TextView textView=view.findViewById(R.id.tab_tv);
imageView.setSelected(true);
textView.setTextAppearance(R.style.TabSelectedStyle);
}

@Override
public void onTabUnselected(TabLayout.Tab tab) {
View view=tab.getCustomView();
ImageView imageView=view.findViewById(R.id.tab_iv);
TextView textView=view.findViewById(R.id.tab_tv);
imageView.setSelected(false);
textView.setTextAppearance(R.style.TabUnSelectedStyle);
}

@Override
public void onTabReselected(TabLayout.Tab tab) {

}
});
}

private void intiFragment() {
fragmentList=new ArrayList<>();
fragmentList.add(MessageFragment.newInstance(R.drawable.laohu));
fragmentList.add(MessageFragment.newInstance(R.drawable.ziluolande));
fragmentList.add(MessageFragment.newInstance(R.drawable.baihe));
fragmentList.add(MessageFragment.newInstance(R.drawable.classroom));
}

private View getTabView(List<IconRelation> data,int position) {
View view= LayoutInflater.from(this).inflate(R.layout.tab_item,null);
ImageView imageView=view.findViewById(R.id.tab_iv);
TextView textView=view.findViewById(R.id.tab_tv);
imageView.setImageResource(data.get(position).getImageId());
textView.setText(data.get(position).getName());
return view;
}

private void initIcon() {
iconRelationList=new ArrayList<>();
iconRelationList.add(new IconRelation(R.drawable.fl_rb_message_bg,"消息"));
iconRelationList.add(new IconRelation(R.drawable.fl_rb_phone_bg,"通讯"));
iconRelationList.add(new IconRelation(R.drawable.fl_rb_discover_bg,"发现"));
iconRelationList.add(new IconRelation(R.drawable.fl_rb_me_bg,"我的"));
}
}
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
package com.gallifrey.todayapplication.tablayout;

public class IconRelation {
private int imageId;
private String name;

public IconRelation(int imageId, String name) {
this.imageId = imageId;
this.name = name;
}

public int getImageId() {
return imageId;
}

public void setImageId(int imageId) {
this.imageId = imageId;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
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
package com.gallifrey.todayapplication.tablayout;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;

import java.util.List;

public class ImageStateAdapter extends FragmentStateAdapter {
private List<Fragment>fragmentList;
public ImageStateAdapter(@NonNull FragmentActivity fragmentActivity, List<Fragment> fragmentList) {
super(fragmentActivity);
this.fragmentList=fragmentList;
}

@NonNull
@Override
public Fragment createFragment(int position) {
return fragmentList.get(position);
}

@Override
public int getItemCount() {
return fragmentList.size();
}
}
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
package com.gallifrey.todayapplication.tablayout;

import android.os.Bundle;

import androidx.fragment.app.Fragment;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import com.gallifrey.todayapplication.R;

/**
* A simple {@link Fragment} subclass.
* Use the {@link MessageFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class MessageFragment extends Fragment {

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
// private static final String ARG_PARAM2 = "param2";

// TODO: Rename and change types of parameters
private int mParam1;

public MessageFragment() {
// Required empty public constructor
}

/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
// * @param param2 Parameter 2.
* @return A new instance of fragment MessageFragment.
*/
// TODO: Rename and change types and number of parameters
public static MessageFragment newInstance(int param1) {
MessageFragment fragment = new MessageFragment();
Bundle args = new Bundle();
args.putInt(ARG_PARAM1, param1);
// args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getInt(ARG_PARAM1);
// mParam2 = getArguments().getString(ARG_PARAM2);
}
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view= inflater.inflate(R.layout.fragment_message2, container, false);
ImageView imageView=view.findViewById(R.id.fl_iv);
imageView.setImageResource(mParam1);
return view;
}
}
  • activity_tab_layout.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
<?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"
tools:context=".tablayout.TabLayoutActivity">
<com.google.android.material.tabs.TabLayout
app:tabIndicatorColor="#05d236"
app:tabIndicatorHeight="5dp"
app:tabIndicatorFullWidth="false"
app:tabTextColor="#6F392727"
app:tabSelectedTextColor="#05d236"
app:tabTextAppearance="@style/TabStyle"
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<!-- 静态添加 -->
<!-- <com.google.android.material.tabs.TabItem-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="match_parent"-->
<!-- android:text="tab1"/>-->
<!-- <com.google.android.material.tabs.TabItem-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="match_parent"-->
<!-- android:text="tab2"/>-->
<!-- <com.google.android.material.tabs.TabItem-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="match_parent"-->
<!-- android:text="tab3"/>-->



</com.google.android.material.tabs.TabLayout>
<!-- viewPage已经停止维护,请使用viewPage2-->
<!-- <androidx.viewpager.widget.ViewPager-->
<!-- android:id="@+id/view_pager"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="0dp"-->
<!-- app:layout_constraintVertical_weight="1"-->
<!-- app:layout_constraintTop_toBottomOf="@id/tab_layout"-->
<!-- />-->
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager2"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintVertical_weight="1"
app:layout_constraintTop_toBottomOf="@id/tab_layout"
/>


</androidx.constraintlayout.widget.ConstraintLayout>
  • fragment_message2.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?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"
tools:context=".tablayout.MessageFragment">

<!-- TODO: Update blank fragment layout -->
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fl_iv"
android:scaleType="centerCrop"
/>

</FrameLayout>
  • tab_item.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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"
android:padding="5dp">
<TextView
android:layout_width="48dp"
android:layout_height="wrap_content"
android:id="@+id/tab_tv"
android:text="测试"
android:textColor="#a5a5a5"
android:textSize="20sp"/>
<ImageView
android:layout_width="48dp"
android:layout_height="48dp"
android:id="@+id/tab_iv"
android:scaleType="center"
android:src="@drawable/fl_rb_message_bg"/>

</LinearLayout>
  • 在values文件夹下新建styles.xml文件添加字体选中效果样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="TabStyle">
<item name="android:textSize">30sp</item>
<item name="android:textStyle">bold</item>
</style>

<style name="TabSelectedStyle">
<item name="android:textColor">#05d236</item>
<item name="android:textStyle">bold</item>
</style>

<style name="TabUnSelectedStyle">
<item name="android:textColor">#a5a5a5</item>
<item name="android:textStyle">normal</item>
</style>

</resources>
  • drawable文件夹下添加图标变化的样式,写法一样这里给出一个样例(其实就是设置两张照片,选中时为有色图标,非选中为灰色图标)
1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="@mipmap/discover2"/>
<item android:state_selected="false" android:drawable="@mipmap/discover"/>
</selector>

WebView

基础知识

  • WebView用于在App中加载网页
  • 使用Web检查器来调试HTML、CSS、Javascript等代码
  • 可以对URL请求、页面加载、渲染以及页面的交互进行处理
  • WebView具有以下几个辅助类:
    • WebChromeClient:辅助WebView实现与浏览器的交互动作
    • WebViewClient:帮助WebView处理各种通知、请求事件等
    • WebSettings:对WebView进行配置和管理
    • addJavascriptInterface():将Java对象绑定到WebView中,以便JavaScript从页面中控制Java对象,实现WebView与HTML页面的交互

使用WebView的步骤

  • 在AndroidManifest.xml中配置访问权限<uses-permission android:name="android.permission.INTERNET" />

  • 在布局文件中创建WebView元素

  • 在代码中加载网页

  • 用loadUrl()加载本地存储的HTML页面内容

  • 或用loadDataWithBaseURL()方法将HTML代码片段

WebView使用介绍

image-20220506003959704

测试样例代码

示例中实现了WebView与JavaScript的交互,以及WebView和Activity的交互

image-20220506025231092

  • 如果要应用访问网络网站,而且能通过明文网址访问,要修改AndroidManifest.xml文件相关设置
  • 加入联网许可
1
<uses-permission android:name="android.permission.INTERNET" />
  • 支持明文
1
2
<application
android:usesCleartextTraffic="true"/>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<head><title>Welcome to Webview</title></head>
<body>
<center>
<div style="margin-top:10%; font-size:30">Js调用Android</div>
<button style="margin-top:10%; width:160;height:60;font-size:30" onclick="android.login()">登陆</button>
<h1 style="margin-top:10%" id="username"></h1>
</center>
<script>
function showUserName(username){
document.getElementById("username").innerText="登录名:"+username;
}
</script>
</body>
</html>
  • WebViewActivity类
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package com.gallifrey.todayapplication.webview;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.Bundle;
import android.view.KeyEvent;
import android.webkit.JavascriptInterface;
import android.webkit.SslErrorHandler;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.TextView;

import com.gallifrey.todayapplication.R;

public class WebViewActivity extends AppCompatActivity {
private WebView mWebview;
private ActivityResultLauncher mLauncher;
private TextView mTvTitle,mTvStart,mTvFinish,mTvProgress;

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

//数据传输
mLauncher=registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if(result.getResultCode()==1){
String tt=result.getData().getStringExtra("user");
mWebview.loadUrl("javascript:showUserName('"+tt+" new')");//js交互
}
}
});

mTvTitle=findViewById(R.id.webview_tv_title);
mTvStart=findViewById(R.id.webview_tv_start);
mTvFinish=findViewById(R.id.webview_tv_finish);
mTvProgress=findViewById(R.id.webview_tv_progress);
mWebview=findViewById(R.id.web_view);




mWebview.setWebViewClient(new WebViewClient(){
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
super.onReceivedSslError(view, handler, error);
handler.proceed();
}

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}

@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
mTvStart.setText("开始加载");
}

@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
mTvFinish.setText("加载完成");
}
});
mWebview.setWebChromeClient(new WebChromeClient(){
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
mTvTitle.setText(title);
}

@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
if(newProgress<100){
mTvProgress.setText(newProgress+"%");
}else {
mTvProgress.setText("100%");
}
}
});
WebSettings webSettings=mWebview.getSettings();
webSettings.setJavaScriptEnabled(true); //设置支持js脚本
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);//设置缓存策略
// mWebview.loadUrl("https://gallifrey.asia");//访问网络网站
mWebview.addJavascriptInterface(this,"android");
mWebview.loadUrl("file:///android_asset/test.html");//访问本地html

}

@JavascriptInterface
public void login(){
Intent intent=new Intent(this,LoginActivity.class);
// startActivityForResult(intent,0);//方法已弃用 ,请在onCreate方法中使用registerForActivityResult()方法代替
mLauncher.launch(intent);
}

// @Override
// protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
// super.onActivityResult(requestCode, resultCode, data);
// if(requestCode==0&&resultCode==1){
// String temp=data.getStringExtra("user");
// mWebview.loadUrl("javascript:showUserName('"+temp+"')");
// }
// }

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_BACK&&mWebview.canGoBack()){
mWebview.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
  • 跳转交互的Activity类
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
package com.gallifrey.todayapplication.webview;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import com.gallifrey.todayapplication.R;

public class LoginActivity extends AppCompatActivity {
private EditText mEtUser;
private Button mBtnSubmit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
mEtUser=findViewById(R.id.webview_et_user);
mBtnSubmit=findViewById(R.id.webview_btn_submit);
mBtnSubmit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String temp=mEtUser.getText().toString();
Intent data=new Intent();
data.putExtra("user",temp);
setResult(1,data);
finish();
}
});
}
}
  • activity_web_view.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
<?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"
tools:context=".webview.WebViewActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/webview_tv_title"
android:text="标题"
android:textSize="26sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/webview_tv_start"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/webview_tv_start"
android:text="开始"
android:textSize="26sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/webview_tv_title"
app:layout_constraintBottom_toTopOf="@id/webview_tv_finish"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/webview_tv_finish"
android:text="结束"
android:textSize="26sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/webview_tv_start"
app:layout_constraintBottom_toTopOf="@id/webview_tv_progress"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/webview_tv_progress"
android:text="进度"
android:textSize="26sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/webview_tv_finish"
app:layout_constraintBottom_toTopOf="@id/web_view"
/>

<WebView
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="@+id/web_view"
app:layout_constraintVertical_weight="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/webview_tv_progress"
app:layout_constraintBottom_toBottomOf="parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
  • activity_login.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
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:paddingStart="10dp"
android:paddingEnd="10dp"
tools:context=".EditTextActivity">

<TextView
android:layout_marginTop="200dp"
android:id="@+id/webview_tv_user"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="用户名: "

android:textSize="30sp" />

<EditText
android:id="@+id/webview_et_user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/webview_tv_user"
android:layout_toEndOf="@id/webview_tv_user"
android:background="@drawable/bgeditext"
android:hint="请输入号码"
android:inputType="phone"
android:paddingStart="10dp"
android:textSize="30sp"

/>
<TextView
android:id="@+id/webview_tv_pwd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/webview_tv_user"
android:layout_alignStart="@id/webview_tv_user"
android:layout_marginTop="40dp"
android:text="密 码: "
android:textSize="30sp" />

<EditText
android:id="@+id/webview_et_pwd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/webview_et_user"
android:layout_alignBaseline="@id/webview_tv_pwd"
android:layout_toEndOf="@id/webview_tv_pwd"
android:background="@drawable/bgeditext"
android:drawablePadding="5dp"
android:hint="请输入密码"
android:inputType="textPassword"
android:paddingStart="10dp"
android:textSize="30sp" />

<Button
android:id="@+id/webview_btn_submit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/webview_tv_pwd"
android:layout_centerHorizontal="true"
android:layout_marginTop="40dp"
android:background="@drawable/pressresult"
android:paddingHorizontal="60dp"
android:text="确定"
android:textSize="30sp" />
</RelativeLayout>