关于recycleview的快速添加弹窗不关闭,列表数据实时展示问题

需求来源

目前做的是一个采集的App,配合金种子云平台的安卓采集端,有个界面是需要实现快速采集,每次采集完成后采集弹框不消失,还要动态去更新背后的recycleview,然而弹框 + 软键盘的展示使得Recycleview的可见区域很小。

初步实现

界面展示:

动态效果:

具体实现对应xml代码如下,不多做解释:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/root_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/tabbgcolor2"
    android:orientation="vertical">

    <com.nercita.commoncustomview.SearchTopBar
        android:id="@+id/searchTopbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:isShowSearchEditText="true"
        app:searchText="请输入要查找的小区号"
        app:searchisShowLeft="true"
        app:searchisShowRight="true"
        app:searchleftSrc="@drawable/icon_white_back"
        app:searchleftTopText="返回"
        app:searchrightSrc="@drawable/icon_saoma"
        app:searchrightTopText="扫码" />

    <LinearLayout
        android:id="@+id/top_liner"
        android:layout_width="match_parent"
        android:layout_height="48dp"
        android:orientation="horizontal"
        android:paddingBottom="5dp"
        android:paddingLeft="20dp"
        android:paddingRight="20dp"
        android:paddingTop="5dp">

        <TextView
            android:id="@+id/tv_name"
            android:layout_width="0dp"
            android:layout_height="35dp"
            android:layout_marginRight="40dp"
            android:layout_weight="2"
            android:background="@drawable/layout_name_bgcolor"
            android:drawableRight="@drawable/pulldown"
            android:gravity="center|left"
            android:padding="5dp"
            android:textColor="@color/txt_color"
            android:textSize="18sp" />

        <Button
            android:id="@+id/bt_insert"
            android:layout_width="0dp"
            android:layout_height="27dp"
            android:layout_weight="1"
            android:background="@drawable/btn_shape_name"
            android:drawableLeft="@drawable/edit"
            android:gravity="center"
            android:paddingBottom="1dp"
            android:paddingLeft="5dp"
            android:paddingRight="5dp"
            android:paddingTop="1dp"
            android:text="插入"
            android:textColor="@color/white"
            android:textSize="16sp" />

        <Button
            android:id="@+id/bt_delete"
            android:layout_width="0dp"
            android:layout_height="27dp"
            android:layout_marginLeft="5dp"
            android:layout_weight="1"
            android:background="@drawable/btn_shape_name"
            android:drawableLeft="@drawable/deletewhite"
            android:gravity="center"
            android:paddingBottom="1dp"
            android:paddingLeft="5dp"
            android:paddingRight="5dp"
            android:paddingTop="1dp"
            android:text="删除"
            android:textColor="@color/white"
            android:textSize="16sp" />
    </LinearLayout>



    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:orientation="vertical">

        <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="45dp"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/tv_sortNum"
                    android:layout_width="@dimen/distance_100"
                    android:layout_height="match_parent"
                    android:background="@drawable/shape_plan_hearder"
                    android:gravity="center"
                    android:text="序号"
                    android:textColor="@color/text_color"
                    android:textSize="18sp"
                    android:textStyle="bold" />

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">

                    <TextView
                        android:id="@+id/tv_plotCode"
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_weight="2"
                        android:background="@drawable/shape_plan_hearder"
                        android:gravity="center"
                        android:text="小区号"
                        android:textColor="@color/text_color"
                        android:textSize="18sp"
                        android:textStyle="bold" />

                    <TextView
                        android:id="@+id/tv_totalRows"
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_weight="1"
                        android:background="@drawable/shape_plan_hearder"
                        android:gravity="center"
                        android:text="行数"
                        android:textColor="@color/text_color"
                        android:textSize="18sp"
                        android:textStyle="bold" />

                    <TextView
                        android:id="@+id/tv_sortOrder"
                        android:layout_width="0dp"
                        android:layout_height="match_parent"
                        android:layout_weight="1"
                        android:background="@drawable/shape_plan_hearder"
                        android:gravity="center"
                        android:text="方向"
                        android:textColor="@color/text_color"
                        android:textSize="18sp"
                        android:textStyle="bold" />
                </LinearLayout>
            </LinearLayout>
        </LinearLayout>

        <android.support.v7.widget.RecyclerView
            android:id="@+id/rv_compile"
            android:layout_width="match_parent"
            android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
    </LinearLayout>



    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:layout_marginBottom="3dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:background="@drawable/fragment_bottom_bg"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@color/white"
            android:gravity="center"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/tv_last"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:drawableLeft="@drawable/icon_left"
                android:text="上一列" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@color/white"
            android:gravity="center"
            android:orientation="horizontal">

            <ImageView
                android:id="@+id/iv_sub"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/subblack"
                android:visibility="visible" />

            <TextView
                android:id="@+id/tv_current"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="1" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="/" />

            <TextView
                android:id="@+id/tv_total"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="1" />

            <ImageView
                android:id="@+id/iv_add"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@drawable/addblack"
                android:visibility="visible" />
        </LinearLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@color/white"
            android:gravity="center"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/tv_next"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:drawableRight="@drawable/icon_right"
                android:text="下一列" />
        </LinearLayout>
    </LinearLayout>

