目录
3.TabLayout+ViewPager2+Fragment实现微信滑动界面
一,Adapter
1.什么是Adapter?
Adapter(适配器)是连接后端数据与前端视图的接口,是数据与视图之间交互的中介。众所周知,Android用户界面采用MVC框架,即model-view-controller,model和view可理解为是数据和视图,而Adapter就属于中间的controller部分。
用Adapter作为数据和视图之间交互的中介,就可以将这两部分分开操作:数据改变时,不需要修改视图组件,只需更新Adapter;视图组件改变时,不需要修改数据,只需绑定Adapter即可。
2.Android中的常用Adapter
- BaseAdapter:用于自定义适配器,数据源由用户决定,使用时会被继承并重写方法,最常用也是最灵活的一个adapter;
- ArrayAdapter:最简单的适配器,数据源为文本字符,只能显示一行文本;
- SimpleAdapter:简单适配器,数据源结构比较复杂,一般为List<Map>类型对象;
- SimpleCursorAdapter:游标适配器,用于显示简单文本类型的listview,数据源一般为数据库中的数据;
二,AdapterView
1.AdapterView简介
AdapterView:容器控件,整体由一个个子元素item组成,子元素的内容与数据由Adapter决定。如下图所示:整体容器框架是AdapterView,其中的每个小元素就是item。
2.AdapterView的子视图对象
ListView | 以垂直滑动列表形式显示一组数据。 |
GridView | 以网格形式显示一组数据。 |
Spinner | 以下拉列表形式显示一组数据。 |
三,ListView滑动列表形式
ListView:以垂直可滑动列表形式显示子项目的视图容器,如下图所示:
ListView使用的基本流程(实现简单的微信界面):
(1)准备ListView整体布局以及每一个子项的视图布局(可以使用内置的布局,也可以自定义布局,我们这里使用自定义布局):
整体布局:
<?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"
>
<ListView
android:id="@+id/lv_wechat"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible">
</ListView>
</RelativeLayout>
子元素布局(头像+昵称+聊天信息):
<?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="horizontal">
<ImageView
android:id="@+id/iv_avatar1"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:src="@mipmap/liyue"
>
</ImageView>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="5"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_nickname1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:text="璃月"
></TextView>
<TextView
android:id="@+id/tv_endmessage1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="10sp"
android:text="114514"
></TextView>
</LinearLayout>
</LinearLayout>
效果预览:
(2)创建Adapter(连接数据源和子元素视图布局,这里使用继承BaseAdapter的自定义适配器):
public class PracticeAdapter extends BaseAdapter {
private Context context; //上下文
private Integer layoutId; //布局子控件id
private List<Practice> list; //数据源
public PracticeAdapter(){}
//构造器
public PracticeAdapter(Context context, Integer layoutId, List<Practice> list){
this.context = context;
this.layoutId = layoutId;
this.list = list;
}
//继承BaseAdapter需重写的四个方法
public int getCount() {return list.size();}//数据个数
public Object getItem(int position) {return list.get(position);}//对应位置的item
public long getItemId(int position) {return position;}//返回item下标位置
//getView最重要的一个函数,position当前item的下标,convertView当前的视图,parent当前视图的父视图
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
convertView = LayoutInflater.from(context).inflate(layoutId, null);
}
//获取列表项中的控件
ImageView iv_avatar1 = convertView.findViewById(R.id.iv_avatar1);
TextView tv_nickname1 = convertView.findViewById(R.id.tv_nickname1);
TextView tv_endmessage1 = convertView.findViewById(R.id.tv_endmessage1);
//给数据项填充数据
Practice practice = list.get(position);
iv_avatar1.setImageResource(practice.getAvatar());
tv_nickname1.setText(practice.getNickName());
tv_endmessage1.setText(practice.getEndMessage());
//返回列表项
return convertView;
}
}
为Adapter准备数据源:
public class Practice {
private Integer avatar;//头像
private String nickName;//昵称
private String endMessage;//聊天信息
public Practice(){}
//构造器
public Practice(Integer avatar, String nickName, String endMessage){
this.avatar = avatar;
this.nickName = nickName;
this.endMessage = endMessage;
}
//数据源 包括头像,昵称,聊天信息
public static List<Practice> getPractice(){
List<Practice> list = new ArrayList<>();
list.add(new Practice(R.mipmap.liyue, "cxk", "师傅!救我口牙!"));
list.add(new Practice(R.mipmap.liyue, "cxk1", "2333333"));
list.add(new Practice(R.mipmap.liyue, "cxk2", "[语音聊天]"));
return list;
}
}
(3)为ListView绑定Adapter:
//获取ListView控件
ListView lv_practice = findViewById(R.id.lv_practice);
//获取数据源
List<Practice> list = Practice.getPractice();
//创建Adapter
PracticeAdapter adapter = new PracticeAdapter(
TabPracticeActivity.this,
R.layout.item_practice, //子控件id
list
);
//为ListView绑定Adapter
lv_practice.setAdapter(adapter);
(4)为ListView绑定事件监听器:
//使用匿名内部类的方式绑定事件监听器
lv_practice.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(
TabPracticeActivity.this,
list.get(position).getNickName(),
Toast.LENGTH_SHORT
).show();
}
});
最终效果:
四, GridView网格形式显示
GridView:以网格形式显示子项目的视图容器:
GridView使用的基本流程:
GridView使用的流程与ListView基本一致,同样分为四步:
- 准备GridView每一个子项的视图布局。( 可以使用内置的布局,也可以用户自定义布局);
- 创建Adapter(连接数据源和视图布局);
- 为GridView绑定Adapter;
- 为GridView绑定事件监听器;
在这里我们可以直接将上面ListView的Adapter绑定给GridView,也就是同一份数据对应不同的视图。首先需要将布局文件中的ListView换成GridView:
<?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"
>
<GridView
android:id="@+id/gv_product"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:horizontalSpacing="2dp"
android:verticalSpacing="2dp"
android:numColumns="2">
</GridView>
</RelativeLayout>
然后将上面步骤三四中的ListView全部换成GridView即可:
//获取GridView控件
GridView gv_product = findViewById(R.id.gv_product);
//获取数据源
List<Practice> list = Practice.getPractice();
//创建适配器
PracticeAdapter adapter = new PracticeAdapter(
TabPracticeActivity.this,
R.layout.item_practice, //子控件id
list
);
//绑定适配器
gv_product.setAdapter(adapter);
//设置事件监听器
gv_product.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Toast.makeText(
TabPracticeActivity.this,
list.get(position).getNickName(),
Toast.LENGTH_SHORT
).show();
}
});
最终效果如下,可以看到滑动列表效果变为了网格形式效果:
五,Fragment和ViewPager2视图控件的使用
1.什么是Fragment?
Fragment意为”片段“,是为了解决安卓app运行的设备大小不一而提出的,Fragment将屏幕分成了几组,进行模块化管理,可以将Fragment当成Activity界面的一个组成部分,一个Activity可以包含很多Fragment。
Fragment拥有自己的生命周期,可接收、处理用户的事件。 Activity中可以动态的添加、替换和移除某个Fragment。
2.ViewPager2
ViewPager2(视图控件)基于RecycleView实现,可以实现类似抖音的上下滑动,也可以实现左右滑动,通常配合Fragment一起使用,需要借助FragmentStateAdapter,从而将Fragment和Activity关联在一起。
3.TabLayout+ViewPager2+Fragment实现微信滑动界面
使用TabLayout可以实现微信底部导航栏,但是界面之间的跳转只能是点击跳转,如果想要实现滑动跳转效果,需要使用ViewPager2+Fragment,因为点击跳转时,两个界面不会同时出现,使用事件监听器设置View是否显示就可实现,但滑动跳转时,两个界面会同时存在。因此需要ViewPager2和Fragment一起使用。
具体实现步骤如下:
(1)设计布局文件(TabLayout+ViewPager2):
<?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">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/vp_context"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.viewpager2.widget.ViewPager2>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tb_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
</com.google.android.material.tabs.TabLayout>
</RelativeLayout>
(2)定义Fragment的item子布局(取名fragment_wechat)以及对应的Fragment,因为微信界面有四个(微信,通讯录,发现,我的),因此item子布局和对应的Fragment也要定义四个(实际开发中由四个人分别定义):
<?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">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="微信界面"
android:textSize="60sp">
</TextView>
</LinearLayout>
public class WechatFragment extends Fragment {
@Nullable
@Override
//inflater布局加载器 container是否为父子容器 savedInstanceState保存实例状态
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_wechat, null);
return view;
}
}
(3)自定义FragmentStateAdapter,联系Fragment和Activity:
public class WechatFragmentAdapter extends FragmentStateAdapter {
private List<Fragment> fragmentList;//Fragment数据源,存放定义的四个Fragment
public WechatFragmentAdapter(List<Fragment> fragmentList, @NonNull FragmentActivity fragmentActivity) {
super(fragmentActivity);//调用Activity,因为Fragment最终必须要和Activity联系,因此构造器必须实现;
this.fragmentList = fragmentList;
}
@NonNull
@Override
public Fragment createFragment(int position) {return fragmentList.get(position);}
@Override
public int getItemCount() {return fragmentList.size();}
}
(4)给ViewPager2设定适配器:
//获取activity中的控件
TabLayout tb_nav = findViewById(R.id.tb_nav);
ViewPager2 vp_context = findViewById(R.id.vp_context);
//创建fragment数据源
List<Fragment> fragmentList = new ArrayList<>();
fragmentList.add(new WechatFragment());
fragmentList.add(new ContractFragment());
fragmentList.add(new FindFragment());
fragmentList.add(new MineFragment());
//创建适配器
WechatFragmentAdapter adapter = new WechatFragmentAdapter(
fragmentList, this
);
//viewpager2绑定适配器
vp_context.setAdapter(adapter);
(5)关联TabLayout与ViewPager2(使用TabLayoutMediator):
//TabLayout和ViewPager2关联 通过TabLayoutMediator
TabLayoutMediator mediator = new TabLayoutMediator(
tb_nav,//TabLayout
vp_context,//ViewPager2
new TabLayoutMediator.TabConfigurationStrategy() {
@Override
//设置每个tab位置的属性(图标,名称等)
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
switch(position){
case 0:
tab.setText("微信");
tab.setIcon(R.mipmap.message);
break;
case 1:
tab.setText("联系人");
tab.setIcon(R.mipmap.contract);
break;
case 2:
tab.setText("发现");
tab.setIcon(R.mipmap.find);
break;
case 3:
tab.setText("我的");
tab.setIcon(R.mipmap.mine);
break;
}
}
}
);
//使效果生效
mediator.attach();
最终效果如下:
标签:控件,Fragment,Adapter,list,视图,new,public From: https://blog.csdn.net/IH_LZH/article/details/137432483