Code概述#
工程包括2部分
graph LR h1(ViewPager知识体系)-->A(常见类和API) h1-->B(基本用法) B-->PagerAdapter B-->FragmentPagerAdapter B-->FragmetnStatePagerAdpater B-->RecyclerView.Adapter+FragmentStateAdapter B-->未完成Fragment+FragmentManager+FragmentTranscation h1-->C(高阶用法) C-->P(PageTransformer) P-->一页多个 P-->层叠 P-->居中缩放 C-->child(未完成-子项控制-5种adapter的用法区别) child-->remove child-->update child-->replace child-->insert
常见API#
名称 | 用途 |
---|---|
ViewPager | 视图组件 |
ViewPager2 | 视图组件 |
PagerAdapter | viewpager1适配器 |
FragmentPagerAdapter | viewpager1适配器 |
FragmentStatePagerAdapter | viewpager1适配器 |
RecyclerView.Adapter | viewpager2适配器 |
FragmentStateAdapter | viewpager2适配器 |
FragmentTransaction | Fragment事物控制 |
FragmentManager | Fragment管理器 |
Fragment | 视图组件 |
标准用法#
ViewPager#
总结
滑动有哪些方法:
- setCurrentItem、arrowScroll
能监听哪些事件:
- onPageScrolled、onPageSelected、onPageScrollStateChanged
- SCROLL_STATE_IDLE、SCROLL_STATE_DRAGGING、SCROLL_STATE_SETTLING
不同事件之间的区别:
- setAdapter是否进入回调
- 动作没完成是否进入回调
假滑了解吗:
- Viewpager通过fakeBy来与其他组件联动
基本方法#
APi | 用途 |
---|---|
setAdapter | |
setPageTransformer | 设置每个页面的变化效果 |
setPageMarginDrawable | 设置一个可用于填充页面间空白的drawable |
setPageMargin | 设置页面的页边距, |
setOnPageChangeListener | |
addOnPageChangeListener | 监听page改变事件,支持三大类page事件:onPageScrolled、onPageSelected、onPageScrollStateChanged 其中onPageScrollStateChanged支持三类滑动事件SCROLL_STATE_IDLE滑动闲置、SCROLL_STATE_DRAGGING手势滑动、SCROLL_STATE_SETTLING代码设置的滑动 |
setOffscreenPageLimit | 设置视图层次结构中当前页面任一侧的页数,超出此限制的页面将在需要时从适配器重新创建 |
setCurrentItem | 设置当前显示的页面。 |
arrowScroll | 上一页View.FOCUS_LEFT;下一页View.FOCUS_RIGHT 返回值代表能否继续滑动,好处是能判断是否到头了 |
onSaveInstanceState | 存储视图内部状态的数据,如page的位置 |
onRestoreInstanceState | 恢复视图内部之前存储的状态,如page的位置 |
removeView | |
isFakeDragging | 返回当前是否假滑状态中 |
beginFakeDrag | 只有不处于假滑状态中,才开始开始假滑 |
fakeDragBy | 控制假滑移动水平方向距离 |
endFakeDrag | 只有处于假滑动状态中,才可以结束假滑 |
getChildCount | 获取没有被销毁的viewcontianer |
实践#
参考ViewPager(六)让ViewPager用起来更顺滑——设置间距与添加转场动画_郝振兴的博客-CSDN博客_viewpage转场动画
禁止滑动#
1 | package com.example.xinenhuadaka.view; |
区分滑动类型#
是否进入回调 | onPageScrolled | onPageSelected | onPageScrollStateChanged |
---|---|---|---|
代码控制 | 是 | 是 | 是 |
手动滑动 | 是 | 是 | 是 |
setAdapter | 是 | 否 | 是 |
onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
- 代码控制的滚动会进入;
- 用户手滑动会进入
- viewpager.setAdapter初始化会进入
onPageSelected(int position);
- 新页面已经显示,但滑动动作没有完成的时候进入回调
- 用于动态设置页码、页面标题的方式,
- 用于动态回显tab选中的方式
- 初次viewpager.setAdapter不会进入回调,需要手动设置页码、页面标题、tab选中样式
onPageScrollStateChanged
这个方法可以做一些关于不同滑动方式的滑动方案的区别设计,用户滑动的时候执行一套逻辑,代码切换的时候执行一套逻辑,并且还可以判断切换动画是否已经结束,是否处于idle状态
ViewPager#SCROLL_STATE_IDLE为切换页面动画结束,或者处于idle闲置状态
ViewPager#SCROLL_STATE_DRAGGING为用户正在滑动时的状态回调,此时滑动未结束
ViewPager#SCROLL_STATE_SETTLING为非用户滑动,代码设置切换的状态,注意:这个状态会在手势滑动翻页(onPageSelected回调之前)回调一次这个状态值
1 | private int mCurrentPos = 0; |
设置假滑#
假滑的意义:
某些场景下,用户不想触摸ViewPager,而是想在操作其他视图组件的时候,让ViewPager自动执行滑动操作,看上去好像有人滑动它一样;
简单来说就是Viewpager与其他组件联动机制的工具
一段假滑的步骤:
boolean isFakeDragging // 是否可以假滑操作
boolean beginFakeDrag() // 开始假滑
Void fakeDragBy(float xOffset) // 控制假滑移动水平方向距离
void endFakeDrag() // 结束假滑
boolean isFakeDragging() // 返回当前是否假滑状态中
1 | public void fakePage(View view) { |
懒加载#
预加载是结合FragmentPagerAdapter、FragmentStatePagerAdapter说的,在Fragment生命周期过程中,网络请求数据未返回之前,可以通过setUserVisibleHint隐藏正在展示的Fragment;网络数据返回后,再通过setUserVisibleHint展示Fragment
预加载#
setOffscreenPageLimit–设置屏幕之外页面数量
PageLimit<1,缓存1页
不预加载#
将ViewPager的常量DEFAULT_OFFSCREEN_PAGES 改为0
修改方式1:照抄ViewPager源码,只修改这个变量的值为0
修改方式2:反射修改ViewPager的DEFAULT_OFFSCREEN_PAGES 常量值为0
ViewPager2#
!>ViewPager2 基于Recyclerview构建
与Viewpager不同之处:
- ViewPager2为final类型,禁止继承复写
- 支持可修改的 Fragment 集合,能正确显示修改后的Fragment
- setUserInputEnabled控制禁止滑动,无需自定义
- fakeDragBy支持假滑
- 使用FragmentStateAdapter、RecyclerView.Adapter替换原先的ViewPager使用的三个Adapter
- 需要重载的方法发生变化,新增getItemCount()、createFragment(),
- 监听事件使用OnPageChangeCallback
- 支持DiffUtil ,可以添加指定数据集改变的item动画
基本方法#
API | 用途 |
---|---|
registerOnPageChangeCallback | onPageScrolled、onPageSelectedonPageSelected、onPageScrollStateChanged |
setOrientation() | 设置垂直ORIENTATION_VERTICAL或水平ORIENTATION_HORIZONTAL |
setLayoutDirection() | 设置轮播、右至左 |
setPageTransformer | |
setUserInputEnabled | 设置禁止用户滑动 |
实践#
PagerAdapter#
总结:
必须复写的方法:
instantiateItem()
,destroyItem()
,getCount()
以及isViewFromObject()
。
- instantiateItem的作用:被ViewPager.addNewItem()调用,创建新的Page
- destroyItem:释放指定的view
- getCount:设置Page数量
- isViewFromObject:在instantiateItem内调用用于判断是否view跟object进行了绑定
三者区别
名称 | 内存优化 | 不可见是否立即销毁Page | 设置limit是否影响destory | POSITION_NONE对destroyItem的影响 | 优点 | 场景 |
---|---|---|---|---|---|---|
PagerAdapter | 极佳 | 是 | 是,不销毁数量内的view | 不可见即销毁 | ||
FragmentPagerAdapter | 较差 | 是,先绑定新的fragment;后detach旧的fragment:两个fragment生命周期如下 onAttach: 3 onCreate: 3 onCreateView3 onViewCreated: 3 onActivityCreated: 3 onDestroyView:—0 |
是,不销毁数量内的Fragment | 从FragmentManager里移除Fragment的视图,Fragment仅进入onDestroyView回调 | 适合固定的少量页面之间导航 | - getItem()新的与数据无关的Fragment - instantiateItem() 中通过super.instantiateItem 获取父类Fragment对象,设置数据 |
FragmentStatePagerAdapter | 中等 | 是,先绑定新fragment,后onDetach旧的fragment;两个fragment生命周期如下 onAttach: 3 onCreate: 3 onCreateView:3 onViewCreated: 3 onActivityCreated: 3 onDestroyView:—0 onDestroy:–0 onDetach: - 0 |
是,不销毁数量内的Fragment | 从FragmentManager里移除Fragment实例,Fragment,会进入onDestroyView回调、onDestroy回调、onDetach回调 | 适合对未知数量的页面进行分页导航 |
基本方法#
ViewPager将每个页面与一个关键对象相关联
名称 | 用途 |
---|---|
POSITION_NONE | 对象发生变化,用于getItemPosition中指定返回值,供notifyDataSetChanged判断 |
POSITION_UNCHANGED | 对象没有改变,用于getItemPosition中指定返回值,供notifyDataSetChanged判断 |
instantiateItem(ViewGroup, int) | 创建给定位置的页面。被ViewPager.addNewItem()调用 |
destroyItem(ViewGroup, int, Object) | 删除给定位置的页面。 |
getCount() | 返回可用的视图数量。 |
isViewFromObject(View, Object) | 确定页面视图是否与 instantiateItem(ViewGroup, int) 返回的特定键对象相关联。 |
getItemPosition(Object object) | 当主视图试图确定某个项目的位置是否已更改时调用,返回POSITION_NONE或POSITION_UNCHANGED |
getPageWidth(int position) | 以(0.f-1.f)的ViewPager测量宽度的百分比形式返回给定页面的比例宽度。 |
notifyDataSetChanged() | 如果支持此适配器的数据发生更改并且关联的视图应该更新,应该由应用程序调用此方法。 |
registerDataSetObserver(DataSetObserver observer) | 注册观察者以接收与适配器数据更改有关的回调。 |
unregisterDataSetObserver(DataSetObserver observer) | 从与适配器数据更改相关的回调中注销观察者。 |
restoreState(Parcelable state, ClassLoader loader) | 还原与此适配器及其先前由 saveState() 保存的页面相关的任何实例状态。 |
saveState | 如果需要重建当前UI状态,请保存与此适配器及其应恢复的页面关联的任何实例状态。 |
setPrimaryItem(ViewGroup container, int position, Object object) | 被调用以通知适配器当前哪个项目被认为是“主要”,这是向用户显示的当前页面。 |
startUpdate(ViewGroup container) | 当所显示页面的变化即将开始时调用。 |
实践#
1 | public class ChildSlidePageAdapter extends PagerAdapter { |
FragmentPagerAdapter#
总结:
- 只有getItem、getCount是必须复写的
- getItem用于给instantiateItem提供Fragment
- getCount用于计算子页面数量
- 构造函数的FragmentManager是必须提供的,用于恢复、刷新、保存子页面持有的Fragment
makeFragmentName
是FragmentPagerAdpater的基类方法,子类复写,可用于修改FragmentTag的生成方式- 刷新指定Fragment有2种方式
方式1
- 复写makeFragmentName,修改Adapter管理Fragment的方式
- 复写instantiateItem,定义map存储<position,FragmentTag>
- adapter对外暴露update方法,方法内通过FragmentManager#findFragmentByTag拿到指定Fragment,并调用Fragment对外暴露的public方法如
((DetailsFragment)fragment).update
方式2
- 复写getItemPosition,根据外部条件,决策是否要全量刷新所有的Fragment,全量刷新返回POSITION_NONE;不需要刷新,返回POSITION_UNCHANGED
- 移除、替换Fragment也有2种方式
方式1类似6.2
- 复写getItemPosition,通知POSITION_NONE,刷新全部子项
- 传入新的list
数据集
基本方法#
API | 用途 |
---|---|
getItem() | |
getCount() | |
instantiateItem | 一般不需要复写,用于将Fragment存入FragmentTransaction,并且为Fragment设置TAG |
makeFragmentName | 优点1:可重写默认生成FragmentTag的方法 默认生成Fragment专属Tag,用于FM查询Fragment "android:switcher:" + viewId + ":" + id;" |
实践#
1 | public class DetailsPagerAdapter extends FragmentPagerAdapter { |
FragmentStatePagerAdapter#
总结:
- 只有getItem、getCount是必须复写的
- getItem用于给instantiateItem提供Fragment
- getCount用于计算子页面数量
- 构造函数的FragmentManager是必须提供的,用于恢复、刷新、保存子页面持有的Fragment
基本方法#
FragmentStatePagerAdapter | |
---|---|
public ScreenSlidePageAdapter(@NonNull FragmentManager fm) {} | 传入FragmentManager |
public abstract Fragment getItem(int position); | 返回Fragment实例 |
public Object instantiateItem(@NonNull ViewGroup container, int position) {} | |
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {} | |
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {} | |
public void restoreState(@Nullable Parcelable state, @Nullable ClassLoader loader) {} | |
public Parcelable saveState() {} | |
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {} | |
public void startUpdate(@NonNull ViewGroup container) {} |
实践#
1 | class MydFragmentStatePagerAdapter extends FragmentStatePagerAdapter { |
实现FragmentStatePagerAdapter子类#
复写getItem方法、getCount方法
1 | /** |
实现Fragment子类#
fragment复写onCreateView方法,设置TextView的text属性和backGroundColor属性
1 | /** |
编写Fragment布局文件#
1 |
|
RecyclerView.Adapter#
总结
必须复写的方法:onCreateViewHolder()、onBindViewHolder()、getItemCount()
如果有异步任务,推荐复写:onViewAttachedToWindow、onViewDetachedFromWindow
如果数据集频繁可变,推荐复写:getItemId、containsItem
推荐的优化做法:在页面ondestory中setAdapter(null),显示进入onViewDetachedFromWindow回调
基本方法#
onCreateViewHolder() | 创建并初始化 ViewHolder 及其关联的 View ,但不会填充view 的内容 |
onBindViewHolder() | ViewHolder 与数据相关联 |
setHasStableIds | adapter数据集中每个子项是否允许使用唯一标识符表示 |
getItemCount() | 获取数据集的大小 |
getItemId | |
getItemViewType | |
onViewAttachedToWindow | adapter创建的子view已经绑定的窗口,进入回调 |
onViewDetachedFromWindow | adapter创建的子view已经从窗口分离,进入回调,只有2种情况会进入 1.显式的调用Adapter的remove方法;2.重新设置RecyclerView的Adapter; |
onAttachedToRecyclerView | 当RecyclerView绑定了当前adapter,进入回调 |
onDetachedFromRecyclerView | 指定RecyclerView解绑了当前adapter,进入回调 |
onViewRecycled | adapter创建的子view被回收,进入回调 |
notifyItemChanged | |
notifyItemInserted | |
notifyItemRemoved | |
notifyItemRangeChanged | |
notifyItemRangeInserted | |
notifyItemRangeRemoved |
实践#
以viewpager2的层叠案例中用的到适配器
1 | class HorizontalVpAdapter extends RecyclerView.Adapter<HorizontalVpAdapter.HorizontalVpViewHolder> { |
FragmentStateAdapter#
总结
必须复写的方法:createFragment()、getItemCount
如果有异步任务,推荐复写:onViewAttachedToWindow、onViewDetachedFromWindow
如果数据集频繁可变,推荐复写:getItemId、containsItem
推荐的优化做法:在页面ondestory中setAdapter(null),显示进入onViewDetachedFromWindow回调
基本方法#
createFragment | |
getItemCount | |
getItemId | |
containsItem |
实践#
1 | private class ScreenSlideAdapter extends FragmentStateAdapter { |
PageTransformer#
参考文章(2条消息) 一个卡片式的ViewPager,带你玩转ViewPager的PageTransformer属性!__江南一点雨的博客-CSDN博客_setpagetransformer
参考文章(2条消息) 关于ViewPager.PageTransformer的一些理解_microhex的博客-CSDN博客_pagetransformer
基本方法#
1 | void transformPage(float position) View page, ; |
当页面填满整个屏幕时,其位置值为 0
当页面刚刚离开屏幕右侧时,其位置值为 1
如果用户在第一页和第二页之间滚动到一半,则第一页的位置为 -0.5,第二页的位置为 0.5。
graph LR left-->mid-->right
mid为屏幕中可见的页面,当mid滑动至right,
left view
mid view收到的position变化为:-0.10f–>-0.990f
rigth view收到的position变化为: 0.00f–>0.00f
动图表示滑动规则#
那么在滑动的过程中:
我们动图模拟右滑时,三个view收到的position变化
右滑#
我们动图模拟左滑时,三个view收到的position变化
左滑
#
setOffscreenPageLimit与View个数的关系#
limitN :setOffscreenPageLimit
count: 子项数量
count = setOffscreenPageLimit +1
实践#
准备工作#
以下示例均共用同一个适配器\布局文件\子项布局文件
1 | <androidx.viewpager2.widget.ViewPager2 |
子项布局文件
1 | <?xml version="1.0" encoding="utf-8"?> |
1 | class HorizontalVpAdapter extends RecyclerView.Adapter<HorizontalVpAdapter.HorizontalVpViewHolder> { |
一页多个#
1 |
|
层叠显示#
- 倒序层叠:默认后面的item遮盖前面的item
1 | public void moreItemOveride(View view) { |
- 正序层叠-顺序靠前的item在z轴上面
只加了一行 ViewCompat.setElevation(view, (offscreenPageLimit - position) * 5);
1 | public void moreItemOveride2(View view) { |
- 实现前后缩放
主要在判断position的位置,根据position重新计算了偏移量horizontalOffsetBase
、缩放量scaleFactor
;区分了正负(左滑右滑)的情况
1 | public void moreItemOveride5(View view) { |
Fragment#
API | 用途 |
---|---|
startPostponedEnterTransition() | |
getFragmentManager() | 获得单签Fragment的宿主Activity持有的管理器 |
getChildFragmentManager() | 获得当前Fragment持有的管理器 |
getParentFragmentManager() | 获得当前Fragment宿主持有的管理器 |
postponeEnterTransition() | |
setExitSharedElementCallback() | |
getArguments() | 获取Bundle参数 |
setArguments() | 设置Bundle惨呼 |
isAdded() | 是否添加至Activity |
isDetached() | 是否从UI布局上解绑 |
onCreateView() |
FragmentManager#
!> 获取管理器有多种方式
1 | fragmentActivity.getSupportFragmentManager() |
API | 用途 |
---|---|
beginTransaction() | 获取事物对象 |
popBackStack() | 将片段从返回栈中弹出 |
findFragmentByTag() | 获取 Activity 中存在的片段 |
findFragmentById() | 获取 Activity 中存在的片段 |
FragmentTransaction #
API | 用途 |
---|---|
setReorderingAllowed() | |
addSharedElement() | |
add() | 设置viewId、Tag,Fragment实例, 默认不传递TAG,使用adapter的 makeFragmentName 的返回值 |
replace() | |
remove() | |
show() | |
addToBackStack() | 添加Fragment至回退栈,用于响应物理返回键 |
commit() | 异步执行事物 |
executePendingTransactions() | 在主线程执行事物,可能会抛出异常 |
commitNow() | 同步执行事物,可能会抛出异常 |
commitAllowingStateLoss() | 提交无关紧要的页面,用于容灾 |
setTransition() | 设置过渡动画 |
setTransitionStyle() | 设置过渡样式 |
#
常见问题#
ViewPager子项的数量如何获取?#
不要用
ViewPager.getChildCount
,它返回的是没有被销毁的
想要获取所有的子项或Fragment数量,应该调用ViewPager.getAdapter().getCount()
.
ViewPager一屏展示多个子项?#
方式1:设置子项宽度#
适用于版本1
1 | /** |
方式2:clipchildren#
适用于1和2版本
第一步:viewpager2父布局clipChildren=false;viewpager2也clipChildren=false
ViewPager2一屏展示多个子项?#
参考PageTransfromer#实践#一页多个
ViewPager如何绑定指示器或Tab?#
待定
ViewPager中刷新单个Fragment?#
(ViewPager中刷新单个Fragment出现异常,数据源改变,Fragment不刷新)
解决方法
1 |
|
如何做懒加载?#
参考前文标准用法#viewpager#实践#预加载
如何做预加载?#
参考前文标准用法#viewpager#实践#预加载
如何刷新指定位置元素?#
Fragment为例,view的话查看《#fragment不刷新?》
初始化taglist的长度为最大长度
1 | private List<String> mTagList = Arrays.asList(new String[50]); // 用来存放所有的 Tag |
taglist存储fragment,并复写adapter的makeFragmentName
1 | /** |
update更新指定fragment
1 | /** |
fragment不刷新?#
思路1:强制清空FragmentManger#
解决方法1<span class=”hint–top hint–error hint–medium hint–rounded hint–bounce” aria-label=” FragmentPagerAdapter数据刷新notifyDataSetChanged没效果研究
“>[4]
adapter更新数据前,先使用FragmentManager强制清空缓存
1 | public void setFragments(ArrayList fragments) { |
思路2:更新指定Fragment#
解决方法2:<span class=”hint–top hint–error hint–medium hint–rounded hint–bounce” aria-label=”ViewPager刷新问题详解
“>[5]
原因:查看FragmentPagerAdpater#instantiateItem源码,有如下一句话:
Do we already have this fragment?
原来他会先去FragmentManager里面去查找有没有相关的fragment:
如果有就直接使用 ;如果没有才会触发fragmentpageadapter的getItem方法获取一个fragment。 所以你更新的fragmentList集合是没有作用的,还要清除FragmentManager里面缓存的fragment。
依据如何更新FragmentManager的Fragment,我们可以得到两种思路
方法1:移除指定的Fragment,刷新一遍的同时,重新创建指定位置的Fragment#
1 |
|
如果是FragmentStateAdapter,思路1写法可能是这样
1 |
|
方法2:从FragmentManager获取Fragment,刷新它#
1 | /** |
PageAdapter每个方法的坑<span class=”hint–top hint–error hint–medium hint–rounded hint–bounce” aria-label=”FragmentPagerAdapter+FragementStatePagerAdapter API的坑#
“>[6]
viewpager2#adapter异步任务释放问题#
参考(3条消息) RecyclerView的Adapter中attach和detach探索_weixin_33882443的博客-CSDN博客
该文章遇到的问题:
Fragment销毁了,Recyclerview的异步任务没执行,尝试在adapter的onViewDetachedFromWindow释放任务,没进入该onViewDetachedFromWindow回调
该文找到做法:
第一步:在activity或fragment生命周期设置recyclerView.setAdapter(null);
第二步:adapter回进入onViewDetachedFromWindow回调
第三步:在onViewDetachedFromWindow中释放异步任务
该文章的参考
参考(Deprecated) Why you should call setAdapter(null) :: eneim’s blog
viewpager1、2替换指定Fragment问题#
参考ViewPage2 +FragmentStateAdapter + Fragment 刷新问题 - 简书 (jianshu.com)
以下代码都是FragmentPagerAdapter、FragmentStatePagerAdapter、FragmentStateAdapter可以参考的
第一步:存储taglist,重写tag的生成规则
1 | /** |
第二步:replace函数中remove掉FragmentManager中的Fragment,并重新初始化fragment
1 | /** |
其他问题#
java.lang.IllegalStateException: Fragment already active#
在 Fragment 没有被添加到 FragmentManager 之前,我们可以通过 Fragment.setArguments() 来设置参数,并在 Fragment 中,使用 getArguments() 来取得参数。这是常用的参数传递方式。
但是这种方式在 Fragment 被添加到 FragmentManager 后,再第二次调用 setArguments() 将会导致 java.lang.IllegalStateException: Fragment already active 异常。
解决此问题的办法是在继承的 Fragment 子类中,新增几个 setter,然后通过这些 setter 将数据传递过去。反向也是类似。
?>这些 setter 中要注意不要操作那些 View,这些 View 只有在 onCreateView() 事件后才可以操作。
java.lang.IllegalStateException: The application’s PagerAdapter changed the adapter’s contents without calling PagerAdapter#notifyDataSetChanged!#
1 | java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged! Expected adapter item count: 0, found: 4 Pager id: com.component.viewpager:id/vp_details Pager class: class androidx.viewpager.widget.ViewPager Problematic adapter: class com.component.viewpager.adapter.DetailsPagerAdapter |
Android java.lang.IllegalArgumentException: Invalid Transition types#
1 | atal Exception: java.lang.IllegalArgumentException: Invalid Transition types at android.support.v4.app.FragmentTransition.chooseImpl(FragmentTransition.java:461) at android.support.v4.app.FragmentTransition.configureTransitionsOrdered(FragmentTransition.java:3317) at android.support.v4.app.FragmentManagerImpl.executeOpsTogether(FragmentManager.java:2380) at android.support.v4.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManager.java:2338) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:2245) at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:703) at android.os.Handler.handleCallback(Handler.java:733) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5590) at java.lang.reflect.Method.invokeNative(Method.java) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084) at dalvik.system.NativeStart.main(NativeStart.java) |
原因:
如下代码,使用了错误包下的TransitionAPI
1 | ((TransitionSet) Objects.requireNonNull(fragment.getExitTransition())) |
解决:
将Transition包导入改为如下:
1 | # error import |
Mixing framework transitions#
1 | java.lang.IllegalArgumentException: Mixing framework transitions and AndroidX transitions is not allowed. Fragment ImagePagerFragment{a3b0fd8} (0be5f4cc-4fae-4a54-87be-5a0b57d19a90 id=0x7f08007c tag=ImagePagerFragment) returned Transition null which uses a different Transition type than other Fragments. |
原因:
多个Fragment切换,传递的Transition引用属于不同的包,一个Fragment引用的androidx包下的Transition,另一个Fragment引用android包下的Transition
解决:
将Transition的包导入统一改为android
1 | # error import |
- 1.FragmentPagerAdapter
>
>
> > ↩ - 2.animation-samples -GridToPager
>
>
> > ↩ - 3.views-widgets-samples-Viewpager
>
>
> > ↩ - 4. FragmentPagerAdapter数据刷新notifyDataSetChanged没效果研究
>
>
> > ↩ - 5.ViewPager刷新问题详解
>
>
> > ↩ - 6.FragmentPagerAdapter+FragementStatePagerAdapter API的坑
>
>
> > ↩ - 7.如何更新及替换ViewPager中的Fragment - SegmentFault 思否
>
>
> > ↩ - 8.[为什么调用 FragmentPagerAdapter.notifyDataSetChanged() 并不能更新其 Fragment? - Dancefire - 博客园 (cnblogs.com)](https://www.cnblogs.com/lianghui66/p/3607091.html) ↩