Activity嵌套多个Fragment且包含Toolbar和Tabhost时对软键盘的一种处理方法

写了有两年多的Android代码,软键盘问题一直是一个很恶心的问题,在style.xml文件中对Activity设置不同的Theme、在AndroidManifest.xml中对Activity设置windowsSoftInputMode、是否有Toolbar等等都会对软键盘的设置造成影响。正好手里的项目很多页面(既有Activity页面的,也有Fragment页面的)有大量的EditText,这两天发现在Android4.x.x系统有bug,这次做一个记录,以供大家参考,手里只有Android4.4.2、Android4.4.4、Android5.1、Android6.0、Android7.1、Android8.0的手机,实测这些手机中没有问题。

1、对于在Activity中的处理还比较容易,处理的方法也比较多,这里说一种可行的方法:将所有EditText(比如除了Toolbar以外的其他所有控件)统统放到一个ScrollView中,AndroidManifest.xml中不需要对Activity进行软键盘设置,如果设置了android:windowSoftInputMode="adjustPan",请去掉 (否则Toolbar会被一起弹出屏幕),布局xml中也不需要进行其他设置,这样点击EditText的时候,Toolbar会保持不动,ScrollView会自行滚动以适应布局变化。

2、ViewPager+Fragment组合下,且Activity顶部包含Toolbar,底部有一个LinearLayout(里面是n个Fragment的切换按钮),见下方示意图:

先说说我踩过的坑:父Activity的布局结构从上到下依次是Toolbar,ViewPager,LinearLayout。对于Fragment的xml布局,我依旧是采用和Activity中一样,根布局采用ScrollView,结果发现软键盘弹起来的时候,父Activity底部的LinearLayout也被弹起来了,虽然Fragment的输入框没有被遮住,但是看着非常不爽。然后各种百度,说来说去都是说在AndroidManifest中给Activity添加属性android:windowSoftInputMode="adjustPan",可是这样虽然能解决Activity底部LinearLayout不弹起来,但是顶部的Toolbar却又被整体移出屏幕了啊!无奈之下采取了下面这个方法:Fragment的布局依旧采用ScrollView作为根布局,Activity在代码中对根布局进行布局变化监听(软键盘的弹起和收回都会触发这个方法),如果键盘弹起来,先记录当前底部LinearLayout的高度,然后将高度动态设置为0;如果键盘收起来,则动态设置底部LinearLayout的高度恢复为之前记录的高度,代码如下:

 

findViewById(R.id.ll_root).addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
    @Override
    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        LogUtils.d("bottom:" + bottom + ",oldBottom:" + oldBottom + ",menuHeight:" + menuHeight);
        if (bottom - oldBottom < -1) {
            //软键盘弹上去了,先记录下底部控件的高度,再动态设置高度为0
            menuHeight = llMenu.getHeight();
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0);
            llMenu.setLayoutParams(params);
        } else if (bottom - oldBottom > 1) {
            if (isFirst) {
                isFirst = false;
            } else {
                //软键盘弹下去了,动态设置高度,恢复原先控件高度
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, menuHeight);
                llMenu.setLayoutParams(params);
            }
        }
    }
});

说一下各个变量的意思:ll_root是Activity根布局的id;llMenu是Activity底部切换Fragment的一组按钮所在的LinearLayout,menuHeight则是这个LinearLayout的高度;isFirst是标记是否是刚进入页面,因为在页面还在渲染的时候也会触发这个方法,而且是bottom<oldBottom,这样的话会误判为键盘收起,导致llMenu设置高度为menuHeight的初始值,而不是真正的高度(因为此时还没能记录下llMenu的高度),注意llMenu的高度切不可直接在在onCreate()方法中获取,因为那时候页面还没渲染完成,所有控件的高度获取的都一定是0。

 

然而,下午忽然发现在Android4.x.x系统的手机上,依旧会弹起Activity底部的llMenu,打印Log一看,原来在Android4.x.x系统的手机上,监听Activity的根布局变化时,软键盘的弹起与隐藏不会对bottom的值造成改变,导致bottom与oldBottom始终相等,也就不会进入if判断。既然根布局变化监听不行,索性直接监听llMenu好了,然后把findViewById(R.id.ll_root)换成了llMenu,结果发现能正常进入if判断而且判断的也是正确的,可是在 onLayoutChange()方法中不执行llMenu.setLayoutParams(params);语句。最终的解决方案是:在llMenu外再嵌套一个LinearLayout(下方代码里面的menuRoot),对外层的LinearLayout的位置进行监听(软键盘的弹起和收回会改变bottom的值),然后在onLayoutChange()方法中动态改变llMenu的高度。

 

// ①注意此处不采用直接对根布局的变化监听,因为在Android5.0以下的系统,监听根布局变化时,软键盘的弹起和隐藏,并不会对bottom造成改变
//   导致bottom和oldBottom始终相等;
// ②也不能直接对llMenu进行监听,在onLayoutChange()方法中llMenu.setLayoutParams(params)并没有效果;
// ③采取的方法是在llMenu外层包裹一个menuRoot,对menuRoot进行监听,至此解决问题
findViewById(R.id.menuRoot).addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
    @Override
    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        if (bottom - oldBottom < -1) {
            LogUtils.d("ViewPosition", "键盘显示,bottom:" + bottom + ",oldBottom:" + oldBottom + ",llMenu.getBottom():" + llMenu.getBottom() + ",menuHeight:" + menuHeight);
            //软键盘弹上去了,先记录下底部控件的高度,再动态设置高度为0
            menuHeight = llMenu.getHeight();
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0);
            llMenu.setLayoutParams(params);
        } else if (bottom - oldBottom > 1) {
            LogUtils.d("ViewPosition", "键盘隐藏,bottom:" + bottom + ",oldBottom:" + oldBottom + ",llMenu.getBottom():" + llMenu.getBottom() + ",menuHeight:" + menuHeight);
            if (isFirst) {
                isFirst = false;
            } else {
                //软键盘弹下去了,动态设置高度,恢复原先控件高度
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, menuHeight);
                llMenu.setLayoutParams(params);
            }
        }
    }
});

至此解决了问题,工作太忙没时间写demo,如有问题欢迎评论区交流。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 一个Activity可以包含多个Fragment,这些Fragment可以在Activity的布局中嵌套显示,也可以在Activity运行动态添加或移除。每个Fragment都有自己的生命周期和布局,可以独立地处理用户交互和数据展示。通过在ActivityFragment之间进行通信,可以实现复杂的应用程序逻辑和界面交互。同,使用Fragment还可以实现多屏幕适配和模块化开发,提高应用程序的可维护性和可扩展性。 ### 回答2: 一个Activity可以包含多个Fragment,而不仅仅是一个Fragment。这个特性使得应用程序的界面更加灵活和易于扩展。每个Fragment向用户展示一个小的UI组件,比如一个输入框、一个列表或者一个图片。这些小的UI组件通过Activity的布局被组合在一起,形成一个复杂的界面。 通过在Activity中添加多个Fragment,可以将UI分成多个可重用的模块。这样做的优点有: 1. 易于维护和升级:由于Fragment可以被视为Activity中的独立单元,因此可以轻松地使用独立的代码库进行维护和升级。 2. 分层结构清晰:通过使用多个Fragment,可以创建一个层次结构更加清晰的UI,让用户更容易理解和使用。 3. 更好的可扩展性:通过添加新的Fragment,可以快速地扩展已有的应用程序,并增加新的功能。 4. 设计灵活性更高:通过使用多个Fragment,可以更灵活地布局应用程序,使其更符合用户需求和设备屏幕尺寸。 虽然使用多个Fragment可以带来很多优点,但也应该注意不要滥用。如果使用过多的Fragment,会导致应用程序变得复杂和难以维护。因此,在设计应用程序的候,应该根据需求和屏幕尺寸来适当地使用多个Fragment,达到最优的效果。 ### 回答3: Android应用程序开发通常使用ActivityFragment两种组件来构建应用程序界面。Activity是应用程序的主要组件,当应用程序启动,会默认启动一个Activity。而Fragment则是Activity内部的组件,一种小型的Activity。可以在一个Activity内嵌入多个Fragment,实现更加丰富的界面效果。 一般情况下,一个Activity包含多个Fragment。每个Fragment可以有自己的布局和逻辑处理Fragment可以被动态添加到Activity中,并且可以根据需要动态地删除或替换。这种方式可以让应用程序在不同的设备上适应不同的屏幕大小。例如,在平板电脑上,应用程序可以显示多个Fragment,而在智能手机上,则只能显示一个Fragment。 在一个Activity中使用多个Fragment的好处在于可以实现多个UI界面。不同的Fragment可以处理不同的任务,例如,一个Fragment可以显示数据列表,另一个Fragment可以用来编辑这些数据。当用户点击菜单或按钮,可以动态地在Activity中添加、删除或替换Fragment,从而实现不同的UI效果。 此外,使用多个Fragment还可以方便地实现界面的复用。例如,可以在不同的Activity中使用同一个Fragment来显示数据列表或一组控件。这样可以节省开发间和代码量,同也可以使应用程序更加简洁。 总之,一个Activity多个Fragment是Android应用程序开发中常见的设计模式。通过灵活地添加、删除或替换Fragment,可以实现丰富多彩的UI效果,同也可以方便地实现UI的复用。因此,开发者在进行应用程序开发,可以根据实际需求使用这种设计模式,从而提高开发效率和用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值