Android中如何仅在EditText软键盘主动换行时添加项目符号?
Android 区分EditText手动换行与自动换行,实现仅手动换行添加项目符号
明确回答:可以检测用户是否按下软键盘的换行键,通过监听键盘按键事件即可实现,进而区分手动换行和文本自动换行的场景,解决你当前每一行都生成项目符号的问题。
解决方案与代码实现
核心思路
- 捕获用户手动按下回车键的事件,记录手动换行的位置索引
- 在绘制时,仅对手动换行触发的新行绘制项目符号,忽略文本自动换行的行
- 预留项目符号的左侧空间,避免文本与符号重叠
调整后的自定义EditText代码
public class BulletEditText extends AppCompatEditText { private Paint bulletPaint; private Rect bulletRect; // 存储手动换行的起始字符索引,标记哪些行是新项目 private List<Integer> manualBreakPositions = new ArrayList<>(); private boolean isTyping; public BulletEditText(Context context) { super(context); init(); } public BulletEditText(Context context, AttributeSet attrs) { super(context, attrs); init(); } public BulletEditText(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { bulletPaint = new Paint(); bulletPaint.setColor(getCurrentTextColor()); bulletPaint.setTextSize(getTextSize()); bulletRect = new Rect(); // 初始添加第一个项目的起始位置 manualBreakPositions.add(0); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_DOWN) { // 记录手动换行后的起始字符索引 int cursorPos = getSelectionStart(); manualBreakPositions.add(cursorPos + 1); return super.onKeyDown(keyCode, event); } return super.onKeyDown(keyCode, event); } @Override protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { super.onTextChanged(text, start, lengthBefore, lengthAfter); isTyping = text.length() > 0; // 清理重复换行与开头换行 String newText = text.toString().replace("\n\n", "\n"); if (newText.startsWith("\n")) { newText = newText.substring(1); manualBreakPositions.removeIf(pos -> pos == 0); if (manualBreakPositions.isEmpty()) { manualBreakPositions.add(0); } } if (!text.toString().equals(newText)) { setText(newText); setSelection(getText().length()); } } @Override protected void onDraw(Canvas canvas) { if (isTyping) { int baseline = getBaseline(); int lineCount = getLineCount(); Layout layout = getLayout(); for (int i = 0; i < lineCount; i++) { int lineStart = layout.getLineStart(i); // 仅在手动标记的起始行绘制项目符号 if (manualBreakPositions.contains(lineStart)) { canvas.drawText(" •", bulletRect.left, baseline, bulletPaint); } baseline += getLineHeight(); } } super.onDraw(canvas); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 为项目符号预留左侧空间 bulletRect.left = getPaddingLeft(); bulletRect.right = bulletRect.left + (int) bulletPaint.measureText(" •"); setPadding(bulletRect.right, getPaddingTop(), getPaddingRight(), getPaddingBottom()); } }
代码说明
- 手动换行监听:通过
onKeyDown捕获回车键,记录换行后的字符起始索引,标记新项目的开始 - 绘制逻辑优化:在
onDraw中通过getLayout().getLineStart(i)获取每行起始索引,仅匹配手动标记的索引时绘制项目符号 - 边距处理:在
onMeasure中调整左侧内边距,避免文本与项目符号重叠
最终效果
用户输入时:
- 长文本自动换行:不会生成新的项目符号
• Item 1 Item 1
Item 1 also - 按下回车键手动换行:自动添加项目符号
• Item 2
• Item 3
内容的提问来源于stack exchange,提问作者Paranoia
相关产品推荐
相关产品推荐

