使用popWindow设计自适应高度的评论框

在开发过程中遇到这样的一个需求

需求如下

1532790178013.png

这也是在开发过程中遇到的一个需求,一开始以为这样的需求其实挺简单, 我们可以有很多种方式来实现,比如自定义dialog , 在界面添加一个输入框弄一个键盘自适应改变view的高度,使用Fragment 使用Dialog 样式来实现。

这次开发都没有用到上面的几种,由于也是实际开发过程中遇到的需求,时间比较紧,也就不用一一去尝试了。

自定义PopWindow来实现上述需求

​ 大概的思路

  1. 自定义PopWindow ,

  2. 点击评论输入的位子调出键盘

  3. 使用回掉函数监听键盘的打开以及隐藏

  4. 在键盘打开的时候穿一个键盘高度的参数设置Pop里面View显示的高度

  5. 然后由于中间hint带有键盘,那么中间可以使用RelativeLayout 来实现(具体布局实现就不说明了后面有会将代码贴出来)

主要大概的是这么几步操作。 本以为这样是非常顺利的,很快的就能实现这个功能,没想到后面遇到了很多问题。 后面会将问题一一道来

布局代码--

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

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

        <!--  显示头像 -->
        <android.support.v7.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/x5"
            android:layout_marginEnd="@dimen/x10"
            android:layout_marginStart="@dimen/x10"
            android:layout_marginTop="@dimen/x15"
            android:visibility="gone">

        </android.support.v7.widget.RecyclerView>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/x60"
            android:layout_margin="@dimen/x10"
            android:background="@drawable/shape_input_comment_bg">
            
            <!-- 最多输入100个文字 -->
            <qudaqiu.shichao.wenle.view.editor.RichEditor
                android:id="@+id/et_input"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_margin="@dimen/x10"
                android:background="@null"
                android:gravity="left"
                android:inputType="textMultiLine"
                android:maxLength="100"
                android:textSize="14sp" />

            <!--  制作简单 -->
            <LinearLayout
                android:id="@+id/ll_input_icon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="@dimen/x15"
                android:layout_marginTop="@dimen/x10"
                android:gravity="center">

                <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@mipmap/input_comments" />

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="@dimen/x10"
                    android:text="期待您的神评论"
                    android:textColor="@color/gray_need" />
            </LinearLayout>
        </RelativeLayout>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="@dimen/x33"
            android:layout_marginBottom="@dimen/x10"
            android:layout_marginEnd="@dimen/x10"
            android:layout_marginStart="@dimen/x10">

            <ImageView
                android:id="@+id/iv_add_img"
                android:layout_width="@dimen/x33"
                android:layout_height="@dimen/x33"
                android:src="@mipmap/reply_images" />

            <ImageView
                android:id="@+id/iv_ait_name"
                android:layout_width="@dimen/x33"
                android:layout_height="@dimen/x33"
                android:layout_marginStart="@dimen/x12"
                android:layout_toRightOf="@+id/iv_add_img"
                android:src="@mipmap/reply_add" />

            <TextView
                android:id="@+id/tv_submit"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentBottom="true"
                android:layout_alignParentRight="true"
                android:background="@drawable/shape_reply_submit_bg"
                android:paddingBottom="@dimen/x3"
                android:paddingEnd="@dimen/x15"
                android:paddingStart="@dimen/x15"
                android:paddingTop="@dimen/x3"
                android:text="发送"
                android:textSize="14sp" />

        </RelativeLayout>

    </LinearLayout>
</layout>

其中RichEditor 继承 AppCompatEditText 自定义view,@用户显示变色,顺便带有@用户全部删除的功能, 这个开源库的地址: https://github.com/JustYJQ/RichEditor

图片显示使用:RecyclerView --> GridLayoutManager(5) 一行显示5个布局格子

准备工作完成,布局已经完成,现在开始关键性的代码

如何来实现CommectDialog,我们需要考虑那些问题?

针对这些问题我建议根据实际情况来考虑,先将大致与activity交互的位子整理出来,其中它需要activity传递那些参数,这些是需要弄清楚的,只有弄清楚了这些东西才好设置一些接口。(根据实际情况来定,目前所说的情况只是符合我当前的项目,后面我会弱化项目本身,从一个工具来来讲解)

