1 /* <lambda>null2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.example.text.styling.roundedbg 17 18 import android.graphics.Canvas 19 import android.graphics.drawable.Drawable 20 import android.text.Annotation 21 import android.text.Layout 22 import android.text.Spanned 23 24 /** 25 * Helper class to draw multi-line rounded background to certain parts of a text. The start/end 26 * positions of the backgrounds are annotated with [android.text.Annotation] class. Each annotation 27 * should have the annotation key set to **rounded**. 28 * 29 * i.e.: 30 * ``` 31 * <!--without the quotes at the begining and end Android strips the whitespace and also starts 32 * the annotation at the wrong position--> 33 * <string name="ltr">"this is <annotation key="rounded">a regular</annotation> paragraph."</string> 34 * ``` 35 * 36 * **Note:** BiDi text is not supported. 37 * 38 * @param horizontalPadding the padding to be applied to left & right of the background 39 * @param verticalPadding the padding to be applied to top & bottom of the background 40 * @param drawable the drawable used to draw the background 41 * @param drawableLeft the drawable used to draw left edge of the background 42 * @param drawableMid the drawable used to draw for whole line 43 * @param drawableRight the drawable used to draw right edge of the background 44 */ 45 class TextRoundedBgHelper( 46 val horizontalPadding: Int, 47 verticalPadding: Int, 48 drawable: Drawable, 49 drawableLeft: Drawable, 50 drawableMid: Drawable, 51 drawableRight: Drawable 52 ) { 53 54 private val singleLineRenderer: TextRoundedBgRenderer by lazy { 55 SingleLineRenderer( 56 horizontalPadding = horizontalPadding, 57 verticalPadding = verticalPadding, 58 drawable = drawable 59 ) 60 } 61 62 private val multiLineRenderer: TextRoundedBgRenderer by lazy { 63 MultiLineRenderer( 64 horizontalPadding = horizontalPadding, 65 verticalPadding = verticalPadding, 66 drawableLeft = drawableLeft, 67 drawableMid = drawableMid, 68 drawableRight = drawableRight 69 ) 70 } 71 72 /** 73 * Call this function during onDraw of another widget such as TextView. 74 * 75 * @param canvas Canvas to draw onto 76 * @param text 77 * @param layout Layout that contains the text 78 */ 79 fun draw(canvas: Canvas, text: Spanned, layout: Layout) { 80 // ideally the calculations here should be cached since they are not cheap. However, proper 81 // invalidation of the cache is required whenever anything related to text has changed. 82 val spans = text.getSpans(0, text.length, Annotation::class.java) 83 spans.forEach { span -> 84 if (span.value.equals("rounded")) { 85 val spanStart = text.getSpanStart(span) 86 val spanEnd = text.getSpanEnd(span) 87 val startLine = layout.getLineForOffset(spanStart) 88 val endLine = layout.getLineForOffset(spanEnd) 89 90 // start can be on the left or on the right depending on the language direction. 91 val startOffset = (layout.getPrimaryHorizontal(spanStart) 92 + -1 * layout.getParagraphDirection(startLine) * horizontalPadding).toInt() 93 // end can be on the left or on the right depending on the language direction. 94 val endOffset = (layout.getPrimaryHorizontal(spanEnd) 95 + layout.getParagraphDirection(endLine) * horizontalPadding).toInt() 96 97 val renderer = if (startLine == endLine) singleLineRenderer else multiLineRenderer 98 renderer.draw(canvas, layout, startLine, endLine, startOffset, endOffset) 99 } 100 } 101 } 102 }