Android仿学习强国填空题考试界面

起因:最近工作中遇到一个需求,使用手机进行填空题考试。
分析:因为涉及到判分,需要答案与文字一一对应,刚开始在网上找一些方案在TextView修改文字样式然后处理事件,感觉样式不是太好控制操作繁琐,然后又注意到学习强国的填空题真的很符合需求,所以就拿来模仿了。1
截图如下:左边我,右边学习强国

23392659-0dcefb6eec54876c.png
23392659-cf552618df604282.png
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="27dp"
    android:layout_height="27dp"
    android:layout_marginLeft="1.5dp"
    android:layout_marginTop="2dp"
    android:layout_marginRight="1.5dp"
    android:orientation="vertical">
    <TextView
        android:id="@+id/tv_text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:textColor="#D9000000"
        android:textSize="16sp"
        android:textStyle="bold"
        android:visibility="gone" />
    <EditText
        android:id="@+id/et_text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/bg_edit_selecter"
        android:cursorVisible="false"
        android:gravity="center"
        android:maxLength="1"
        android:textColor="#FF16AFF3"
        android:visibility="gone" />
</LinearLayout>

效果就是这个样子的。
总体思路:RecyclerView 实现数据的装载,使用TextView和Edittext展示内容与填空处,监听焦点,软件盘退格,并设置焦点,根据屏幕宽度设置一行展示的文字个数。
布局文件:布局文件就不多说了,根据自己需求写,但是要同时包含TextView、EditText

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="27dp"
    android:layout_height="27dp"
    android:layout_marginLeft="1.5dp"
    android:layout_marginTop="2dp"
    android:layout_marginRight="1.5dp"
    android:orientation="vertical">
    <TextView
        android:id="@+id/tv_text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:textColor="#D9000000"
        android:textSize="16sp"
        android:textStyle="bold"
        android:visibility="gone" />
    <EditText
        android:id="@+id/et_text"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/bg_edit_selecter"
        android:cursorVisible="false"
        android:gravity="center"
        android:maxLength="1"
        android:textColor="#FF16AFF3"
        android:visibility="gone" />
</LinearLayout>

计算一行展示的文字个数
这块注释写的很清楚了,需要去除内外边距计算 ,其实最后得出的numInLine还可以进行减一操作,为了安全起见,但是也可以不用(int类型除法本来就会丢失精度的)。

//获取屏幕宽度
int screenWidth = getScreenWidth();
//去除padding宽度
int contentWidth = screenWidth - DensityUtils.dp2px(context, Constant.EXAM_PADDING_DP);
//计算出一行字数
int numInLine = contentWidth / DensityUtils.dp2px(context, Constant.EXAM_LETTER_DP);
//设置一行个数
rv_list.setLayoutManager(new GridLayoutManager(context, numInLine));
/**
* 获取屏幕宽度
*/
public int getScreenWidth() {
    DisplayMetrics dm2 = getResources().getDisplayMetrics();
    return dm2.widthPixels;
}

数据源
数据源很简单,每个对象代表一个字,标明是否是填空处

public class BlankTextBean {
    /**
    * 文字
    */
    private String text;
    /**
    * 是否是填空
    */
    private boolean blank;
    public String getText() {
        return text;
    }
    public void setText(String text) {
        this.text = text;
    }
    public boolean isBlank() {
        return blank;
    }
    public void setBlank(boolean blank) {
        this.blank = blank;
    }
}

适配器(用心去感受。。。)
这块主要需求为:
1.无论点击哪个填空处,焦点总是在第一个没有字的格子上。

  1. 点击退格键,如果当前框有字则删除,否则像钱移动一个格子。
    3.填空时,如果填了字,并且后面还有格子焦点自动向后移动一个格子。
    PS:在适当时机调用clearList();注意保存并设置临时填空数据;