问题

  • 有点击事件 at用户 图片选择

  • 有提交按钮,携带那些参数到上个界面,评论空内部的数据,选择的图片,at的用户。

  • 图片选择有数量限制(图片选择需要用到activity跳转activity一个比较常用的一个方法:sstartActivityForResult(* , *),不是很了解的可以自行百度)选择好了图片携带过来首先接收页面是当前activity 然后 -- > CommentDialog )

问题很清楚了,我们需要一个接口用于回调处理CommentDialog某些点击事件

接口设置: Listener --- >

interface Listener{
    onClickCheckUser(); // 选择 用户
    onClickCheckPictrue(); // 选择图片
    OnClickSubmit(); // 提交评论 
}

class CommentDialog{
    private List<String> imgs = new ***** ; //选择图片的地址
    /**
    ******
    */

}

处理完上述问题。那么接下来的代码得去实现那些。

  1. 布局已经搭建完成,那么将布局放到Popwindow中去,得让它显示出来这是整个项目中关键的代码之一
        /**
     * show comment popupwindow(弹出评论的popupWindow)
     *
     * @param type        类型  扩展
     * @param height_view 软键盘高度
     */
    @SuppressLint("WrongConstant")
    public void showPopupCommnet(final int pid, final int type, final int height_view) {// pe表示是评论还是举报1.代表评论。2.代表举报

        final View view = LayoutInflater.from(context).inflate(
                R.layout.view_dynamic_comment_input, null); //使用LayoutInflater 加载布局

        inputComment = (RichEditor) view.findViewById(R.id.et_input); //评论框
        ll_input_icon = view.findViewById(R.id.ll_input_icon);  //中间的hint
        
        //   点击事件
        btn_submit = view.findViewById(R.id.tv_submit);
        iv_add_img = view.findViewById(R.id.iv_add_img);
        iv_ait_name = view.findViewById(R.id.iv_ait_name);
        recyclerView = view.findViewById(R.id.recyclerView); // 图片显示Recyclerview

        // btn_submit.setOnClickListener(this);
        iv_add_img.setOnClickListener(this);
        iv_ait_name.setOnClickListener(this);

        // 首先进来设置光标不可见
        inputComment.setCursorVisible(false);
        // 初始化PopWindow 将布局放入 view
        popupWindow = new PopupWindow(view, LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT, true);

        popupWindow.setTouchable(true); // 设置屏幕点击事件

        popupWindow.setTouchInterceptor(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) { // 处理屏幕点击事件
                return false;   // 此处返回false 不然点击屏幕事件会被外部抢夺
            }
        });

        popupWindow.setFocusable(true);
        
        // 设置点击窗口外边窗口消失 下面为绑定代码,点击外边窗口消息主要代码是  setBackgroundDrawable
        popupWindow.setOutsideTouchable(true);
        popupWindow.setBackgroundDrawable(context.getResources().getDrawable(
                R.drawable.popuwindow_white_bg));
        

        // 设置弹出窗体需要软键盘
//        popupWindow.setSoftInputMode(PopupWindow.INPUT_METHOD_NEEDED);
        // 再设置模式,和Activity的一样,覆盖,调整大小。
        popupWindow
                .setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        
        // 显示的位子  height_view -- activit  
        popupWindow.showAtLocation(view, Gravity.BOTTOM, 0, height_view); 

        ColorDrawable cd = new ColorDrawable(0x333333);     // 改变覆盖在界面上面的问题
        popupWindow.setBackgroundDrawable(cd);
        
        
        WindowManager.LayoutParams params = context.getWindow().getAttributes();
        params.alpha = 0.4f;
        context.getWindow().setAttributes(params);
        // 设置popWindow的显示和消失动画
        popupWindow.setAnimationStyle(R.style.mypopwindow_anim_style);

        popupWindow.update();

        // 更新UI-- 开启新的线程更新ui。 这里为什么会有一个handle 后面会讲解其中这和RcycleView 显示图片数据有关系
        Message msg = Message.obtain();
        myHandler.sendMessage(msg);

        
        popupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {
            // 在dismiss中恢复透明度
            public void onDismiss() {
                WindowManager.LayoutParams params = context.getWindow().getAttributes();
                params.alpha = 1f;
                context.getWindow().setAttributes(params);
            }
        });

        btn_submit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String comment = inputComment.getText().toString().trim();
                if (comment.length() <= 0) {
                    if (type == 1) {
                        Toast.makeText(context, "评论内容不能为空",
                                Toast.LENGTH_SHORT).show();
                    }
                    return;
                }
                boolean b = checkBlackList(comment);
                if (!b) {
                    // 包含非法关键字
                    Utils.toastMessage(context, "您输入咨询订单含有敏感词汇");
                    return;
                }

                // 提交评论
                if (onSubmitCommentListener != null) {
                    onSubmitCommentListener.onSubmitComment(comment, selectPhotos, aitTattooistData);
                }

            }
        });

        inputComment.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void afterTextChanged(Editable editable) {
                // 设置光标显示
                if (editable.toString().length() > 0) {
                    ll_input_icon.setVisibility(View.GONE);
                    inputComment.setCursorVisible(true);
                } else {
                    ll_input_icon.setVisibility(View.VISIBLE);
                    inputComment.setCursorVisible(false);

                }
            }
        });

        // 删除at数据。。。 开源第三方内部编写好的
        inputComment.setOnDeleteAtListener(this);
    }

