Android软键盘与工具面板的切换

小蜗牛06 8年前
   <h2><strong>老规矩,效果图先上</strong></h2>    <p style="text-align:center"><img src="https://simg.open-open.com/show/1d11ab92fc6c54ed90be2fe3dec4dae1.gif"></p>    <p style="text-align:center">我是效果图</p>    <p>点击输入框,软键盘弹起</p>    <p>点击Switch按钮时,软键盘与面板进行切换</p>    <p>触碰空白处,软键盘与面板均隐藏</p>    <p>这个效果的关键点是获取软键盘的高度(我们用变量KeyboardHeight代表软键盘的高度),将面板的高度设置为KeyboardHeight,那么切换时,输入框在屏幕的位置就岿然不动了,看似简单,实际上要获取KeyboardHeight要花些许功夫。</p>    <p>先上布局。</p>    <pre>  <code class="language-java"><?xml version="1.0" encoding="utf-8"?>  <RelativeLayout      xmlns:android="http://schemas.android.com/apk/res/android"      xmlns:tools="http://schemas.android.com/tools"      android:id="@+id/activity_chat_room"      android:layout_width="match_parent"      android:layout_height="match_parent"      tools:context="com.hayukleung.kps.ChatRoomActivity"      >    <ScrollView        android:id="@+id/kps_content"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_above="@+id/kps_bottom"        >    </ScrollView>    <LinearLayout        android:id="@+id/kps_bottom"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:orientation="vertical"        >      <RelativeLayout          android:id="@+id/kps_bar"          android:layout_width="match_parent"          android:layout_height="wrap_content"          >        <EditText            android:id="@+id/kps_text"            android:layout_width="match_parent"            android:layout_height="40dp"            android:layout_centerVertical="true"            android:layout_toLeftOf="@+id/kps_switch_panel"            />        <Button            android:id="@+id/kps_switch_panel"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_alignParentEnd="true"            android:layout_centerVertical="true"            android:text="switch\npanel and keyboard"            android:textSize="10sp"            />      </RelativeLayout>      <View          android:id="@+id/kps_panel"          android:layout_width="match_parent"          android:layout_height="0dp"          android:background="@color/colorPrimary"          />    </LinearLayout>  </RelativeLayout></code></pre>    <p style="text-align:center"><img src="https://simg.open-open.com/show/b6893e2c085481b9c3c5700ad1881f5a.png"></p>    <p style="text-align:center">Android Screen Size</p>    <p>从上图可以得出KeyboardHeight与屏幕各部分尺寸值得算术关系,我们逐一将它们计算出来。</p>    <h2><strong>软键盘的弹起</strong></h2>    <p>首先我们要了解Android软键盘弹起时Activity的布局变化情况,设置SOFT_INPUT_ADJUST_RESIZE,Activity的布局会根据软键盘的高度压缩自己,设置SOFT_INPUT_ADJUST_PAN,Activity的布局只会保证输入框焦点出的位置不被软键盘遮挡,将布局往上推 <strong>最小</strong> 的距离。我们计算软键盘的做法就是利用 <strong>SOFT_INPUT_ADJUST_RESIZE</strong> 的特点,软键盘弹起时Activity设置为SOFT_INPUT_ADJUST_RESIZE。这样就可以得到Activity的布局高度的变化值,这个值就与软键盘的高度有关了。</p>    <pre>  <code class="language-java">/**   * 显示键盘   */  private void showKeyboard() {    mInputMethodManager.showSoftInput(mKpsText, SHOW_IMPLICIT);    setSoftInputMode(SOFT_INPUT_STATE_UNCHANGED | SOFT_INPUT_ADJUST_RESIZE);  }  /**   * 隐藏键盘   */  private void hideKeyboard() {    mInputMethodManager.hideSoftInputFromWindow(mKpsText.getWindowToken(), HIDE_NOT_ALWAYS);    setSoftInputMode(SOFT_INPUT_STATE_UNCHANGED | SOFT_INPUT_ADJUST_PAN);  }  /**   * 动态更改软键盘模式   *   * Desired operating mode for any soft input area. May be any combination of:   *   * <ul>   * <li> One of the visibility states   * {@link #SOFT_INPUT_STATE_UNSPECIFIED},   * {@link #SOFT_INPUT_STATE_UNCHANGED},   * {@link #SOFT_INPUT_STATE_HIDDEN},   * {@link #SOFT_INPUT_STATE_VISIBLE},   * {@link #SOFT_INPUT_STATE_ALWAYS_HIDDEN},   * {@link #SOFT_INPUT_STATE_ALWAYS_VISIBLE}.   * <li> One of the adjustment options   * {@link #SOFT_INPUT_ADJUST_NOTHING},   * {@link #SOFT_INPUT_ADJUST_UNSPECIFIED},   * {@link #SOFT_INPUT_ADJUST_RESIZE},   * {@link #SOFT_INPUT_ADJUST_PAN}.   *   * @param mode   */  private void setSoftInputMode(int mode) {    getWindow().setSoftInputMode(mode);  }</code></pre>    <p>要监听Activity高度的变化,可以对Activity的根布局设置OnGlobalLayoutListener监听。一旦布局的大小发生变化就会执行里面的onGlobalLayout方法,我们会在该方法完成对软键盘高度的计算。一开始软键盘未弹起时,该方法会一直空转,一旦弹起,我们就拿到了数据完成计算,完成了计算及时移除该监听,避免不必要的性能损耗。</p>    <pre>  <code class="language-java">// mActivityChatRoom是根布局Layout,软键盘弹起时会引起它的布局大小变化,对它进行布局变化监听  mActivityChatRoom.getViewTreeObserver()      .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {        private int keyboardHeight = 0;        private boolean hasNavigationBar = true;        @Override public void onGlobalLayout() {          // TODO 计算StatusBarHeight          // TODO 计算ActionBarHeight          // TODO 计算NavigationBarHeight          // TODO 计算ScreenHeight          // TODO 计算ActivityHeight          // TODO 计算KeyboardHeight          if (0 < keyboardHeight) {            // 成功计算得到KeyboardHeight,及时移除监听            mActivityChatRoom.getViewTreeObserver()              .removeOnGlobalLayoutListener(this);          }        }      });</code></pre>    <h2><strong>StatusBarHeight</strong></h2>    <pre>  <code class="language-java">Rect rect = new Rect();  getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);  int statusBarHeight = rect.top;</code></pre>    <h2><strong>ActionBarHeight</strong></h2>    <pre>  <code class="language-java">TypedValue tv = new TypedValue();  getTheme().resolveAttribute(R.attr.actionBarSize, tv, true);  int actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics());</code></pre>    <h2><strong>NavigationBarHeight</strong></h2>    <pre>  <code class="language-java">Resources resources = getResources();  int navigationBarHeight = resources.getDimensionPixelSize(resources.getIdentifier("navigation_bar_height","dimen", "android"));</code></pre>    <p>计算NavigationBarHeight时需要注意,我们的手机如果不存在NavigationBar,这个值算出来并不是0,所以不能简单的通过该值判断手机是否存在NavigationBar,需要进行一步额外的判断。具体是,键盘未弹起时计算得到的KeyboardHeight应该是0,如果计算出来的值是-NavigationBarHeight,说明该手机没有NavigationBar,这时候将NavigationBar不存在的布尔状态记录下来,等到软键盘弹起计算高度时就根据该布尔量忽略掉NavigationBarHeight。</p>    <h2><strong>ScreenHeight & ActivityHeight</strong></h2>    <pre>  <code class="language-java">// mActivityChatRoom是根布局Layout  int screenHeight = mActivityChatRoom.getRootView().getHeight();  int activityHeight = mActivityChatRoom.getHeight();</code></pre>    <h2><strong>KeyboardHeight</strong></h2>    <pre>  <code class="language-java">keyboardHeight = screenHeight - activityHeight - statusBarHeight - actionBarHeight - navigationBarHeight;  if (0 == keyboardHeight + navigationBarHeight) {    // 不存在navigation bar    hasNavigationBar = false;  }  keyboardHeight += hasNavigationBar ? 0 : navigationBarHeight;  ViewGroup.LayoutParams params = mKpsPanel.getLayoutParams();  params.height = keyboardHeight;mKpsPanel.setLayoutParams(params);</code></pre>    <p> </p>    <p> </p>    <p>来自:http://www.jianshu.com/p/46a5dfe96a66</p>    <p> </p>