您的位置:首页 > 移动开发 > Android开发

Android键盘面板冲突 布局闪动处理方案

2017-04-01 11:07 471 查看
转:来自Android键盘面板冲突 布局闪动处理方案


起源,之前在微信工作的时候,为了给用户带来更好的基础体验,做了很多尝试,踩了很多输入法的坑,特别是动态调整键盘高度,二级页面是透明背景,魅族早期的Smart bar等, 后来逐一完善了,考虑到拥抱开源,看业界还是有很多应用存在类似问题。就有了这个repo



之前有写过一篇核心思想: Switching between the panel and the keyboard in Wechat












欢迎提交 Pull requests

尽量多的英文注解。

每个提交尽量的细而精准。

Commit message 遵循: AngularJS's commit message convention

尽可能的遵循IDE的代码检查建议(如 Android Studio 的 'Inspect Code')。

如何使用

build.gradle
中引入:

compile 'cn.dreamtobe.kpswitch:library:1.4.4'

使用引导

非全屏主题情况下使用引导


所谓非全屏主题,就是
(activity.getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0







I.
AndroidManifest


可直接参照: AndroidManifest.xml

对应的Activity,在
AndroidManifest
中配置
android:windowSoftInputMode=adjustResize



<manifest
...>
<application
...>

<activity
android:name=".activity.ChattingActivity"
android:windowSoftInputMode=adjustResize"/>
...
</application>
...
</manifest>

II. 需要处理页面的layout xml



需要用到 最上层布局 (KPSwitchRootFrameLayout/KPSwitchRootLinearLayout/KPSwitchRootRelativeLayout)

需要用到 面板布局(KPSwitchPanelFrameLayout/KPSwitchPanelLinearLayout/KPSwitchPanelRelativeLayout)。

简单案例:

<?xml version="1.0" encoding="utf-8"?>
<!-- 可选用 KPSwitchRootLinearLayout、KPSwitchRootRelativeLayout、KPSwitchRootFrameLayout -->
<cn.dreamtobe.kpswitch.widget.KPSwitchRootLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<!-- 布局内容 -->
...

<!-- 可选用 KPSwitchPanelLinearLayout、KPSwitchPanelRelativeLayout、KPSwitchPanelFrameLayout -->
<cn.dreamtobe.kpswitch.widget.KPSwitchPanelLinearLayout
android:id="@+id/panel_root"
android:layout_width="fill_parent"
android:layout_height="@dimen/panel_height"
android:visibility="gone">
<!-- 面板内容 -->
...
</cn.dreamtobe.kpswitch.widget.KPSwitchPanelLinearLayout>

</cn.dreamtobe.kpswitch.widget.KPSwitchRootLinearLayout>

III. 需要处理页面的Activity:



处理一些事件(KPSwitchConflictUtil)

键盘状态(高度与显示与否)监听(KeyboardUtil#attach())

简单案例:

...

// 面板View
private KPSwitchPanelLinearLayout mPanelLayout;
// 键盘焦点View,用于输入内容
private EditText mSendEdt;
// 用于切换键盘与面板的按钮View
private ImageView mPlusIv;

@Override
public void onCreate(Bundle saveInstanceState){
...

mPanelLayout = (KPSwitchPanelLinearLayout)findViewById(R.id.panel_root);
mSendEdt = (EditText) findViewById(R.id.send_edt);
mPlusIv = (ImageView) findViewById(R.id.plus_iv);

/**
* 这个Util主要是监控键盘的状态: 显示与否 以及 键盘的高度
* 这里也有提供给外界监听 键盘显示/隐藏 的监听器,具体参看
* 这个接口 {@Link KeyboardUtil#attach(Activity, IPanelHeightTarget, OnKeyboardShowingListener)}
*/
KeyboardUtil.attach(this, mPanelLayout);

/**
* 这个Util主要是协助处理一些面板与键盘相关的事件。
* 这个方法主要是对一些相关事件进行注册,如切换面板与键盘等,具体参看源码,比较简单。
* 里面还提供了一些已经处理了冲突的工具方法: 显示面板;显示键盘;键盘面板切换;隐藏键盘与面板;
*
* @param panelRoot 面板的布局。
* @param switchPanelKeyboardBtn 用于触发切换面板与键盘的按钮。
* @param focusView 键盘弹起时会给这个View focus,收回时这个View会失去focus,通常是发送的EditText。
*/
KPSwitchConflictUtil.attach(mPanelLayout, mPlusIv, mSendEdt);

}

...

...

// 如果需要处理返回收起面板的话
@Override
public boolean dispatchKeyEvent(KeyEvent event){
if (event.getAction() == KeyEvent.ACTION_UP &&
event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
if (mPanelLayout.getVisibility() == View.VISIBLE) {
KPSwitchConflictUtil.hidePanelAndKeyboard(mPanelLayout);
return true;
}
}
return super.dispatchKeyEvent(event);
}

全屏主题情况下使用引导


所谓全屏主题,就是
(activity.getWindow().getAttributes().flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0







I.
AndroidManifest


可直接参照: AndroidManifest.xml

对应的Activity,在
AndroidManifest
中配置
android:windowSoftInputMode=adjustUnspecified
,或者不配置,默认就是这个模式。


II. 需要处理页面的layout xml


<?xml version="1.0" encoding="utf-8"?>
...
...

<!-- 可选用 KPSwitchFSPanelFrameLayout、KPSwitchFSPanelLinearLayout、KPSwitchFSPanelRelativeLayout -->
<cn.dreamtobe.kpswitch.widget.KPSwitchFSPanelFrameLayout
android:id="@+id/panel_root"
style="@style/Panel"
android:visibility="gone">

...
</cn.dreamtobe.kpswitch.widget.KPSwitchFSPanelFrameLayout>

...

III. 需要处理页面的Activity:



主要是处理一些事件(KPSwitchConflictUtil)

键盘状态(高度与显示与否)监听(KeyboardUtil#attach())

onPause
时,记录键盘状态用于从后台回到当前布局,恢复键盘状态不至于冲突(IFSPanelConflictLayout#recordKeyboardStatus())

如下使用案例:

...

// 面板View
private KPSwitchFSPanelLinearLayout mPanelLayout;
// 键盘焦点View,用于输入内容
private EditText mSendEdt;
// 用于切换键盘与面板的按钮View
private ImageView mPlusIv;

@Override
public void onCreate(Bundle saveInstanceState){
...

mPanelLayout = (KPSwitchFSPanelLinearLayout)findViewById(R.id.panel_root);
mSendEdt = (EditText) findViewById(R.id.send_edt);
mPlusIv = (ImageView) findViewById(R.id.plus_iv);

/**
* 这个Util主要是监控键盘的状态: 显示与否 以及 键盘的高度
* 这里也有提供给外界监听 键盘显示/隐藏 的监听器,具体参看
* 这个接口 {@Link KeyboardUtil#attach(Activity, IPanelHeightTarget, OnKeyboardShowingListener)}
*/
KeyboardUtil.attach(this, mPanelLayout);

/**
* 这个Util主要是协助处理一些面板与键盘相关的事件。
* 这个方法主要是对一些相关事件进行注册,如切换面板与键盘等,具体参看源码,比较简单。
* 里面还提供了一些已经处理了冲突的工具方法: 显示面板;显示键盘;键盘面板切换;隐藏键盘与面板;
*
* @param panelRoot 面板的布局。
* @param switchPanelKeyboardBtn 用于触发切换面板与键盘的按钮。
* @param focusView 键盘弹起时会给这个View focus,收回时这个View会失去focus,通常是发送的EditText。
*/
KPSwitchConflictUtil.attach(mPanelLayout, mPlusIv, mSendEdt);

}

@Override
protected void onPause() {
super.onPause();
// 用于记录当前的键盘状态,在从后台回到当前页面的时候,键盘状态能够正确的恢复并且不会导致布局冲突。
mPanelLayout.recordKeyboardStatus(getWindow());
}

...

// 如果需要处理返回收起面板的话
@Override
public boolean dispatchKeyEvent(KeyEvent event){
if (event.getAction() == KeyEvent.ACTION_UP &&
event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
if (mPanelLayout.getVisibility() == View.VISIBLE) {
KPSwitchConflictUtil.hidePanelAndKeyboard(mPanelLayout);
return true;
}
}
return super.dispatchKeyEvent(event);
}

基本原理

键盘高度计算,以及键盘是否显示的计算,参看:KeyboardUtil.KeyboardStatusListener#calculateKeyboardHeightKeyboardUtil.KeyboardStatusListener#calculateKeyboardShowing

处理闪动问题,参看: KPSwitchRootLayoutHandler,以及如果是非全屏主题用到的面板布局:KPSwitchPanelLayoutHandler;如果是全屏主题用到的面板布局: KPSwitchFSPanelLayoutHandler

Jacksgong / JKeyboardPanelSwitch

Star1930Fork355

项目描述:For resolve the layout conflict when keybord & panel are switching (Android键盘面板冲突 布局闪动处理方案) — 查看更多内容...

问题列表:
#43Adapt the case of DialogFragmentanjiao 2017-03-27
#55focusView.setOnTouchListener在up的时候。panelLayout.setVisibility(View.INVISIBLE);lyqaiym 2017-01-24
#54希望能适配下panel是用fragment填充的情况mansoul1994 2017-01-05
#52Demo中 锁屏会出现问题fanss 2016-12-30
#53建议在onGlobalLayout中判断下 activity 是否有焦点RubinChen 2016-12-29
分支代码更新时间:2017-03-09

开发语言:Java

下载ZIP
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: