最近开发总结(关于键盘监听,单例模式,popupWindow)

最近开发需求:
实现类似qq评论弹出框来实现评论功能.

使用popupWindow实现

这个是我的第一反应,使用<code>popupWindow</code>来实现,于是说做就做。但是写着写着就出现了问题,我怎么去监听键盘?于是去向大神明明请教,明明给了我他之前写过的关于监听键盘的demo供我参考,于是就有了这个关于键盘监听的总结

1.1监听键盘(虽然最终没有使用,但是也记录下来作为积累)

对键盘的监听实现是使用<code>ViewTreeObserver</code>的<code>OnGlobalLayoutListener</code>监听方法来实现的具体流程是:
在<code>OnGlobalLayoutListener</code>方法中获取程序显示界面,记录程序显示界面与改变之前的高度差(键盘高度)。实现代码如下:

public class TestLayout extends RelativeLayout {
    private Context mContext;
    private int mOldh = -1;
    private int mNowh = -1;
    protected int mScreenHeight = 0;//程序显示区域底部
    protected boolean mIsSoftKeyboardPop = false;
    public TestLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                //获取程序的显示区域
                ((Activity) mContext).getWindow().getDecorView().getWindowVisibleDisplayFrame(r);
                if (mScreenHeight == 0) {
                    mScreenHeight = r.bottom;
                }
                mNowh = mScreenHeight - r.bottom;
                if (mOldh != -1 && mNowh != mOldh) {
                    if (mNowh > 0) {
                        mIsSoftKeyboardPop = true;
                        //实现键盘弹出监听
                        if (mListenerList != null) {
                            for (OnResizeListener l : mListenerList) {
                                l.OnSoftPop(mNowh);
                            }
                        }
                    } else {
                        mIsSoftKeyboardPop = false;
                        if (mListenerList != null) {
                            for (OnResizeListener l : mListenerList) {
                                l.OnSoftClose();
                            }
                        }
                    }
                }
                mOldh = mNowh;
            }
        });
    }
    public boolean isSoftKeyboardPop() {
        return mIsSoftKeyboardPop;
    }
    private List<OnResizeListener> mListenerList;
    /**
     * 添加键盘监听
     */
    public void addOnResizeListener(OnResizeListener l) {
        if (mListenerList == null) {
            mListenerList = new ArrayList<>();
        }
        mListenerList.add(l);
    }
    public interface OnResizeListener {
        /**
         * 软键盘弹起
         */ 
       void OnSoftPop(int height);
        /**
         * 软键盘关闭
         */
        void OnSoftClose();
    }
}

使用方法如下:

1.1.1 获取<code>TestLayout</code>实例
1.1.2实现<code>OnResizeListener</code>接口
1.1.3给<code>TestLayout</code>添加<code>OnResizeListener</code>

1.2使用<code>popupWindow</code>实现弹出框

1.2.1实现<code>OnResizeListener</code>接口来监听键盘事件
1.2.2初始化<code>popupWindow</code>
1.2.3写<code>show</code>方法和<code>dismiss</code>方法

具体代码实现:

public class AddCommentPopup implements TestLayout.OnResizeListener {
    private Activity mContext;
    private View mRootView;
     //popupWindow显示在布局
    private PopupWindow mPopupWindow;
    private TestLayout mView;
    public AddCommentPopup(Activity mContext) {
        init(mContext);
    }
    public void init(Activity context){
        mContext = context;
        mRootView = context.getWindow().getDecorView().findViewById(android.R.id.content);
        mView = (TestLayout)  mContext.getLayoutInflater().inflate(R.layout.popu_comment);
        mView.addOnResizeListener(this);
        //初始化popupWindow并设置点击popupWindow区域外popupWindow消失
        mPopupWindow = new PopupWindow(mView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);
        mPopupWindow.setTouchable(true);
        mPopupWindow.setOutsideTouchable(true);
        mPopupWindow.setBackgroundDrawable(new BitmapDrawable(context.getResources(), (Bitmap)null));
    }
    public void showCommentView(int height){
        if (mPopupWindow != null && mPopupWindow.isShowing()) { 
           mPopupWindow.dismiss();
        }
        mCommentContent.setFocusable(true);
        mCommentContent.setFocusableInTouchMode(true);
        mCommentContent.requestFocus();
        CUtils.openKeybord(mCommentContent, mContext);
        mPopupWindow.showAtLocation(mRootView, Gravity.BOTTOM, 0, height);
    }
    public void dismissCommentView(){
        if (mPopupWindow != null && mPopupWindow.isShowing()) {
            mPopupWindow.dismiss();
        }
        mCommentContent.setFocusable(false);
        mCommentContent.setFocusableInTouchMode(false);
        mEmoticonsKeyBoardLayout.setVisibility(View.GONE);
        CUtils.closeKeybord(mCommentContent, mContext);
    }
    @Override
    public void OnSoftPop(int height) {
        //设置当键盘弹出时popupWindow的Y偏移量为键盘高度
        showCommentView(height);
    }
    @Override
    public void OnSoftClose() {
        //当键盘收起是设置popupWindow的Y偏移量为0
        showCommentView(0);
    }
}

写完之后我就高高兴兴的交工了,告诉了大神明明我的这个插件的使用方法之后大神问我:“你这样不就是把这个插件和Activity耦合在一起了,我在不同的地方使用都要复写onActivityResult来实现@功能,这样不好。你可以试试用Fragment来实现,你可以找找那些用Fragment实现弹出框的例子借鉴下”

1.3.使用Fragment来实现

首先说下使用fragment要解决的问题:
  因为在评论功能中会有@功能,当点击@时<code>startActivityForResult</code>跳到另外的界面并拿到返回值显示在当前输入框,如果使用<code>popupWindow</code>来实现这个功能的话就需要在<code>activity</code>中使用<code>onActivityResult</code>中将返回值给<code>popupWindow</code>来实现上述功能,这样就将<code>popupWindow</code>和<code>activity</code>耦合在了一起,所以使用<code>fragment</code>来实现

使用<code>Fragment</code>实现思路:

思路基本与<code>popupWindow</code>实现思路一致,只是需要考虑<code>Fragment</code>显示的布局和<code>show</code>方法和<code>dismiss</code>方法的实现,并复写<code>onActivityResult</code>来实现@功能

2.1.1 <code>show</code>方法:

public void show(Activity activity) {
    mManager = activity.getFragmentManager();
    mTransaction = mManager.beginTransaction();
    //添加到返回栈,这样按下返回键时Fragment不会消失
    mTransaction.add(android.R.id.content, this).addToBackStack(null);
    mTransaction.commit();
}

2.1.2 <code>dismiss</code>方法

public void dismiss() {
    mTransaction = mManager.beginTransaction();
    mManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
    mTransaction.remove(this);
    mTransaction.commit();
}

1.4.单例模式

这个功能到这里基本上算是完成开发了,于是提交代码,告诉大神明明这个弹出框的用法之后以为就算完工了;过了一会明明问我:“你这样写每次都要<code>new</code>一个<code>fragment</code>这样是不是性能上有点不好你优化下”
最终在大神明明的指点下写了这样一个单例模式:

public static AddCommentPopupFragment getInstance(Activity activity) {
    if (sInstance != null) {
        if (sInstance.getActivity() != null && sInstance.getActivity() != activity) {
            sInstance = new AddCommentPopupFragment();
        }
    } else {
        sInstance = new AddCommentPopupFragment();
    }
    return sInstance;
}

到此为止这个功能才算完成开发

推荐阅读更多精彩内容