android 软键盘的显示与隐藏问题的研究

Note:事实上,如果配置了adjustUnspecified,软键盘的行为会和layout有很大关系,是否可滑动,是否有相对关系等,需要按实际情况具体对待。


http://www.2cto.com/kf/201405/298962.html


在android中,经常会和输入法的软件键盘交互。在Manifest文件里,系统给activity的一个属性-windowSoftInputMode来控制输入法的显示方式。该属性提供了Activity的window与软键盘的window交互的方式。这里的属性设置有两方面的影响:
1.软键盘的显示与隐藏。-当Activity界面成为用户的焦点时,或隐藏或显示。
2。对Activty的主window窗口进行调整。或者将Activity的window窗口调小以便为软键盘腾出空间,或者当Activity的部分window被软件盖住时,移动Activity的内容以便用户能够看到当前的焦点。

你至少要从下列属性值选取一项对其设置,要么是”state...“,要么是”adjust...“。你可以设置多个值。设置不同的属性值,要用|进行分开。比如:

下面是对属性的值的描述。

描述
”stateUnSpecified“ 不指定软件的状态(显示或隐藏)。系统会根据主题中的设置来选择相应的状态。 该属性软键盘的默认设置。
”stateUnchnaged“ 总是保持上次软键盘的状态。当Activity进入到最前端时,不论是它上次它是显示或隐藏,保持不变。
”stateHidden“ 当用户进入目标Activity时,软键盘保持隐藏状态。这里的Activity是用户是向前进入Activity,而不是由于退出其它Activity退回到目标Activity。
”stateVisible“ 只有条件合适(当用户前进进入到Activity的主window),就会显示键盘
”stateAlawaysVisible“ 当用户选择进入目标Activity时,软键盘被设置为可见的。这里的Activity是用户向前进入的Activity,而不是由于退出其它Activity而回到目标Activity
"adjustUnspecified" 不指定是否去调整Activity的界面。或者调整Activity窗口的大小以便为软键盘腾出空间或者移动窗口的内容来屏幕上当前的焦点可见。系统会自动选择其中一种模式,这依赖于窗口是包含可以滑动其内容的view.如有这样的视图,窗口的大小就会被调整。在这样的假定的情况下,很小的滑动就可以使用窗口的内容可见。 该属性是主windowr默认设置。
”adjustResize“ Activity的窗口总是被调整其大小以便为软键盘腾出空间。
”adjustPan“ Activity的主窗口不会被调整其大小以便为软键盘腾出空间。相反,窗口的内容会被自动移动以便当前的焦点不会被软键盘遮住,用户可以总是看到他输入的内容。这个值一般用于用户很少想调整窗口的大小的情况下,因为用户可能需要关闭软键盘来与窗口的其它部分进行交互。

从上面系统的描述了解了系统在处理两个交互时都显示Activity和软键盘都是看作window窗口来处理的。
很多的时候,我们都希望能够监听到软件键盘的显示与关闭状态,比如下图的情况,

你有一个登录界面是这样设计的

\

你希望登录时它是这样的,

\

然后你去尝试给activity的windowSoftInputMode属性加上值,当你加上 adjustResize时,它是这样的
\

你不甘心,你将adjustResize修改成adjustPan,结果是这样的

\


没有办法,只有靠我们自己来监听键盘的显示或隐藏来动态改变布局。现在的问题是怎么监听到键盘的动态改变呢,系统并没有提供相应的方法,我们可以通过两种方法来实现。
1.在adjustResize属性下,activity的窗口大小会发生改变,而窗口中的layout的大小也必然后会发生改变。当view大小发生改变时,必然会引起onSizeChanged(int, int, int, int)的回调。所以可能自定义一个Layout,来监测onSizeChanged()函数的回调,然后在其中的作相应的处理。这个方法也是网上传的最多的方法。
2.借助ViewTreeOberserver类。ViewTreeOberserver可以用来注册一个监听器,它能监听view树的全局变化。这些变化包括但不限于,整个View的布局,绘制传递的源头,触摸模式的变化。

第一种方法的实现:
自定义一个Layout,以RelativeLayout为例,

可以在onSizeChanged(int w, int h,int oldw,int oldh) 方法里监听界面大小的变化,然后在该方法里定义回调函数,当监听到键盘被调出时,将键盘向上推一段距离,这样将登录键显示出来。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.example.keyboardlistener;
 
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.RelativeLayout;
 
public class KeyboardLayout extends RelativeLayout {
 
     private onSizeChangedListener mChangedListener;
     private static final String TAG = "KeyboardLayoutTAG" ;
     private boolean mShowKeyboard = false ;
     
     public KeyboardLayout(Context context, AttributeSet attrs, int defStyle) {
         super (context, attrs, defStyle);
         // TODO Auto-generated constructor stub
     }
 
     public KeyboardLayout(Context context, AttributeSet attrs) {
         super (context, attrs);
         // TODO Auto-generated constructor stub
     }
 
     public KeyboardLayout(Context context) {
         super (context);
         // TODO Auto-generated constructor stub
     }
     