这样整个popwindow布局已经搭建好了, 其中很多地方本该用回调的位子我没用,此处考虑这个只用于目前开发的项目,其中还有写界面是需要复用到这个界面也就没有在使用上面将的那几个接口问题,直接是在内部处理了一些点击事件,然后在另外需要评论的界面调用这个界面,点击事件就不用在去重新写了。
  1. 这个问题主要是弹出键盘的问题。
/**
 * 弹出键盘
 * 目前有一个bug。。 小米手机不能弹出 魅族可以弹出
 */
 public void popupInputMethodWindow() {
   InputMethodManager imm = (InputMethodManager)         context.getSystemService(Service.INPUT_METHOD_SERVICE);
   imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
 }

这个方法是在键盘没有弹出的时候点击,键盘会弹出,键盘弹出的时候点击会隐藏

 public class SoftKeyBoardListener {
    private View rootView;//activity的根视图
    int rootViewVisibleHeight;//纪录根视图的显示高度
    private OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener;

    public SoftKeyBoardListener(Activity activity) {
        //获取activity的根视图
        rootView = activity.getWindow().getDecorView();

        //监听视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                //获取当前根视图在屏幕上显示的大小
                Rect r = new Rect();
                rootView.getWindowVisibleDisplayFrame(r);
                int visibleHeight = r.height();
                if (rootViewVisibleHeight == 0) {
                    rootViewVisibleHeight = visibleHeight;
                    return;
                }

                //根视图显示高度没有变化,可以看作软键盘显示/隐藏状态没有改变
                if (rootViewVisibleHeight == visibleHeight) {
                    return;
                }

                //根视图显示高度变小超过200,可以看作软键盘显示了
                if (rootViewVisibleHeight - visibleHeight > 200) {
                    if (onSoftKeyBoardChangeListener != null) {
                        onSoftKeyBoardChangeListener.keyBoardShow(rootViewVisibleHeight - visibleHeight);
                    }
                    rootViewVisibleHeight = visibleHeight;
                    return;
                }

                //根视图显示高度变大超过200,可以看作软键盘隐藏了
                if (visibleHeight - rootViewVisibleHeight > 200) {
                    if (onSoftKeyBoardChangeListener != null) {
                        onSoftKeyBoardChangeListener.keyBoardHide(visibleHeight - rootViewVisibleHeight);
                    }
                    rootViewVisibleHeight = visibleHeight;
                    return;
                }
            }
        });
    }

    private void setOnSoftKeyBoardChangeListener(OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {
        this.onSoftKeyBoardChangeListener = onSoftKeyBoardChangeListener;
    }

    public interface OnSoftKeyBoardChangeListener {
        void keyBoardShow(int height);

        void keyBoardHide(int height);
    }

    public static void setListener(Activity activity, OnSoftKeyBoardChangeListener onSoftKeyBoardChangeListener) {
        SoftKeyBoardListener softKeyBoardListener = new SoftKeyBoardListener(activity);
        softKeyBoardListener.setOnSoftKeyBoardChangeListener(onSoftKeyBoardChangeListener);
    }
}

上述类是用来监听键盘弹出或者隐藏

在activity里面调用。 在下面使用的过程中会看到我有用到一些boolean类型的参数来控制,这是由于在开发过程中遇到一些问题,AActivity 跳转 BActivity 的时候在回来的时候键盘是被隐藏了。

 /**
         *  软键盘弹出来监听
         */
        SoftKeyBoardListener.setListener(this, object : SoftKeyBoardListener.OnSoftKeyBoardChangeListener {
            override fun keyBoardShow(height: Int) {
                if (is_show_keybord) {
                    if (dialog.isIsShowDialog) {
                        // 显示键盘
                        view_height = height
                        dialog.showPopupCommnet(1, 1, height)
                        //  判断软键盘是否弹出
                    }
                    dialog.isIsShowDialog = true
                }
            }

            override fun keyBoardHide(height: Int) {
                is_show_keybord = true
                // 隐藏键盘
                if (dialog.popupWindow != null) {
                    if (dialog.isIsShowDialog) { // 这一步操作还是显示的
                        dialog.setDismiss()
                    }
                }
            }
        })

