SlidingMenu在Android 5.0上存在兼容性问题,在有多个Fragment切换的Activity中,如果同时存在SlidingMenu,则打开一次侧滑菜单,界面就卡住了,不能刷新,不能切换Fragment。
最近,测试给提了个bug,说在华为P8手机上侧滑菜单打开后,不能切换卡项,经过一番研究,发现这个是Slidingmenu在5.0上存在的兼容问题,下面记录以下研究过程。
先上图,MainActivity有侧滑菜单和多个Fragment,点击下面的按钮依次切换三个Fragment,如图是正常情况:
接着来看bug, 只要打开一次侧滑菜单,界面就卡住了,点击下面的按钮不能切换卡片,但是实际上是切换了的,只是界面没有刷新而已,如图:
看到了吗,虽然点击了卡项2,但是界面并没有刷新
(1) 主界面布局就下面一排按钮,加一个FrameLayout作为Fragment的容器
layout\activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" >
<LinearLayout android:id="@+id/ly_bottom" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:orientation="horizontal" >
<Button android:id="@+id/btn1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="卡片1" />
<Button android:id="@+id/btn2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="卡片2" />
<Button android:id="@+id/btn3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:text="卡片3" />
</LinearLayout>
<FrameLayout android:id="@+id/ly_content" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@id/ly_bottom">
</FrameLayout>
</RelativeLayout>
(2) MainActivity中加入Slidigmenu,每次点击按钮就会切换Fragment
MainActivity:
public class MainActivity extends Activity implements View.OnClickListener {
private SlidingMenu menu;
private Fragment1 f1 = new Fragment1();
private Fragment2 f2 = new Fragment2();
private Fragment3 f3 = new Fragment3();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btn1).setOnClickListener(this);
findViewById(R.id.btn2).setOnClickListener(this);
findViewById(R.id.btn3).setOnClickListener(this);
this.initMenu();
}
private void initMenu() {
menu = new SlidingMenu(this);
menu.setMode(SlidingMenu.LEFT);
menu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
menu.setShadowWidth(300);
menu.setBehindOffset(200);
menu.attachToActivity(this, SlidingMenu.SLIDING_CONTENT);
menu.setMenu(R.layout.left_menu);
}
@Override
public void onClick(View v) {
FragmentTransaction tr = getFragmentManager().beginTransaction();
switch (v.getId()) {
case R.id.btn1:
Toast.makeText(this, "点击了卡项1", Toast.LENGTH_SHORT).show();
tr.replace(R.id.ly_content, f1);
break;
case R.id.btn2:
Toast.makeText(this, "卡项2被点击了", Toast.LENGTH_SHORT).show();
tr.replace(R.id.ly_content, f2);
break;
case R.id.btn3:
Toast.makeText(this, "点击了卡项3", Toast.LENGTH_SHORT).show();
tr.replace(R.id.ly_content, f3);
break;
}
tr.commit();
}
}
(3) 三个Fragment是相同的,就一个TextView,然后设一下背景,这里只列举第一个,其余两个改下字体颜色和背景
layout\layout_fragment_1.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="卡片1" android:textColor="@android:color/holo_green_dark" android:textSize="24sp" />
</RelativeLayout>
Fragment1.java:
public class Fragment1 extends Fragment {
public static Fragment1 newInstance(Context context) {
Fragment1 fragment = new Fragment1();
return fragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.layout_fragment_1, null);
}
}
详细代码请看附件
这个具体原因也不清楚,只是在Android 5.0上出现,例如:华为P8。在Android 6.0则不存在,所以,归结为SlidingMenu的兼容问题
第一种解决方法是开启硬件加速
在AndroidManifest.xml文件中在application标签中添加属性 android:hardwareAccelerated=”false”,如图:
但是,这种方法有个缺点,就是开启了硬件加速之后,如果碰到非常复杂的界面布局,嵌套太多的话,就会报StackOverflow的错误,可以自己百度一下,如果你恰好遇到一个喜欢留个FrameLayout,然后在代码里面不停的removeAllView()、addView(),动态添加布局的猪一样的队友,那么恭喜你,很有可能遇到我说的情况。顺便说一下,优雅的解决复杂布局的方法是用多个Fragment来拆开复杂界面、分离页面逻辑
万一你遇到开启硬件加速后,复杂界面报错的情况怎么办呢?别着急,临时关闭硬件加速就可以了,告诉机器,这个界面不要硬件加速。
首先找到报错的那个界面,例如MainActivity,然后设置这个Activity的属性,针对这个Activity不要使用硬件加速就可以了,如图:
如果这个猪一样的队友写的报错界面太多了,你总不能一个一个去找吧,所以,就有第二种方法,直接修改SlidingMenu的源码
修改SlidingMenu.java,定位到第1005行,将下面的代码:
boolean layer = percentOpen > 0.0f && percentOpen < 1.0f;
改为:
boolean layer = percentOpen >= 0.0f && percentOpen <= 1.0f;
推荐使用这种方法,好了,问题解决。
博主是参考了StackOverflower上面这篇文章解决的:
http://stackoverflow.com/questions/28563240/ui-not-refreshed-after-first-toggle-the-sliding-menu-on-android-5-0-lollipop
这个bug我已经提到Github上SlidingMenu的issue了,详见下面地址:
https://github.com/jfeinstein10/SlidingMenu/issues/754
SlidingMenu的坑真是不少啊,已经发现两个了,之前博主发现一个bug,写了一篇博客,参见:
SlidingMenu addIgnoreView() 无效的bug解决方法
本文演示用的demo已上传,下载地址:http://download.csdn.net/detail/fuchaosz/9548810
Tips
如果觉得这篇博客对你有帮助或者喜欢博主的写作风格,就给博主留个言或者顶一下呗,鼓励博主创作出更多优质博客,Thank you.