Android 软键盘弹出自动移动布局

gif图片

2行代码搞定软键盘布局上移


当我们在使用登录界面的时候,软键盘弹出经常会挡住输入框或者登录按钮

一般应用都没有处理,处理的也是很粗糙,所以我写了一个自定义控件解决该问题。

想移动谁就移动谁,so easy !!!!!

/**
 * 类描述: 监听布局Layout变化,进行移动整体布局的自定义控件
 * 创建人: chenyang
 * QQ: 454725164
 * 邮箱: inke88@163.com
 * 创建时间: 2016年06月17日 15时35分
 * 修改人:
 * 修改时间:
 * 修改备注:
 * 版本:
 */
public class KeyboardMoveLayout extends LinearLayout {
    private OnSizeChangedListener mChangedListener;
    private boolean isShowKeyboard = false;

    public KeyboardMoveLayout(Context context) {
        super(context);
    }

    public KeyboardMoveLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public KeyboardMoveLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (null != mChangedListener && 0 != oldw && 0 != oldh) {
            if (h < oldh) {
                isShowKeyboard = true;
            } else {
                isShowKeyboard = false;
            }
            mChangedListener.onChanged(isShowKeyboard);
        }
    }

    public void setOnSizeChangedListener(OnSizeChangedListener listener) {
        mChangedListener = listener;
    }

    public interface OnSizeChangedListener {
        void onChanged(boolean showKeyboard);
    }
}

上面的KeyboardMoveLayout自定义控件主要用于监听软键盘的弹出或者关闭,该自定义控件一般放在一级根布局或者二级根布局。


想移动谁,就把ScrollView包裹在谁身上

<?xml version="1.0" encoding="utf-8"?>
<test.inke.com.test.KeyboardMoveLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/ll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="test.inke.com.test.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#ff0000"></LinearLayout>

    <ScrollView
        android:id="@+id/sc"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true">

        <LinearLayout
            android:id="@+id/ll_move"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <EditText
                android:id="@+id/et1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="40dp"
                android:text="1111" />

            <EditText
                android:id="@+id/et2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:text="2222" />

            <EditText
                android:id="@+id/et3"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:text="3333" />

            <EditText
                android:id="@+id/et4"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:text="4444" />

            <EditText
                android:id="@+id/et5"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:text="5555" />

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:ellipsize="end"
                android:maxLines="2"
                android:text="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" />

            <Button
                android:id="@+id/bt"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="50dp"
                android:text="xxxxxxxx" />
        </LinearLayout>
    </ScrollView>
</test.inke.com.test.KeyboardMoveLayout>

上面是demo的xml布局。


以下是自定义控件的核心工具类

/**
 * 类描述: 自动移动的工具类
 * 创建人: chenyang
 * QQ: 454725164
 * 邮箱: inke88@163.com
 * 创建时间: 2016年06月17日 15时40分
 * 修改人:
 * 修改时间:
 * 修改备注:
 * 版本:
 */
public class AutoMoveUtis {
    public static AutoMoveUtis autoMoveUtis;

    private AutoMoveUtis() {
    }

    public static AutoMoveUtis getInstance() {
        if (autoMoveUtis == null) {
            synchronized (AutoMoveUtis.class) {
                if (autoMoveUtis == null) {
                    autoMoveUtis = new AutoMoveUtis();
                }
            }
        }
        return autoMoveUtis;
    }

    //保存View和移动的距离信息
    public static Map<Integer, MoveLayoutModel> moveMaps = new HashMap<Integer, MoveLayoutModel>();
    private int currentFocus = -1;//当前焦点
    private int oldFocus = -1;//上一次焦点
    private Handler handler = new Handler();
    private boolean isAlreadJudgeMove;//是否已经判断移动,防止多次移动,损耗性能。
    private int delayTime = 100;//延迟执行滚动时间。
    private ScrollView scrollView;

    /**
     * 监听软件盘是否弹出
     *
     * @param rootView
     * @param scrollView
     */
    public void setRootAndScrollView(KeyboardMoveLayout rootView, ScrollView scrollView) {
        this.scrollView = scrollView;
        rootView.setOnSizeChangedListener(new KeyboardMoveLayout.OnSizeChangedListener() {
            @Override
            public void onChanged(boolean showKeyboard) {
                if (showKeyboard && !isAlreadJudgeMove) {
                    moveHeight();
                }
            }
        });
    }

