ViewPager2
ViewPager2
1、什么是ViewPager?
布局管理器允许左右翻转带数据的页面
,你想要显示的视图可以通过实现PagerAdapter来显示。这个类其实是在早期设计和开发的,它的API在后面的更新之中可能会被改变,当它们在新版本之中编译的时候可能还会改变源码。
ViewPager经常用来连接Fragment,它很方便管理每个页面的生命周期,使用ViewPager管理Fragment是标准的适配器实现。最常用的实现一般有FragmentPagerAdapter和FragmentStatePagerAdapter。
ViewPager是android扩展包v4包中的类,这个类可以让我们左右切换当前的view。我们先来聊聊ViewPager的几个相关知识点:
- 1、ViewPager类直接继承了ViewGroup类,因此它一个容器类,可以添加其他的view类
- 2、ViewPager类需要一个PagerAdapter适配器类给它提供数据(这点跟ListView一样需要数据适配器Adater)
3、ViewPager经常和Fragment一起使用,并且官方还提供了专门的FragmentPagerAdapterFragmentStatePagerAdapter类供Fragment中的ViewPager使用
2、什么是ViewPager2
原理: viewpager2 内部实现原理是使用recycleview加LinearLayoutManager实现竖直滚动,其实可以理解为对recyclerview的二次封装
源代码如下:
private void initialize(Context context, AttributeSet attrs) {
mRecyclerView = new RecyclerView(context) {
@Override
public CharSequence getAccessibilityClassName() {
return "androidx.viewpager.widget.ViewPager";
}
@Override
public void onInitializeAccessibilityEvent(@NonNull AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setFromIndex(mCurrentItem);
event.setToIndex(mCurrentItem);
}
};
mRecyclerView.setId(ViewCompat.generateViewId());
mLayoutManager = new LinearLayoutManager(context);
mRecyclerView.setLayoutManager(mLayoutManager);
setOrientation(context, attrs);
mRecyclerView.setLayoutParams(
new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
.....
attachViewToParent(mRecyclerView, 0, mRecyclerView.getLayoutParams());
}
ViewPager2的出现是为了替代ViewPager,它有以下几个优势:
- 支持RTL布局,
- 支持竖向滚动
- 支持notifyDataSetChanged
RTL布局是Right To Left布局也就是从右往左的布局,大家知道我们平常写的布局都是从左往右,但是如果你适配阿拉伯语等环境的UI布局,他们的写法是从右往左的,具体这里不做研究。
API的变动:
FragmentStateAdapter
替换了原来的FragmentStatePagerAdapter
RecyclerView.Adapter
替换了原来的PagerAdapter
- r
egisterOnPageChangeCallback
替换了原来的addPageChangeListener
FragmentStateAdapter和FragmentStatePagerAdapter作用相同, 可以用viewpager来管理fragment, 区别在于viewpager2的FragmentStateAdapter与recycleview的生命周期绑定
另外viewpager2的Adapter是继承自recyclerview的adapter, 支持除了notifyDataSetChanged()以外的notifyItemChanged(int position)等方式, 使用上更加的便捷
3、ViewPager使用案例
activity_main.xml:
<RelativeLayout 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=".MainActivity">
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</android.support.v4.view.ViewPager>
</RelativeLayout>
tab.xml(作为ViewPager的子布局):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tab1"
/>
</LinearLayout>
然后这里我们先创建4个要在ViewPager中显示的界面,代码如下:
ArrayList<View> viewContainter = new ArrayList<View>();
View view1 = LayoutInflater.from(this).inflate(R.layout.tab1, null);
View view2 = LayoutInflater.from(this).inflate(R.layout.tab2, null);
View view3 = LayoutInflater.from(this).inflate(R.layout.tab3, null);
View view4 = LayoutInflater.from(this).inflate(R.layout.tab4, null);
//viewContainter添加view
viewContainter.add(view1);
viewContainter.add(view2);
viewContainter.add(view3);
viewContainter.add(view4);
有了数据后我们就要创建数据适配器了,我们创建一个数据适配器MyPagerAdapter继承自PagerAdapter
,
MyPagerAdapters完整代码:
/**
* ViewPager的数据适配器
*/
class MyPagerAdapters extends PagerAdapter{
//返回可以滑动的VIew的个数
@Override
public int getCount() {
return viewContainter.size();
}
//滑动切换的时候销毁当前的组件
@Override
public void destroyItem(ViewGroup container, int position,
Object object) {
((ViewPager) container).removeView(viewContainter.get(position));
}
//将当前视图添加到container中并返回当前View视图
@Override
public Object instantiateItem(ViewGroup container, int position) {
((ViewPager) container).addView(viewContainter.get(position));
return viewContainter.get(position);
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
在PagerAdapter
我们必须重写以下几个方法:
int getCount()
getCount():返回可以滑动的VIew的个数
void destroyItem(ViewGroup container, int position,Object object)
从当前container中删除指定位置的View
Object instantiateItem(ViewGroup container, int position)
将当前视图添加到container中并返回当前View视图
boolean isViewFromObject(View arg0, Object arg1)
该函数用来判断instantiateItem(ViewGroup, int)函数所返回来的Object与一个页面视图是否是代表的同一个视图,
官方建议直接返回arg0 == arg1即可。
MainActivity完整代码如下:
package com.zejian.viewpager;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.PagerTabStrip;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
public class MainActivity extends Activity {
ViewPager pager = null;
PagerTabStrip tabStrip = null;
ArrayList<View> viewContainter = new ArrayList<View>();
@SuppressLint("ResourceAsColor")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
pager = (ViewPager) this.findViewById(R.id.viewpager);
View view1 = LayoutInflater.from(this).inflate(R.layout.tab1, null);
View view2 = LayoutInflater.from(this).inflate(R.layout.tab2, null);
View view3 = LayoutInflater.from(this).inflate(R.layout.tab3, null);
View view4 = LayoutInflater.from(this).inflate(R.layout.tab4, null);
//viewpager开始添加view
viewContainter.add(view1);
viewContainter.add(view2);
viewContainter.add(view3);
viewContainter.add(view4);
//设置Adapter
pager.setAdapter(new MyPagerAdapters());
}
/**
* ViewPager的数据适配器
*/
class MyPagerAdapters extends PagerAdapter{
//返回可以滑动的VIew的个数
@Override
public int getCount() {
return viewContainter.size();
}
//滑动切换的时候销毁当前的组件
@Override
public void destroyItem(ViewGroup container, int position,
Object object) {
((ViewPager) container).removeView(viewContainter.get(position));
}
//将当前视图添加到container中并返回当前View视图
@Override
public Object instantiateItem(ViewGroup container, int position) {
((ViewPager) container).addView(viewContainter.get(position));
return viewContainter.get(position);
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
}
}
4、ViewPager2使用案例
实现水平滚动实例
引入 ViewPager2 组件:
dependencies {
implementation "androidx.viewpager2:viewpager2:1.0.0-alpha02"
}
把 ViewPager2 声明在 activity_horizontal_scrolling.xml 里面:
<?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=".MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="0dp"
android:layout_height="0dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
建立一个简单的 item 布局,item_page.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/container"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tvTitle"
tools:text="item"
android:layout_centerInParent="true"
android:textColor="@android:color/white"
android:textSize="32dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
建立数据适配器 ViewPagerAdapter:
public class ViewPagerAdapter extends RecyclerView.Adapter<ViewPagerAdapter.ViewPagerViewHolder> {
private List<Integer> colors = new ArrayList<>();
{
colors.add(android.R.color.black);
colors.add(android.R.color.holo_purple);
colors.add(android.R.color.holo_blue_dark);
colors.add(android.R.color.holo_green_light);
}
@NonNull
@Override
public ViewPagerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ViewPagerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_page, parent,false));
}
@Override
public void onBindViewHolder(@NonNull ViewPagerViewHolder holder, int position) {
holder.mTvTitle.setText("item " + position);
holder.mContainer.setBackgroundResource(colors.get(position));
}
@Override
public int getItemCount() {
return colors.size();
}
class ViewPagerViewHolder extends RecyclerView.ViewHolder {
TextView mTvTitle;
RelativeLayout mContainer;
public ViewPagerViewHolder(@NonNull View itemView) {
super(itemView);
mContainer = itemView.findViewById(R.id.container);
mTvTitle = itemView.findViewById(R.id.tvTitle);
}
}
}
在 HorizontalScrollingActivity 的 onCreate 方法中,设置 ViewPager2:
public class HorizontalScrollingActivity extends AppCompatActivity {
public static void start(Context context) {
Intent starter = new Intent(context, HorizontalScrollingActivity.class);
context.startActivity(starter);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_horizontal_scrolling);
ViewPager2 viewPager2 = findViewById(R.id.viewpager2);
ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter();
viewPager2.setAdapter(viewPagerAdapter);
}
}
拓展:VerticalScrollingActivity的使用
修改HorizontalScrollingActivity 为VerticalScrollingActivity
package com.example.viewpager2demo;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
public class VerticalScrollingActivity extends AppCompatActivity {
public static void start(Context context) {
Intent starter = new Intent(context, VerticalScrollingActivity.class);
context.startActivity(starter);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_horizontal_scrolling);
ViewPager2 viewPager2 = findViewById(R.id.viewpager2);
ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter();
viewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
viewPager2.setAdapter(viewPagerAdapter);
}
}
4.1、Viewpager2+TabLayout+Fragment的简单使用
探秘FragmentStateAdapter:当Fragment碰上ViewPager2
activity_main
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
tools:context=".MainActivity">
<com.google.android.material.tabs.TabLayout
android:id="@+id/my_tab"
android:layout_width="match_parent"
android:layout_height="60dp"/>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/my_pager2"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
MainActivity
package com.wmc.test;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import android.widget.Button;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private TabLayout myTab;
private ViewPager2 myPager2;
List<String> titles=new ArrayList<>();
List<Fragment> fragments=new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myTab = findViewById(R.id.my_tab);
myPager2 = findViewById(R.id.my_pager2);
//添加标题
titles.add("1");
titles.add("2");
//添加Fragment进去
fragments.add(new MyFragment());
fragments.add(new Fragment());
//实例化适配器
MyAdapter myAdapter=new MyAdapter(getSupportFragmentManager(),getLifecycle(),fragments);
//设置适配器
myPager2.setAdapter(myAdapter);
//TabLayout和Viewpager2进行关联
new TabLayoutMediator(myTab, myPager2, new TabLayoutMediator.TabConfigurationStrategy() {
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
tab.setText(titles.get(position));
}
}).attach();
}
}
MyAdapter
在package com.wmc.test;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.List;
public class MyAdapter extends FragmentStateAdapter {
List<Fragment> fragments;
public MyAdapter(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle, List<Fragment> fragments) {
super(fragmentManager, lifecycle);
this.fragments = fragments;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return fragments.get(position);
}
@Override
public int getItemCount() {
return fragments.size();
}
}
MyFragment
public class MyFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View inflate = inflater.inflate(R.layout.myfragment, null);
return inflate;
}
}
myfragment.xml
<?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:background="#FF9800"
android:orientation="vertical">
</LinearLayout>
参考
1、https://blog.csdn.net/willway_wang/article/details/88725392
2、https://blog.csdn.net/javazejian/article/details/52138962
3、https://blog.csdn.net/wangjinyu501/article/details/8169924