首页 > 代码库 > LinearLayout详解四:彻底解决软键盘遮挡输入框的问题

LinearLayout详解四:彻底解决软键盘遮挡输入框的问题

之前把预备知识都介绍完了,话说学以致用,接下来我们要通过重载LinearLayout类来解决软键盘覆盖的问题。

首先阐述一下这个问题,如下图所示:


然后看挡住输入框的情况



然后我们给出xml的源代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="6"
        android:background="#ff0000"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/login_title" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="20dp"
        android:layout_weight="3"
        android:orientation="vertical" >
    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_alignParentBottom="true"
        android:layout_gravity="center_vertical"
        android:hint="用户名"
        android:ems="10" >

        <requestFocus />
    </EditText>
    
    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_alignParentBottom="true"
        android:layout_gravity="center_vertical"
        android:hint="用户名"
        android:ems="10" >

        <requestFocus />
    </EditText>
    </LinearLayout>

</LinearLayout>


虽然我知道,看代码是多么让人蛋。疼的事情,但请大家还是忍住对我的菊,花猛踹一脚的愤怒看一下我辛辛苦苦垒的代码吧。

这个层次其实一点都不复杂就是外面一层linearlayout,他内部包含两个linearlayout,这是再正常不过的登录界面了:上面是logo,下面是用户名,密码输入框。困扰大家的问题就是弹出来的软键盘会遮挡输入框。这个比iOS的烦人多了,iOS解决这类问题还是比较简单的,直接代码搞定就可以了。


现在讲一下通常的解决方案就是:监听键盘弹出,然后隐藏上面的logo,然后自然而然的下面的也就顶上去了。怎么实现呢,我们只要写一个类继承自LinearLayout即可

我们写一个类:LinearLayoutView.java 源代码如下:

package com.example.overidelinearlayout;


import android.content.Context;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.LinearLayout;

public class LinearLayoutView extends LinearLayout{

	public static final int KEYBORAD_HIDE = 0;
	public static final int KEYBORAD_SHOW = 1;
	private static final int SOFTKEYPAD_MIN_HEIGHT = 50;
	
	private Handler uiHandler = new Handler();
	
	public LinearLayoutView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	public LinearLayoutView(Context context, AttributeSet attrs) {
		super(context, attrs);
		
		// TODO Auto-generated constructor stub
	}

	@Override
	protected void onSizeChanged(int w,final int h, int oldw,final int oldh) {
		// TODO Auto-generated method stub
		super.onSizeChanged(w, h, oldw, oldh);
		uiHandler.post(new Runnable() {
			@Override
			public void run() {
				if (oldh - h > SOFTKEYPAD_MIN_HEIGHT){		
					Log.e("lp", "up");
					System.out.println("弹起");
					keyBordStateListener.stateChange(KEYBORAD_SHOW);
				}
				else {					
					System.out.println("隐藏");
					Log.e("lp", "down");
					if(keyBordStateListener != null){
						keyBordStateListener.stateChange(KEYBORAD_HIDE);
					}
				}
			}
		});
	}
	
	@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);
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}
	
	private KeyBordStateListener  keyBordStateListener;
	
	public void setKeyBordStateListener(KeyBordStateListener keyBordStateListener) {
		this.keyBordStateListener = keyBordStateListener;
	}

	public interface KeyBordStateListener{		
		public void stateChange(int state);
	}
	
}

然后我们把xml最上层的linearlayout改为LinearLayoutView即可,然后给他们加上id,更新后的xml如下:

<com.example.overidelinearlayout.LinearLayoutView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:id="@+id/login_root_layout"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <LinearLayout
        android:id="@+id/login_layout_logo"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="6"
        android:background="#ff0000"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/login_title" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginTop="20dp"
        android:layout_weight="3"
        android:orientation="vertical" >
    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_alignParentBottom="true"
        android:layout_gravity="center_vertical"
        android:hint="用户名"
        android:ems="10" >

        <requestFocus />
    </EditText>
    
    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignLeft="@+id/textView1"
        android:layout_alignParentBottom="true"
        android:layout_gravity="center_vertical"
        android:hint="用户名"
        android:ems="10" >

        <requestFocus />
    </EditText>
    </LinearLayout>

</com.example.overidelinearlayout.LinearLayoutView>

然后我们再写MainActivity里面的代码:

package com.example.overidelinearlayout;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;

import com.example.overidelinearlayout.LinearLayoutView.KeyBordStateListener;

public class MainActivity extends Activity implements KeyBordStateListener {

	private LinearLayoutView resizeLayout;
	private LinearLayout logoLayout;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		resizeLayout = (LinearLayoutView) findViewById(R.id.login_root_layout);
		logoLayout = (LinearLayout) findViewById(R.id.login_layout_logo);
		resizeLayout.setKeyBordStateListener(this);
	}

	@Override
	public void stateChange(int state) {
		// TODO Auto-generated method stub
		switch (state) {
		case LinearLayoutView.KEYBORAD_HIDE:
			logoLayout.setVisibility(View.VISIBLE);
			break;
		case LinearLayoutView.KEYBORAD_SHOW:
			logoLayout.setVisibility(View.GONE);
			break;
		}
	}

}

最后别忘了在manifest中这样写:

<activity
            android:name="com.example.overidelinearlayout.MainActivity"
            android:windowSoftInputMode="adjustResize"  >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

最后看一下效果吧:


搞定收工!

最后附上源代码:源代码在此,请猛戳!(虽然本来不想给的,省得大家都不懂脑筋,但回头想想又不忍心,毕竟本人也经历过到处看教程却苦于没代码的岁月。被项目压着的日子不好过啊!!!看着嗷嗷待哺的诸位着实有点于心不忍)