    /**
     * 监听焦点变化
     */
    public View.OnFocusChangeListener onFocusChangeListener = new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View view, boolean isFocused) {
            if (isFocused) {
                currentFocus = view.getId();//获取view的id
                if (AutoMoveUtis.moveMaps.containsKey(view.getId())) {
                    //焦点变化在触发移动
                    if (oldFocus != currentFocus) {
                        isAlreadJudgeMove = true;
                        moveHeight();//移动
                    }
                }
            } else {
                // 此处为失去焦点时的处理内容
            }
        }
    };

    /**
     * 默认移动自身EditText的高度
     *
     * @param view
     */
    public void setAutoMoveEditText(final EditText view) {
        view.post(new Runnable() {
            @Override
            public void run() {
                moveMaps.put(view.getId(), new MoveLayoutModel(view.getId(), view.getHeight()));
            }
        });
        view.setOnFocusChangeListener(onFocusChangeListener);
    }

    /**
     * 移动自身EditText的高度的倍数
     *
     * @param view
     * @param ratioHeight
     */
    public void setAutoMoveEditText(final EditText view, final float ratioHeight) {
        view.post(new Runnable() {
            @Override
            public void run() {
                moveMaps.put(view.getId(), new MoveLayoutModel(view.getId(), (int) (view.getHeight() * ratioHeight)));
            }
        });
        view.setOnFocusChangeListener(onFocusChangeListener);
    }


    /**
     * 移动随意的距离
     *
     * @param view
     * @param moveDistance
     */
    public void setAutoMoveEditText(final EditText view, final int moveDistance) {
        view.post(new Runnable() {
            @Override
            public void run() {
                moveMaps.put(view.getId(), new MoveLayoutModel(view.getId(), moveDistance));
            }
        });
        view.setOnFocusChangeListener(onFocusChangeListener);
    }

    /**
     * 移动到ScrollView的底部
     *
     * @param view
     */
    public void setAutoMoveButtomEditText(final EditText view) {
        view.post(new Runnable() {
            @Override
            public void run() {
                moveMaps.put(view.getId(), new MoveLayoutModel(view.getId(), view.getHeight(), MoveLayoutModel.MOVE_BOTTOM));
            }
        });
        view.setOnFocusChangeListener(onFocusChangeListener);
    }

    /**
     * 移动高度
     */
    private void moveHeight() {
        //初始状态不移动
        if (currentFocus == -1) {
            return;
        }
        //根据设置的模式,进行移动高度或者移动到底部
        if (AutoMoveUtis.moveMaps.containsKey(currentFocus)) {
            MoveLayoutModel moveLayoutModel = AutoMoveUtis.moveMaps.get(currentFocus);
            if (moveLayoutModel.getMoveStatus() == MoveLayoutModel.MOVE_DISTANCE) {
                moveDistance(moveLayoutModel.getMoveDistance());
            } else if (moveLayoutModel.getMoveStatus() == MoveLayoutModel.MOVE_BOTTOM) {
                moveButtom();
            }
        }
        oldFocus = currentFocus;
    }

    // 移动距离
    private void moveDistance(final int moveHeight) {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                isAlreadJudgeMove = false;
                scrollView.scrollTo(0, moveHeight);//滚动到底部
            }
        }, delayTime);
    }


    // 移动到底部
    private void moveButtom() {
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                isAlreadJudgeMove = false;
                scrollView.fullScroll(ScrollView.FOCUS_DOWN);
            }
        }, delayTime);
    }


}


最后需要在Activity中增加

<span style="font-size:32px;color:#ff0000;">android:windowSoftInputMode="adjustResize|stateHidden"</span>

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="test.inke.com.test">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:windowSoftInputMode="adjustResize|stateHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>



测试类:

/**
 * 类描述:
 * 创建人: chenyang
 * QQ: 454725164
 * 邮箱: inke88@163.com
 * 创建时间: 2016年06月17日 15时31分
 * 修改人:
 * 修改时间:
 * 修改备注:
 * 版本:
 */
public class MainActivity extends Activity {
    private EditText et1, et2, et3, et4, et5;
    private ScrollView scrollView;
    private KeyboardMoveLayout rootView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        rootView = (KeyboardMoveLayout) findViewById(R.id.ll);
        scrollView = (ScrollView) findViewById(R.id.sc);
        et1 = (EditText) findViewById(R.id.et1);
        et2 = (EditText) findViewById(R.id.et2);
        et3 = (EditText) findViewById(R.id.et3);
        et4 = (EditText) findViewById(R.id.et4);
        et5 = (EditText) findViewById(R.id.et5);

        // 注入根布局和ScrollView控件
        AutoMoveUtis.getInstance().setRootAndScrollView(rootView, scrollView);
        //焦点移动到哪个EditText,进行布局滑动就注入哪个EditText
        AutoMoveUtis.getInstance().setAutoMoveEditText(et1);//移动EditText自身高度
        AutoMoveUtis.getInstance().setAutoMoveEditText(et2, 2f);//移动EditText自身高度的倍数
        AutoMoveUtis.getInstance().setAutoMoveEditText(et3, 30);//移动随意高度
        AutoMoveUtis.getInstance().setAutoMoveEditText(et4, 150);//移动随意高度
        AutoMoveUtis.getInstance().setAutoMoveButtomEditText(et5);//移动到底部
    }
}





评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值