</LinearLayout>

有弹窗弹出,弹窗用DialogFragment,弹窗弹出/收起对应top_liner的隐藏/显示,这样做的目的是为recycleview腾出点空间,不然recycleview更矮的可怜。

可以看出recycleview的可见区域变小了,被软键盘+弹窗给遮挡了,恰巧我们这里需求是:每次保存没必要关闭弹窗。所以新增的数据在recycleview的可见区域里也看不到,这样的话用户就不知道到底有没有添加进去,导致用户体验不好

优化思路

1.弹窗弹出/收起对应top_liner的隐藏/显示

2.软键盘弹出时(),让recycleview高度缩小,软键盘收起时,恢复原样

3.每次保存或修改数据后,让弹窗背后的recycleview滑动到当前修改行,让用户可以看到

优化方案实现

1.添加四个方法:

 /**
     * @param row 
     * 滑动到指定行
     */
    public void scrollTo(int row) {
        row--;
        if (row < 0)
            row = 0;
        rvCompile.scrollToPosition(row);
    }

    /**
     * 设置缩小高度
     */
    public void setShortHeight() {
        int height = mContext.getResources().getDimensionPixelOffset(R.dimen.distance_40);
        LinearLayout.LayoutParams linearParams = (LinearLayout.LayoutParams) rvCompile.getLayoutParams();
        linearParams.height = height * 3;
        rvCompile.setLayoutParams(linearParams);

    }

    /**
     * 保存原始高度
     */
    public void saveNormalHeight() {
        if (normalHeight == 0) {
            LinearLayout.LayoutParams linearParams = (LinearLayout.LayoutParams) rvCompile.getLayoutParams(); 
            normalHeight = linearParams.height;
            Log.d("存储正常高度:" + normalHeight);
        }
    }

    /**
     * 设置正常高度
     */
    public void setNormalHeight() {
        LinearLayout.LayoutParams linearParams = (LinearLayout.LayoutParams) rvCompile.getLayoutParams();
        linearParams.height = normalHeight;
        rvCompile.setLayoutParams(linearParams);
    }

2.在onCreate()里调用saveNormalHeight()保存原始高度,在onResume()中实现软键盘监听,然后控制recycleview高度和定位行,只贴出相代码

 protected void onResume() {
        super.onResume();
       ····
        KeyboardStautusDetectorUtil keyboardStautusDetectorUtil = new KeyboardStautusDetectorUtil();
        keyboardStautusDetectorUtil.setmVisibilityListener(new KeyboardStautusDetectorUtil.KeyboardVisibilityListener() {
            @Override
            public void onVisibilityChanged(boolean keyboardVisible) {
                if (keyboardVisible && dialogIsDiss) {
                    setShortHeight();
                    if (mCurrentRow == 0 && dialogIsDiss) {
                        scrollTo(serial);
                    } else {
                        scrollTo(mCurrentRow);
                    }
                } else {
                    setNormalHeight();
                }
            }
        });
        keyboardStautusDetectorUtil.registerActivity(this);
    ···
    }