     @Override
     protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec) {
         // TODO Auto-generated method stub
         super .onMeasure(widthMeasureSpec, heightMeasureSpec);
         Log.d(TAG, "onMeasure-----------" );
     }
 
     @Override
     protected void onLayout( boolean changed, int l, int t, int r, int b) {
         // TODO Auto-generated method stub
         super .onLayout(changed, l, t, r, b);
         Log.d(TAG, "onLayout-------------------" );
     }
     
     @Override
     protected void onSizeChanged( int w, int h, int oldw, int oldh) {
         // TODO Auto-generated method stub
         super .onSizeChanged(w, h, oldw, oldh);
         Log.d(TAG, "--------------------------------------------------------------" );
         Log.d(TAG, "w----" + w + "\n" + "h-----" + h + "\n" + "oldW-----" + oldw + "\noldh----" + oldh);
         if ( null != mChangedListener && 0 != oldw && 0 != oldh) {
             if (h < oldh) {
                 mShowKeyboard = true ;
             } else {
                 mShowKeyboard = false ;
             }
             mChangedListener.onChanged(mShowKeyboard);
             Log.d(TAG, "mShowKeyboard-----      " + mShowKeyboard);
         }
     }
     
     public void setOnSizeChangedListener(onSizeChangedListener listener) {
         mChangedListener = listener;
     }
     
     interface onSizeChangedListener{
         
         void onChanged( boolean showKeyboard);
     }
     
}

在主Activity里创建一个Handler,当监听到布局发生变化时,通过Handler更新UI。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package com.example.keyboardlistener;
 
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.widget.Button;
 
import com.example.keyboardlistener.KeyboardLayout.onSizeChangedListener;
 
public class MainActivity extends Activity {
     
     private static final String TAG = "KeyboardLayoutTAG" ;
     private KeyboardLayout mRoot;
     private Button mLogin;
     private int mLoginBottom;   
     private static final int KEYBOARD_SHOW = 0X10 ;
     private static final int KEYBOARD_HIDE = 0X20 ;
     private boolean mGetBottom = true ;
     
     private Handler mHandler = new Handler() {
 
         @Override
         public void handleMessage(Message msg) {
             // TODO Auto-generated method stub
             super .handleMessage(msg);
             switch (msg.what) {
             case KEYBOARD_HIDE:
                 mRoot.setPadding( 0 , 0 , 0 , 0 );
                 break ;
 
             case KEYBOARD_SHOW:
                 int mRootBottom = mRoot.getBottom();
                 Log.d(TAG, "the mLoginBottom is  " + mLoginBottom);
                 mRoot.setPadding( 0 , mRootBottom - mLoginBottom, 0 , 0 );
                 break ;
                 
             default :
                 break ;
             }
         }
         
     };
     
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super .onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
         
         getActionBar().hide();
         mRoot = (KeyboardLayout) findViewById(R.id.root_view);
         mLogin = (Button) findViewById(R.id.login);
         mRoot.setOnSizeChangedListener( new onSizeChangedListener() {
             
             @Override
             public void onChanged( boolean showKeyboard) {
                 // TODO Auto-generated method stub
                 if (showKeyboard) {
                     mHandler.sendMessage(mHandler.obtainMessage(KEYBOARD_SHOW));
                     Log.d(TAG, "show keyboard" );
                 } else {
                     mHandler.sendMessage(mHandler.obtainMessage(KEYBOARD_HIDE));
                 }
             }
         });
         
         mRoot.getViewTreeObserver().addOnPreDrawListener( new OnPreDrawListener() {
             
             @Override
             public boolean onPreDraw() {
                 // TODO Auto-generated method stub
                 if (mGetBottom) {
                     mLoginBottom = mLogin.getBottom(); //获取登录按钮的位置信息。
                 }
                 mGetBottom = false ;
                 return true ;
             }
         });
         
     }
 
//    @Override
//    public boolean onCreateOptionsMenu(Menu menu) {
//        // Inflate the menu; this adds items to the action bar if it is present.
//        getMenuInflater().inflate(R.menu.main, menu);
//        return true;
//    }
     
     
 
}

第二种方法的实现:

借助ViewTreeObserver类对你想监听的view添加OnGlobalLayoutListener监听器,然后在onGlobalLayout()方法里窗口的变化情况来判断键盘是否被调出来了。下面是ViewTreeObserver监听的部分的代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
mRoot.getViewTreeObserver().addOnGlobalLayoutListener( new OnGlobalLayoutListener() {
             
             @Override
             public void onGlobalLayout() {
                 int offset = mRoot.getRootView().getHeight() - mRoot.getHeight();
                 //根据视图的偏移值来判断键盘是否显示
                 if (offset > 300 ) {
                     mHandler.sendMessage(mHandler.obtainMessage(KEYBOARD_SHOW));
                 } else {
                     mHandler.sendMessage(mHandler.obtainMessage(KEYBOARD_HIDE));
                 }
                 
             }
         });

其中Handler的具体实现同上述结构中的Handler一样。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值