目标
实现如下图所示的切换效果
功能分析
- 需要一个透明度参数,下一个场景慢慢出现,上一个场景慢慢消失
- 滑动前需要知道左右场景的
weatherId
,才能完成向下一场景的切换。weatherId
可以通过不同天气fragment的天气数据得到,我的做法是在viewpager中得到fragment再从fragment中得到天气数据,再得到weatherId。 - 根据滑动方向和当前
fragment
在viewpager
中的itemId
来确定下一个场景的weatherId
。
层次结构
<?xml version="1.0" encoding="utf-8"?>
<com.moji.sencedemo.MJRelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.moji.sencedemo.MainActivity">
<com.moji.sencedemo.MJFrameLayout
android:id="@+id/fl_bg"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.moji.sencedemo.MJFrameLayout>
<com.moji.sencedemo.MJViewPager
android:layout_width="match_parent"
android:id="@+id/vp_content"
android:layout_height="match_parent">
</com.moji.sencedemo.MJViewPager>
</com.moji.sencedemo.MJRelativeLayout>
如上面布局所示,底层是一个framelayout
用来存放LibGdx
中自定义的AndroidFragmentApplication
。上层是一个viewpager
,用来存放多个fragment
,左右滑动时可以切换不同的fragment
。
监听ViewPager滑动
获取稳定的1~0参数
-
onPageScrolled(int position, float positionOffset, int positionOffsetPixels)
在这个方法中监听到的,当向左滑动时positionOffset
是从1~0。
当向右滑动时positionOffset
是从010。 - 产生的问题:
通过监听知道:当向右滑动时在onPageScrolled方法中执行以下操作可以得到0~1的参数。
if(lastPosition!=position) {
posit = 1;
lastPosition = position;
}
如果当左滑动时取posit,当向右滑动时1-posit就得到了稳定的1~0参数。
- 当需要参数变化有速度上的变化可以参照AndroidInterpolator的算法。例如,先慢后快的参数变化:
posit = (float)(Math.cos((posit + 1) * Math.PI) / 2.0f) + 0.5f;
接下来需要得到下一个场景的weatherId。
根据滑动方向得到下一个场景的天气Id
if (right) {//滑不动的时候,是不再滑的。
String integer = null;
try {
integer = weatherIdses.get(currentPosition + 1);
} catch (Exception e) {
e.printStackTrace();
}
if (integer != null) {
MJSceneManager.getInstance().switchScreen(integer, posit);
}
} else {
String integer = null;
try {
integer = weatherIdses.get(currentPosition - 1);
} catch (Exception e) {
e.printStackTrace();
}
if (integer != null) {
MJSceneManager.getInstance().switchScreen(integer, posit);
}
}
判断滑动方向得到下一个场景的weatherId
切换到下一个场景。
�判断滑动方向
- 判断的第一步
onPageScrolled(int position, float positionOffset, int positionOffsetPixels){
currentPosition = mViewPager.getCurrentItem();
if(position >= currentPosition) {
right = true;
left = false;
} else {
right = false;
left = true;
}
}
当向右滑动时position=currentPosition
。当向左滑动并没滑动到尽头时position<currentPosition
。但是当向左滑动并且滑动到尽头时position=currentPosition
。判断结果是向右滑动,因为场景会发生变化。
- 判断第二步
出现的问题:
问题原因: 当向左滑动时滑动到尽头时方向判断是错的。
解决方法:判断左边滑动到尽头
onPageScrolled(int position, float positionOffset, int positionOffsetPixels){
currentPosition = mViewPager.getCurrentItem();
if(position >= currentPosition) {
right = true;
left = false;
} else {
right = false;
left = true;
}
if(currentPosition == 0&&isScrolling&&positionOffset == 0) {//左边滑动的时候,判断是不是滑动到了头。
right = false;
left = false;
}
}
加上下面的这个判断可以判断是否是向左滑动到头,这时也要判断即不是向左边滑动也不是向右边滑动。
其中isScrolling
的标志是判断viewPager
是否正在滑动,判断方法如下:
public void onPageScrollStateChanged(int state,ScrollCallBack callBack) {
//stage=1表示正在滑动
//stage=2表示滑动完毕了
//stage=0表示什么都没做
if(state == 1) {
isScrolling = true;
} else {
isScrolling = false;//当连续缓慢滑动时没有调用滑动完毕,只调用
}
- 判断第三步
出现的问题:如下图
问题原因:当左右滑动时,滑动到一半松手后自动滑动到下一页时,上面的方向判断就会出错,mViewPager.getCurrentItem()
该方法在滑动到一半时松手,值会发生变化。具体表现如下图:
解决方法:
onPageScrolled(int position, float positionOffset, int positionOffsetPixels){
if(first) {
currentPosition = mViewPager.getCurrentItem();
if(position >= currentPosition) {
right = true;
left = false;
} else {
right = false;
left = true;
}
if(currentPosition == 0&&isScrolling&&positionOffset == 0) {//左边滑动 的时候,判断是不是滑动到了头。
right = false;
left = false;
}
}
isFirst = false;
}
加上以上判断可以解决滑动方向的判断。isFirst什么时候还原呢?
public void onPageScrollStateChanged(int state,ScrollCallBack callBack) {
//stage=1表示正在滑动
//stage=2表示滑动完毕了
//stage=0表示什么都没做
if(state == 0) {
isFirst = true;
}
- 判断第四步
出现的问题:如下图所示
问题原因:左右滑动到尽头时,转变方向时,isFirst
没有被重置,方向判断错误。场景不发生变化。
解决方法:判断左右滑动到尽头,并转变方向时,重新计算滑动的方向。
onPageScrolled(int position, float positionOffset, int positionOffsetPixels){
if(scrollStage == 1&&position == mViewPager.getCurrentItem()&&positionOffsetPixels == 0) {
mIsEnd = true;
} else {
mIsEnd = false;
}
if(lastEnd&&!mIsEnd) {
isFirst = true;
}
if(first) {
currentPosition = mViewPager.getCurrentItem();
if(position >= currentPosition) {
right = true;
left = false;
} else {
right = false;
left = true;
}
if(currentPosition == 0&&isScrolling&&positionOffset == 0) {//左边滑动 的时候,判断是不是滑动到了头。
right = false;
left = false;
}
isFirst = false;
}
lastEnd = mIsEnd;
}
下面这个方法判断左边和右边滑动到头。其中scrollState=1表明正在滑动。
if(scrollState == 1&&position == mViewPager.getCurrentItem()&&positionOffsetPixels == 0) {
mIsEnd = true;
} else {
mIsEnd = false;
}
判断左边和右边滑动到头后,突然转变方向,则是下面这个方法来判断。
if(lastEnd&&!mIsEnd) {
isFirst = true;
}
- 判断第五步
出现的问题:如下图所示
问题原因: 当手指粘着屏幕左右滑动时,isFirst
没有更新,导致方向判断错误。
解决方法:判断手指粘着屏幕滑动。重置isFirst
参数
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels,ScrollCallBack callBack) {
if(scrollStage == 1&&lastPixels!=0&&Math.abs(lastPixels - positionOffsetPixels) >500) {
isFirst = true;
1、MJSceneManager.getInstance().setPageSelect(currentPosition - position);
}
if(scrollStage == 1&&position == mViewPager.getCurrentItem()&&positionOffsetPixels == 0) {
mIsEnd = true;
} else {
mIsEnd = false;
}
if(lastEnd&&!mIsEnd) {
isFirst = true;
}
if(first) {
currentPosition = mViewPager.getCurrentItem();
if(position >= currentPosition) {
right = true;
left = false;
} else {
right = false;
left = true;
}
if(currentPosition == 0&&isScrolling&&positionOffset == 0) {//左边滑动 的时候,判断是不是滑动到了头。
right = false;
left = false;
}
isFirst = false;
}
lastEnd = mIsEnd;
}
- 判断第六步
出现的问题:当快速滑动时场景会出现以下问题:
问题的原因:是下一个场景在快速滑动时没有赋值给当前场景, 当前场景一直没有改为,出现场景重叠。
解决方法:快速滑动时把下一个场景赋值给当前场景,并把下一个场景置为空。
MJSceneManager.getInstance().setPageSelect(currentPosition - position);
具体代码如下:
public void setPageSelect(int diff) {//触摸不松手滑动到ViewPager中item变化的时候
hasInitStage = false;
pageSelect = true;
if(diff == 0||diff == 1) {//左右粘着滑动,
} else if(diff == 2||diff == -1){ //左右快速滑动
alpha = 1.0f;
useAlpha = 1.0f;
isSwitch = false;
mIsScroll = false;
pageSelect = false;
if(mNextStage != null) {
mCurrentStage = mNextStage;
}
mNextStage = null;
}
}
- 判断第七步
出现的问题:如下图所示
问题原因:在左右粘着滑动时,当前场景一直没有变化,而上一个步骤把当前场景给置空了,因此需要判断粘着滑动不作任何处理。
解决方法:区分粘着滑动和快速滑动。方法public void setPageSelect(int diff)
的参数是为了区分快速滑动和左右粘着滑动。
public void setPageSelect(int diff) {//触摸不松手滑动到ViewPager中item变化的时候
hasInitStage = false;
pageSelect = true;
if(diff == 0||diff == 1) {//左右粘着滑动,
} else if(diff == 2||diff == -1){ //左右快速滑动
alpha = 1.0f;
useAlpha = 1.0f;
isSwitch = false;
mIsScroll = false;
pageSelect = false;
if(mNextStage != null) {
mCurrentStage = mNextStage;
}
mNextStage = null;
}
}
至此,LigGdx滑动渐变的实现过程分析完毕,下一次会分析一下粒子和骨骼动画的融合。