最近开发需求:
实现类似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;
}
到此为止这个功能才算完成开发
网友评论