class TextAdapter extends BaseQuickAdapter<BlankTextBean, BaseViewHolder> {
        private List<EditText> editTextList = new ArrayList<>();
        private boolean isDelete = false;
        public TextAdapter(@Nullable List<BlankTextBean> data) {
            super(R.layout.item_blank_text, data);
        }
        public void clearList() {
            editTextList.clear();
        }
        /**
        * 获取首个焦点位置
        *
        * @return
        */
        private int getFirstFocusPosition() {
            for (int i = 0; i < editTextList.size(); i++) {
                if (!editTextList.get(i).getText().toString().isEmpty()) {
                    if (i == (editTextList.size() - 1)) {
                        return i;
                    }
                } else {
                    return i;
                }
            }
            return 0;
        }
        /**
        * 获取点击的edittext在集合的位置
        *
        * @param editText
        * @return
        */
        private int getEdittextPosition(EditText editText) {
            for (int i = 0; i < editTextList.size(); i++) {
                if (editText.hashCode() == editTextList.get(i).hashCode()) {
                    return i;
                }
            }
            return 0;
        }
        @Override
        protected void convert(BaseViewHolder helper, BlankTextBean item) {
            TextView tv_text = helper.getView(R.id.tv_text);
            EditText et_text = helper.getView(R.id.et_text);
            tv_text.setText(item.getText());
            if (item.isBlank()) {
                editTextList.add(et_text);
                //设置答案文字
                if (ExamBlankView.this.questionBean != null && ExamBlankView.this.questionBean.getUserAnswer() != null) {
                    if (editTextList.size() <= ExamBlankView.this.questionBean.getUserAnswer().length()) {
                        editTextList.get(editTextList.size() - 1).setText(String.valueOf(ExamBlankView.this.questionBean.getUserAnswer().charAt(editTextList.size() - 1)));
                    }
                }
                tv_text.setVisibility(View.GONE);
                et_text.setVisibility(View.VISIBLE);
            } else {
                tv_text.setVisibility(View.VISIBLE);
                et_text.setVisibility(View.GONE);
            }
            /**
            * 设置获取焦点事件,使得焦点在第一个没字的edittext上,如果都有字停留在最后一个格子处
            */
            et_text.setOnFocusChangeListener((v, hasFocus) -> {
                if (hasFocus && !isDelete) {
                    editTextList.get(getFirstFocusPosition()).requestFocus();
                }
            });
            /**
            * 焦点的转移
            */
            et_text.addTextChangedListener(new TextWatcher() {
                @Override
                public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                }
                @Override
                public void onTextChanged(CharSequence s, int start, int before, int count) {
                }
                @Override
                public void afterTextChanged(Editable s) {
                    int edittextPosition = getEdittextPosition(et_text);//当前点击的edittext在几何中的位置
                    if (s.toString().length() >= 1 && (edittextPosition + 1) < editTextList.size()) {//增加
                        editTextList.get(edittextPosition + 1).requestFocus();
                    } else if (s.toString().length() < 1 && (edittextPosition - 1) >= 0) {//删除
                        isDelete = true;
                        editTextList.get(edittextPosition - 1).requestFocus();
                        isDelete = false;
                    }
                }
            });
            /**
            * 退格键删除空时的操作
            */
            et_text.setOnKeyListener((v, keyCode, event) -> {
                int edittextPosition = getEdittextPosition(et_text);
                if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) {
                    if (et_text.getText().toString().isEmpty()) {//当前文字为空
                        isDelete = true;
                        if (edittextPosition - 1 >= 0) {
                            editTextList.get(edittextPosition - 1).requestFocus();
                        } else {
                            editTextList.get(edittextPosition).requestFocus();
                        }
                        isDelete = false;
                        return true;
                    } else if (!et_text.getText().toString().isEmpty()) {//当前文字不为空
                        isDelete = true;
                        et_text.setText("");
                        if (edittextPosition - 1 >= 0) {
                            editTextList.get(edittextPosition - 1).requestFocus();
                        } else {
                            editTextList.get(edittextPosition).requestFocus();
                        }
                        isDelete = false;
                        return true;
                    }
                    return false;
                }
                return false;
            });
        }
    }

完!如代码不全可以联系我

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