自定义控件实现语法高亮

效果如图:

自定义控件实现语法高亮
效果截图

核心代码如下:

package com.laugh.HighlightCode;
import android.widget.EditText;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Color;
import android.graphics.Typeface;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.Layout;
import android.os.Handler;
import android.os.Message;
import android.text.TextWatcher;
import android.text.Editable;
import android.text.style.ForegroundColorSpan;
import android.text.Spanned;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.text.style.BackgroundColorSpan;
import android.view.View;
import android.view.MotionEvent;
import android.util.Log;

public class HighlightEditor extends EditText implements TextWatcher {
	public static final Pattern a = Pattern.compile("=|<|>|!|\\-|\\+|&|\\|");
	public static final Pattern b = Pattern.compile("true|false|[0-9]*$|\\d+(\\.\\d+)?");
	public static final Pattern c = Pattern.compile("class|import|extends|package|implements|switch|while(?=.*\\()|for(?=.*\\()|break|case|private|public|protected|void|super|this|static|final|if|else|return|new|catch|try|default|interface");
	public static final Pattern d = Pattern.compile("\\;|\\(|\\)|\\{|\\}|R\\..+?\\b|String |int |boolean |float |double |char |long |([email protected]).*?(\\s|(?=\\())|(?<=extends ).*|(?<=implements ).*|(?<=(class |interface )).*?(?=\\s\\b)");
	public static final Pattern e = Pattern.compile("((?<!:)\\/\\/.*|\\/\\*(\\s|.)*?\\*\\/|<!--(.|\r\n)*-->)");
	public static final Pattern f = Pattern.compile("(?<=import ).*(?=;)");
	public static final Pattern g = Pattern.compile("\".+?\"");
	public static final int COLOR_A = 0xFFF44336;
	public static final int COLOR_B = 0xFF99C794;
	public static final int COLOR_C = 0xFFFF5252;
	public static final int COLOR_D = 0xFF6699CC;
	public static final int COLOR_E = 0xFF999999;
	public static final int COLOR_F = 0xFF646464;

	private Paint leftPaint;//左边栏背景色画笔
	private int paddingLeft = 60;//左边边距宽度
	private TextPaint textPaint;//左边文字画笔

	private CharSequence text;

	public HighlightEditor(Context context) {
		this(context, null);
	}

	public HighlightEditor(Context context, AttributeSet attr) {
		super(context, attr);
		setPadding(paddingLeft, 0, 0, 0);
		setTextColor(0xFF646464);
		
		this.leftPaint = new Paint();//左边栏背景色画笔
		this.leftPaint.setColor(Color.parseColor("#64646464"));

		textPaint = new TextPaint();//创建一个textPaint画笔
		textPaint.setColor(Color.parseColor("#FF4081"));
		textPaint.setTextSize(24);
		textPaint.setAntiAlias(true);

		addTextChangedListener(this);
	}

	@Override
	public void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		int LineCount = getLineCount();//编辑框行数
		int LineHeight = getLineHeight();//编辑框每行高度
		if (LineHeight != 0) {
			canvas.drawRect(0, 0, paddingLeft, getHeight(), leftPaint);//绘制左边栏
			for (int i = 0;i < LineCount;i++) {
				StaticLayout layout = new StaticLayout(String.valueOf(i + 1), textPaint, paddingLeft,
													   Layout.Alignment.ALIGN_CENTER, 1.0F, 0.0F, true);
				canvas.save();
				canvas.translate(0, (i) * LineHeight);
				layout.draw(canvas);
				canvas.restore();
			}

			//绘制当前选中行的横条
			int y = (getLayout().getLineForOffset(getSelectionStart()) + 1) * LineHeight;
			canvas.drawRect(0, y - LineHeight, getWidth(), y, leftPaint);
		}
	}




	@Override
	public void onTextChanged(final CharSequence text, int start, int before, int count) { 
		//text  输入框中改变后的字符串信息 
		//start 输入框中改变后的字符串的起始位置 
		//before 输入框中改变前的字符串的位置 默认为0
		//count 输入框中改变后的一共输入字符串的数量 
		this.text = text;
		highlight();
		/*
		if (handler.hasMessages(0)) {
			handler.removeMessages(0);
		}
		handler.sendEmptyMessage(0);*/
		
	} 

	@Override
	public void beforeTextChanged(final CharSequence text, int start, int count, int after) { 
		//text  输入框中改变前的字符串信息 
		//start 输入框中改变前的字符串的起始位置 
		//count 输入框中改变前后的字符串改变数量一般为0 
		//after 输入框中改变后的字符串与起始位置的偏移量 

	} 

	@Override
	public void afterTextChanged(Editable edit) { 
		//edit  输入结束呈现在输入框中的信息 
	}
	
	
	private Handler handler = new Handler(){
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			switch(msg.what)
			{
				case 0:
					highlight();
					break;
			}
		}
	};
	
	
	private void highlight()
	{
		ForegroundColorSpan[] spans = getText().getSpans(0, getText().length(), ForegroundColorSpan.class);
		for (int n = spans.length;n-- > 0;) {
			getText().removeSpan(spans[n]);
		}
		BackgroundColorSpan[] Spans = getText().getSpans(0, getText().length(), BackgroundColorSpan.class);
		for (int n = Spans.length;n--> 0;) {
			getText().removeSpan(spans[n]);
		}
		Matcher A = a.matcher(text);
		Matcher B = b.matcher(text);
		Matcher C = c.matcher(text);
		Matcher D = d.matcher(text);
		Matcher E = e.matcher(text);
		Matcher F = f.matcher(text);
		Matcher G = g.matcher(text);
		while (A.find()) {
			getText().setSpan(new ForegroundColorSpan(COLOR_A), A.start(), A.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
		}
		while (C.find()) {
			getText().setSpan(new ForegroundColorSpan(COLOR_C), C.start(), C.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
		}
		while (D.find()) {
			getText().setSpan(new ForegroundColorSpan(COLOR_D), D.start(), D.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
		}
		while (B.find()) {
			getText().setSpan(new ForegroundColorSpan(COLOR_B), B.start(), B.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
		}
		while (G.find()) {
			ForegroundColorSpan[] G_Spans = getText().getSpans(G.start(), G.end(), ForegroundColorSpan.class);
			for (int n = G_Spans.length;n--> 0;) {
				getText().removeSpan(G_Spans[n]);
			}
			getText().setSpan(new ForegroundColorSpan(COLOR_B), G.start(), G.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
		}
		while (E.find()) {
			ForegroundColorSpan[] E_Spans = getText().getSpans(E.start(), E.end(), ForegroundColorSpan.class);
			for (int n = E_Spans.length;n--> 0;) {
				getText().removeSpan(E_Spans[n]);
			}
			getText().setSpan(new ForegroundColorSpan(COLOR_E), E.start(), E.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
		}
		while (F.find()) {
			ForegroundColorSpan[] F_Spans = getText().getSpans(F.start(), F.end(), ForegroundColorSpan.class);
			for (int n = F_Spans.length;n--> 0;) {
				getText().removeSpan(F_Spans[n]);
			}
			getText().setSpan(new ForegroundColorSpan(COLOR_F), F.start(), F.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
		}
	}
}

基本没有bug,只不过没有较好的优化线程

Tisp:默默的告诉你这是我的第一篇博文

CSDN:https://download.csdn.net/download/qq_36109137/10949393

Github:https://github.com/X-JianChen/HighlightCode