关于 if (keyboardVisible && dialogIsDiss) 判断条件加了个dialogIsDiss是因为要排除搜索框中的软键盘弹出

3.添加弹窗的监听事件,显示隐藏top_liner

     @Override
            public void dialogDismiss() {
                topLiner.setVisibility(View.VISIBLE);
                dialogIsDiss = false;
            }


            @Override
            public void dialogShow() {
                dialogIsDiss = true;
                topLiner.setVisibility(View.GONE);
            }

效果展示

遇到的坑:

在监听软键盘弹出隐藏时,刚开始打算用给跟布局添加addOnLayoutChangeListener 方法实现,然而发现不会成功,打断点调试时候发现bottom和oldBottom 不为0的情况下始终是相等的,但是网上却说这个方法确实能监听到。我猜测是我用了DialogFragment原因

  @Override
    public void onLayoutChange(View v, int left, int top, int right,
                               int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        // old是改变前的左上右下坐标点值,没有old的是改变后的左上右下坐标点值
        // 现在认为只要控件将Activity向上推的高度超过了1/3屏幕高,就认为软键盘弹起
        if (oldBottom != 0 && bottom != 0 && (oldBottom - bottom > keyHeight)) {
            // ToastUtil.toast(CompileActivity.this, "监听到软键盘弹起...");
            setShortHeight();
                    if (mCurrentRow == 0 && dialogIsDiss) {
                        scrollTo(serial);
                    } else {
                        scrollTo(mCurrentRow);
                    }

        } else if (oldBottom != 0 && bottom != 0
                && (bottom - oldBottom > keyHeight)) 
            // ToastUtil.toast(CompileActivity.this, "监听到软件盘关闭...");
             setNormalHeight();
        }
    }

后来用了知乎上这种方法

/**
 * 创建时间:2018/8/31
 * 编写人:kanghb
 * 功能描述:
 */
public class KeyboardStautusDetectorUtil {

    private static final int SOFT_KEY_BOARD_MIN_HEIGHT = 400;
    private KeyboardVisibilityListener mVisibilityListener;

    boolean keyboardVisible = false;

    public void registerFragment(Fragment f) {
        registerView(f.getView());
    }

    public void registerActivity(Activity a) {
        registerView(a.getWindow().getDecorView().findViewById(android.R.id.content));
    }

    public KeyboardStautusDetectorUtil registerView(final View v) {
        v.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Rect r = new Rect();
                v.getWindowVisibleDisplayFrame(r);

                int heightDiff = v.getRootView().getHeight() - (r.bottom - r.top);
                if (heightDiff > SOFT_KEY_BOARD_MIN_HEIGHT) { // if more than 100 pixels, its probably a keyboard...
                    if (!keyboardVisible) {
                        keyboardVisible = true;
                        if (mVisibilityListener != null) {
                            mVisibilityListener.onVisibilityChanged(true);
                        }
                    }
                } else {
                    if (keyboardVisible) {
                        keyboardVisible = false;
                        if (mVisibilityListener != null) {
                            mVisibilityListener.onVisibilityChanged(false);
                        }
                    }
                }
            }
        });

        return this;
    }

    public KeyboardStautusDetectorUtil setmVisibilityListener(KeyboardVisibilityListener listener) {
        mVisibilityListener = listener;
        return this;
    }

    public interface KeyboardVisibilityListener {
        void onVisibilityChanged(boolean keyboardVisible);
    }
}

目前没发现什么问题,也解决了我所遇到的问题。

------ 本文结束 ------
坚持原创技术分享,您的支持将鼓励我继续创作!