Search code examples
androidandroid-edittextandroid-canvasondraw

Caching part of canvas in custom view. Android


I have extended EditText view with overridden onDraw method:

@Override
protected void onDraw(Canvas canvas) {
    int count = getLineCount();
    drawLineNumbers(canvas, count); // here I draw line numbers on canvas,
                                    // like on picture
    super.onDraw(canvas);

}

Line number under red

As we know, onDraw method of EditText calls very often, e.g. it calls for each indicator flashing - that's why redrawing all line numbers consume a lot of hardware resources.

Is there efficient method to cache part of canvas and do not redraw it every time? In my case I want to redraw it only when line's count changed. I have already tried save it in Bitmap, but on files with big amount of lines it throwing OutOFMemmory exception.

Any thoughts are welcome.


Solution

  • make a compound custom view:

    class NumEditText extends LinearLayout
    

    and add two views: left margin view with line numbers and an. associated EditText

    EDIT:

    try this skeleton:

    public class NumberedEditText extends LinearLayout {
    
    private LineNumbers lineNumbers;
    private ET et;
    
    public NumberedEditText(Context context) {
        super(context);
        setOrientation(HORIZONTAL);
        lineNumbers = new LineNumbers(context);
        et = new ET(context);
        addView(lineNumbers);
        addView(et, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
    }
    
    class LineNumbers extends View {
        private final static String TAG = "NumberedEditText.LineNumbers";
        public LineNumbers(Context context) {
            super(context);
        }
    
        @Override
        protected void onScrollChanged(int l, int t, int oldl, int oldt) {
            super.onScrollChanged(l, t, oldl, oldt);
            invalidate();
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int fixed = 50;
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(fixed, MeasureSpec.EXACTLY);
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            Log.d(TAG, "onDraw ");
        }
    }
    
    class ET extends EditText implements TextWatcher {
        private final static String TAG = "NumberedEditText.ET";
        private Layout layout;
        private int cnt;
    
        public ET(Context context) {
        super(context);
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            addTextChangedListener(this);
            layout = getLayout();
            cnt = layout.getLineCount();
        }
    
        @Override
        protected void onScrollChanged(int l, int t, int oldl, int oldt) {
            super.onScrollChanged(l, t, oldl, oldt);
            lineNumbers.scrollTo(l, t);
        }
    
        @Override
        public void onTextChanged(CharSequence text, int start, int before, int after) {
        }
    
        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        }
    
        @Override
        public void afterTextChanged(Editable s) {
            if (layout.getLineCount() != cnt) {
                cnt = layout.getLineCount();
                lineNumbers.invalidate();
            }
        }
    }
    }