如何实现监听Android输入法弹出收回,为什么要使用接口

最近在做毕业设计,其中一个小功能就是要实现一个聊天窗口,聊天窗口里面要输入内容,输入法弹出来以后,信息气泡要抬起来,输入法收回去以后还要放下来。

在网上查了一圈,基本认定,是没有输入法弹出收回这个监听器的,只能从基础布局的大小入手,监听基础布局的大小改变,来判断输入法的弹出和收回。

View中已经提供了方法

/**
     * This is called during layout when the size of this view has changed. If
     * you were just added to the view hierarchy, you're called with the old
     * values of 0.
     *
     * @param w Current width of this view.
     * @param h Current height of this view.
     * @param oldw Old width of this view.
     * @param oldh Old height of this view.
     */
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    }
但View和我正在使用的RelativeLayout并不提供setOnSizeChangedListener()方法,因此,我们需要在RelativeLayout中添加一个setOnSizeChangedListener()方法,因此,需要把RelativeLayout重写,目的是重写里面的onSizeChange()方法。
public class ResizableRelativeLayout extends RelativeLayout {
	//构造方法直接调用父类方法,此处已省略
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
    }
}
那么问题来了,我的目的是让Listview里面的内容往上推,但是,我重写的是外面嵌套的布局,我怎么告诉用这个布局的Activity尺寸已经改变,然后让Activity做一些事呢?
想一下JavaScript,方法是可以在方法的参数里传递的,那么在Java里面,有没有方法能把方法传递过来呢?答案是有。
我们需要在重写的ResizableRelativeLayout里面添加一个接口,在这个接口里面有一个方法,这个方法在尺寸改变时调用,那么如果要监听尺寸改变,就要实现这个接口,那么这个接口的方法自然就从实现接口的地方传递进来,这样就算是传递了方法。
再来个大白话版:接口在里面摆着,就是让这个类里的方法们一个方向,让他们去调这个接口里的方法,至于方法具体是什么,无所谓,反正知道要去调这个方法,工作就结束了。
那么,我们把接口添加进去。
public class ResizableRelativeLayout extends RelativeLayout {

    private OnSizeChangeListener onSizeChangeListener;

    public interface OnSizeChangeListener{
        void onSizeChange(int width, int height, int oldWidth, int oldHeight);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        onSizeChangeListener.onSizeChange(w,h,oldw,oldh);//在尺寸改变时,调用接口里面的那个方法,这个方法,是自己实现的,也就实现了方法传递
    }

    public void setOnSizeChangeListener(OnSizeChangeListener onSizeChangeListener){
        this.onSizeChangeListener = onSizeChangeListener;
    }
}
在Activity中,使用
resizableRelativeLayout.setOnSizeChangeListener(new ResizableRelativeLayout.OnSizeChangeListener() {
    @Override
    public void onSizeChange(int width, int height, int oldWidth, int oldHeight) {
    	//需要在尺寸改变时做的事
    }
});
这样,就实现了对尺寸改变的监听。
但问题还没解决,我们要做的是监听输入法弹出收回,所以要在这里做一个判断,当高度减小时,判断结果是输入法弹出,反之输入法收回。
resizableRelativeLayout.setOnSizeChangeListener(new ResizableRelativeLayout.OnSizeChangeListener() {
    @Override
    public void onSizeChange(int width, int height, int oldWidth, int oldHeight) {
        if(oldHeight>height)
            listView.setSelection(listView.getAdapter().getCount()-1);
    }
});
运行后发现,确实可以监听输入法弹出和收回,但是ListView并没有跟着动,大概想一下原因就是,输入法弹出是有延迟的,具体原因还没有想,解决方法是让ListView延迟抬起。
resizableRelativeLayout.setOnSizeChangeListener(new ResizableRelativeLayout.OnSizeChangeListener() {
    @Override
    public void onSizeChange(int width, int height, int oldWidth, int oldHeight) {
        if(oldHeight>height)
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    listView.setSelection(listView.getAdapter().getCount()-1);
                }
            },500);
    }
});
这样,就实现了监听输入法弹出和收回。

我们来总结一下思路:
1.系统没有提供输入法弹出和收回的监听,我们需要自己实现这个监听,实现这个监听的一个方法,就是监听界面的尺寸改变,因为输入法弹出后会改变界面尺寸;
2.系统依然没有提供尺寸改变的监听,但在尺寸改变时有一个回调方法onSizeChanged(),我们需要用这个回调方法自己实现一个监听;
3.实现监听的目的是方法传递,我们需要建立一个接口,在外面实现接口里面的方法,就实现了方法传递。
至此已经实现了监听尺寸改变以及输入法弹出收回
4.在实际环境中,输入法弹出有延迟,需要让需要做的事延迟启动。

然后是另一个问题,为什么使用接口。
上边已经说到,接口是为了传递方法,而传递方法的原理,就是类里面的方法知道接口里有那么一个叫xxx的方法,所以类里的方法就知道怎么调用这个xxx方法,具体的实现,可以放在使用这个类的时候再去实现。


你可能感兴趣的:(android,Java)