处理开发过程中遇到的问题

第一个问题:AActivity 跳转 BActivity的时候键盘隐藏,某些手机不知道原因键盘不能使用上述的方法popupInputMethodWindow调用

​ 关于这个问题,测试手机不多,目前发现在红米手机上是有这个问题的。就是A跳转B之后然后finish回来,A界面的软键盘是被关闭了的,然后使用上述popupInputMethodWindow方法准备调用键盘的时候是没有效果,开始怀疑是A界面的焦点没有获取得到,后面打印日志发现不是这个问题,焦点获取得到键盘还是没有调用起来。

​ 然后针对这个问题,我就想,能不能让popwindow不隐藏,也就出现了上述一个参数is_show_keybord ,当跳转其他键盘的时候设置这个参数为false,然后在回来的时候也就不会隐藏popwindow了,或者不显示dialog。一面多次显示dialog重复出现。

上述处理的是显示问题,另外还有一个问题,也是最根本的问题,键盘显示问题,由于跳转键盘被隐藏了,那么我们需要重新调用起来键盘 ,否者键盘是不可见的

 // kotlin 写法
 KeybordSUtils.openKeybord(dialog.inputComment, this@WenFastDetailActivity) 

/**
     * 打开软键盘
     *
     * @param mEditText
     * @param mContext
     */
    public static void openKeybord(EditText mEditText, Context mContext) {
        InputMethodManager imm = (InputMethodManager) mContext
                .getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.showSoftInput(mEditText, InputMethodManager.RESULT_SHOWN);
        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,
                InputMethodManager.HIDE_IMPLICIT_ONLY);
    }

这样上面的问题就解决了。

问题二,RecyclerView的显示问题

在写这些之前是没有想到过会有这么多问题,因为Recycleview做一个显示这样还不简单吗?事实上在这块是有一个问题而且和上述有点关联,就是当recyclerview上面显示数据的时候,会导致软键盘隐藏。具体是什么原因目前还不太清楚,这个问题也是出现在个别手机上。

处理方法:


       // 更新UI-- 开启新的线程更新ui。
       Message msg = Message.obtain();
       myHandler.sendMessage(msg);
/**
    * 实现监听
    */
   private void notifyChange() {
       if (recyclerView == null) {
           LogUtils_java.e("recyclerView 不能为空");
           return;
       }
       if (selectPhotos.size() > 0) {
           recyclerView.setVisibility(View.VISIBLE);
           photoAdapter = new CommentImgAdapter(R.layout.item_comment_img_ad, selectPhotos);
           recyclerView.setLayoutManager(new GridLayoutManager(context, 5));
           recyclerView.setAdapter(photoAdapter);
       } else {
           recyclerView.setVisibility(View.GONE);
       }

       if (photoAdapter != null) {
           photoAdapter.setOnItemChildClickListener(this);
       }
   }

 // 使用handler。。 刷新数据 处理由于recyclerview在主线程刷新导致软键盘隐藏问题
   @SuppressLint("HandlerLeak")
   private Handler myHandler = new Handler() {
       public void handleMessage(Message msg) {
           notifyChange();
           super.handleMessage(msg);
       }
   };


处理完上述问题,关于软键盘的问题也就处理完了。


余下的是一些逻辑操作了。主要代码就这些。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,471评论 25 707
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,158评论 0 17
  • 我们的高中语文老师,也是教导处主任,雅痞雅痞的,上课的时候那一手好看的板书真是迷倒了不少同学,以至于整个高中,我们...
    王薄年阅读 263评论 0 0
  • “我爱情就是发自我的内心,我的身体只服从内心召唤,在多情的,有才的,文质彬彬的他面前,我心灵战栗,身体潮湿,我只...
    eileen宝贝阅读 762评论 28 14
  • 香椿树 文/金萌 前些天,爸爸从奶奶家给我带了一棵小小的香椿树,我和妈妈把它栽到小区的一块空地上。我每天细心地照顾...
    调皮的小精灵阅读 530评论 0 1