EditText文本输入控制(侧重发布微博时@某某某的解决)

10 篇文章 0 订阅

在发布微博或者写空间说说时,经常会用到@某人的输入格式:

猜测在新浪微博中的使用,是用SpannableStringBuilder来进行实现,同时在点击“@xxx”时光标不能停在用户名内部,即不可编辑用户。

在qq空间中,@之后的用户名没有样式也可点击编辑,但是这两个的共同点是删除时会删除这个人,而不是删除其中一个字母。

下面我实现的是新浪微博的样式,因为更加严谨一些:

在上一篇中完成到对特定的用户有了样式显示(蓝色高亮),也有点击事件。

更简单的高亮方式:

后来又想到一个更加简单的高亮方式,但是只是高亮没有实用价值,或者说功能实现起来麻烦一些,就是使用html,在editText中可以现实网页源码内容,那么可以显示之前在用户名加上超链接标签,但是同样需要记录用户的开始索引和结束索引,因为当@多人时,第二次会丢失超链接标签,需要反复设置。

正题:

首先声明一个用来保存内容中所有的“@xxx”的位置的变量:

private ArrayList<WhereKey> spans_position;
	class WhereKey {
		public int start;
		public int end;
	}
只需要记录首尾位置。

接下来要做的是更新这些位置的值,因为在编辑时可能会删除也可能会插入内容,那么这个操作的就放在afterTextChanged方法中:

spans_position.clear();
				// Log.i(TAG, "spans_position.size()--before=" +
				// spans_position.size());
				ForegroundColorSpan[] spans_pos = s.getSpans(0, s.length(),
						ForegroundColorSpan.class);
				for (int i = 0; i < spans_pos.length; i++) {
					int start = s.getSpanStart(spans_pos[i]);
					int end = s.getSpanEnd(spans_pos[i]);
					WhereKey whereKey = new WhereKey();
					whereKey.start = start;
					whereKey.end = end;
					spans_position.add(whereKey);
				}
				// Log.i(TAG, "spans_position.size()--after=" +
				// spans_position.size());

同时上一篇中的adapter部分也有了变化:

@Override
		public View getView(final int position, View convertView,
				ViewGroup parent) {
			PopHolder holder;
			if (convertView == null) {
				holder = new PopHolder();
				convertView = LayoutInflater.from(CreateNewWeibo.this).inflate(
						R.layout.pop_for_at_item, null);
				holder.nick_name = (TextView) convertView
						.findViewById(R.id.pop_for_at_tv);
				convertView.setTag(holder);
			} else {
				holder = (PopHolder) convertView.getTag();
			}
			holder.nick_name.setText(mListItems.get(position).nickname);
			convertView.setOnClickListener(new OnClickListener() {

				@Override
				public void onClick(View v) {
					b = false;
					String temp = editText.getText().toString();
					String body = "@" + mListItems.get(position).nickname;
					at_users.add(body);
					// Log.i(TAG, "at_users.size()="+ at_users.size());
					String text = temp.substring(0, curr) + body;
					SpannableStringBuilder style = new SpannableStringBuilder(
							text); // 将str字符串载入SpannableStringBuilder对象中
					ArrayList<WhereKey> keys = new ArrayList<CreateNewWeibo.WhereKey>();
					for (int i = 0; i < at_users.size(); i++) {
						WhereKey one_key = new WhereKey();
						one_key.start = text.indexOf(at_users.get(i));
						one_key.end = at_users.get(i).length() + one_key.start;
						keys.add(one_key);
					}
					for (int i = 0; i < keys.size(); i++) {
						style.setSpan(new ForegroundColorSpan(Color.BLUE),
								keys.get(i).start, keys.get(i).end,
								Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
					}
					editText.setText(style);
					// editText.setText(Html.fromHtml(text));
					// Toast.makeText(CreateNewWeibo.this,
					// editText.getText().toString(),
					// Toast.LENGTH_SHORT).show();
					mPop.dismiss();
					curr = 0;
					editText.setSelection(editText.getText().length());
				}
			});
			return convertView;
		}

	}

增加了多个用户时的用户收集变量:at_users,它的更新同样是放在afterTextChanged中:

if (delete_before.length() > s.length()) {
					ForegroundColorSpan[] spans = s.getSpans(0, s.length(),
							ForegroundColorSpan.class);

					for (int i = 0; i < spans.length; i++) {
						int start = s.getSpanStart(spans[i]);
						int end = s.getSpanEnd(spans[i]);
						String last = s.toString().substring(start, end);
						for (int j = 0; j < at_users.size(); j++) {
							String first = at_users.get(j).substring(0,
									at_users.get(j).length() - 1);
							if (last.equals(first)) {
								s.delete(start, end).toString();
								at_users.remove(j);
							}
						}
					}
				}
delete_before这个变量记录的是text改变之前的值,上面代码的作用主要是判断是否在进行删除用户操作,当删除用户其中的一个字母时就会在text中移除这个用户的全部信息,并把他从at_users中移除。

接下来要做的就是实现touch用户名时光标不会停在用户信息中间,而会跳到它的前面(至于跳到前面还是后面可以控制,不一定),首先给editText添加OnTouchListener监听,实现onTouch方法,在方法中要弄明白的事情是事件的执行顺序,首先会执行的是onDown,然后是onUp,但是如果只是这样来看,还是没办法获取到你touch之后光标的位置,得到的全是光标之前的位置,解决的办法是先调用一次父类的onTouchenvent,然后在onUp事件中捕获到光标的位置,再借助最前面提到的spans_position来跳转光标:

editText.setOnTouchListener(new OnTouchListener() {

			@Override
			public boolean onTouch(View v, MotionEvent event) {
				v.onTouchEvent(event);
				if (event.getAction() == MotionEvent.ACTION_UP) {
					int start_now = editText.getSelectionStart();
					Log.i(TAG, "start_now=" + start_now);
					Log.i(TAG, "spans_position.size()=" + spans_position.size());
					for (int i = 0; i < spans_position.size(); i++) {
						// Log.i(TAG, "spans_position.get(i).start="
						// + spans_position.get(i).start);
						// Log.i(TAG, "spans_position.get(i).end="
						// + spans_position.get(i).end);
						if (start_now > spans_position.get(i).start
								&& start_now < spans_position.get(i).end) {
							// Log.i(TAG, "into");
							editText.setSelection(spans_position.get(i).start);
							return true;
						}
					}
				}

				return false;
			}
		});
这样功能就和微博的完全一样了,同时在输入@进行联想是使用的是popwindow,不用去跳转到另外的活动。

未验证和解决的问题:对于一条信息中多次@同一个人有隐患,未解决。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值