Search in sources :

Example 11 with StaticLayout

use of android.text.StaticLayout in project platform_frameworks_base by android.

the class SubtitleView method onDraw.

@Override
protected void onDraw(Canvas c) {
    final StaticLayout layout = mLayout;
    if (layout == null) {
        return;
    }
    final int saveCount = c.save();
    final int innerPaddingX = mInnerPaddingX;
    c.translate(mPaddingLeft + innerPaddingX, mPaddingTop);
    final int lineCount = layout.getLineCount();
    final Paint textPaint = mTextPaint;
    final Paint paint = mPaint;
    final RectF bounds = mLineBounds;
    if (Color.alpha(mBackgroundColor) > 0) {
        final float cornerRadius = mCornerRadius;
        float previousBottom = layout.getLineTop(0);
        paint.setColor(mBackgroundColor);
        paint.setStyle(Style.FILL);
        for (int i = 0; i < lineCount; i++) {
            bounds.left = layout.getLineLeft(i) - innerPaddingX;
            bounds.right = layout.getLineRight(i) + innerPaddingX;
            bounds.top = previousBottom;
            bounds.bottom = layout.getLineBottom(i);
            previousBottom = bounds.bottom;
            c.drawRoundRect(bounds, cornerRadius, cornerRadius, paint);
        }
    }
    final int edgeType = mEdgeType;
    if (edgeType == CaptionStyle.EDGE_TYPE_OUTLINE) {
        textPaint.setStrokeJoin(Join.ROUND);
        textPaint.setStrokeWidth(mOutlineWidth);
        textPaint.setColor(mEdgeColor);
        textPaint.setStyle(Style.FILL_AND_STROKE);
        for (int i = 0; i < lineCount; i++) {
            layout.drawText(c, i, i);
        }
    } else if (edgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) {
        textPaint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, mEdgeColor);
    } else if (edgeType == CaptionStyle.EDGE_TYPE_RAISED || edgeType == CaptionStyle.EDGE_TYPE_DEPRESSED) {
        final boolean raised = edgeType == CaptionStyle.EDGE_TYPE_RAISED;
        final int colorUp = raised ? Color.WHITE : mEdgeColor;
        final int colorDown = raised ? mEdgeColor : Color.WHITE;
        final float offset = mShadowRadius / 2f;
        textPaint.setColor(mForegroundColor);
        textPaint.setStyle(Style.FILL);
        textPaint.setShadowLayer(mShadowRadius, -offset, -offset, colorUp);
        for (int i = 0; i < lineCount; i++) {
            layout.drawText(c, i, i);
        }
        textPaint.setShadowLayer(mShadowRadius, offset, offset, colorDown);
    }
    textPaint.setColor(mForegroundColor);
    textPaint.setStyle(Style.FILL);
    for (int i = 0; i < lineCount; i++) {
        layout.drawText(c, i, i);
    }
    textPaint.setShadowLayer(0, 0, 0, 0);
    c.restoreToCount(saveCount);
}
Also used : RectF(android.graphics.RectF) StaticLayout(android.text.StaticLayout) TextPaint(android.text.TextPaint) Paint(android.graphics.Paint) TextPaint(android.text.TextPaint) Paint(android.graphics.Paint)

Example 12 with StaticLayout

use of android.text.StaticLayout in project platform_frameworks_base by android.

the class SubtitleView method computeMeasurements.

private boolean computeMeasurements(int maxWidth) {
    if (mHasMeasurements && maxWidth == mLastMeasuredWidth) {
        return true;
    }
    // Account for padding.
    final int paddingX = mPaddingLeft + mPaddingRight + mInnerPaddingX * 2;
    maxWidth -= paddingX;
    if (maxWidth <= 0) {
        return false;
    }
    // TODO: Implement minimum-difference line wrapping. Adding the results
    // of Paint.getTextWidths() seems to return different values than
    // StaticLayout.getWidth(), so this is non-trivial.
    mHasMeasurements = true;
    mLastMeasuredWidth = maxWidth;
    mLayout = new StaticLayout(mText, mTextPaint, maxWidth, mAlignment, mSpacingMult, mSpacingAdd, true);
    return true;
}
Also used : StaticLayout(android.text.StaticLayout) TextPaint(android.text.TextPaint) Paint(android.graphics.Paint)

Example 13 with StaticLayout

use of android.text.StaticLayout in project TextJustify-Android by bluejamesbond.

the class SpannableDocumentLayout method onMeasure.

@SuppressWarnings("ConstantConditions")
@Override
public boolean onMeasure(IProgress<Float> progress, ICancel<Boolean> cancelled) {
    boolean done = true;
    float parentWidth = params.getParentWidth();
    float boundWidth = params.getParentWidth() - params.getInsetPaddingLeft() - params.getInsetPaddingRight();
    mLeadMarginSpanDrawEvents = new LinkedList<>();
    StaticLayout staticLayout = new StaticLayout(getText(), (TextPaint) getPaint(), (int) boundWidth, Layout.Alignment.ALIGN_NORMAL, 1, 0, false);
    int[] newTokens = new int[TOKEN_LENGTH * 1000];
    LeadingMarginSpan[] activeLeadSpans = new LeadingMarginSpan[0];
    HashMap<LeadingMarginSpan, Integer> leadSpans = new HashMap<>();
    TextAlignment defAlign = params.textAlignment;
    Spannable textCpy = (Spannable) this.text;
    Paint.FontMetricsInt fmi = paint.getFontMetricsInt();
    int maxTextIndex = textCpy.length() - 1;
    int lines = staticLayout.getLineCount();
    int enableLineBreak = 0;
    int index = 0;
    int lineNumber;
    float x;
    float y = params.insetPaddingTop;
    float left = params.insetPaddingLeft;
    float right = params.insetPaddingRight;
    float lineHeightAdd = params.lineHeightMultiplier;
    float lastAscent;
    float lastDescent;
    boolean isParaStart = true;
    boolean isReverse = params.reverse;
    for (lineNumber = 0; lineNumber < lines; lineNumber++) {
        if (cancelled.isCancelled()) {
            done = false;
            break;
        }
        progress.onUpdate((float) lineNumber / (float) lines);
        newTokens = ammortizeArray(newTokens, index);
        int start = staticLayout.getLineStart(lineNumber);
        int end = staticLayout.getLineEnd(lineNumber);
        float realWidth = boundWidth;
        if (params.debugging) {
            Console.log(start + " => " + end + " :: " + " " + -staticLayout.getLineAscent(lineNumber) + " " + staticLayout.getLineDescent(lineNumber) + " " + textCpy.subSequence(start, end).toString());
        }
        // start == end => end of textCpy
        if (start == end || lineNumber >= params.maxLines) {
            break;
        }
        // Get textCpy alignment for the line
        TextAlignmentSpan[] textAlignmentSpans = textCpy.getSpans(start, end, TextAlignmentSpan.class);
        TextAlignment lineTextAlignment = textAlignmentSpans.length == 0 ? defAlign : textAlignmentSpans[0].getTextAlignment();
        // Calculate components of line height
        lastAscent = -staticLayout.getLineAscent(lineNumber);
        lastDescent = staticLayout.getLineDescent(lineNumber) + lineHeightAdd;
        // Handle reverse
        DirectionSpan[] directionSpans = textCpy.getSpans(start, end, DirectionSpan.class);
        isReverse = directionSpans.length > 0 ? directionSpans[0].isReverse() : params.reverse;
        // Line is ONLY a <br/> or \n
        if (start + 1 == end && (Character.getNumericValue(textCpy.charAt(start)) == -1 || textCpy.charAt(start) == '\n')) {
            // Line break indicates a new paragraph
            // is next
            isParaStart = true;
            // Use the line-height of the next line
            if (lineNumber + 1 < lines) {
                y += enableLineBreak * (-staticLayout.getLineAscent(lineNumber + 1) + staticLayout.getLineDescent(lineNumber + 1));
            }
            // Don't ignore the next line breaks
            enableLineBreak = 1;
            continue;
        } else {
            // Ignore the next line break
            enableLineBreak = 0;
        }
        x = lineTextAlignment == TextAlignment.RIGHT ? right : left;
        y += lastAscent;
        // Line CONTAINS a \n
        boolean isParaEnd = end == maxTextIndex || textCpy.charAt(Math.min(end, maxTextIndex)) == '\n' || textCpy.charAt(end - 1) == '\n';
        if (isParaEnd) {
            enableLineBreak = 1;
        }
        // LeadingMarginSpan block
        if (isParaStart) {
            // Process LeadingMarginSpan
            activeLeadSpans = textCpy.getSpans(start, end, LeadingMarginSpan.class);
            // Set up all the spans
            if (activeLeadSpans.length > 0) {
                for (LeadingMarginSpan leadSpan : activeLeadSpans) {
                    if (!leadSpans.containsKey(leadSpan)) {
                        // Default margin is everything
                        int marginLineCount = -1;
                        if (leadSpan instanceof LeadingMarginSpan.LeadingMarginSpan2) {
                            LeadingMarginSpan.LeadingMarginSpan2 leadSpan2 = ((LeadingMarginSpan.LeadingMarginSpan2) leadSpan);
                            marginLineCount = leadSpan2.getLeadingMarginLineCount();
                        }
                        leadSpans.put(leadSpan, marginLineCount);
                    }
                }
            }
        }
        float totalMargin = 0.0f;
        int top = (int) (y - lastAscent);
        int baseline = (int) (y);
        int bottom = (int) (y + lastDescent);
        for (LeadingMarginSpan leadSpan : activeLeadSpans) {
            // TOKEN_X based on alignment
            float calcX = x;
            // LineAlignment
            int lineAlignmentVal = 1;
            if (lineTextAlignment == TextAlignment.RIGHT) {
                lineAlignmentVal = -1;
                calcX = parentWidth - x;
            }
            // Get current line count
            int spanLines = leadSpans.get(leadSpan);
            // Update only if the valid next valid
            if (spanLines > 0 || spanLines == -1) {
                leadSpans.put(leadSpan, spanLines == -1 ? -1 : spanLines - 1);
                mLeadMarginSpanDrawEvents.add(new LeadingMarginSpanDrawParameters(leadSpan, (int) calcX, lineAlignmentVal, top, baseline, bottom, start, end, isParaStart));
                // Is margin required?
                totalMargin += leadSpan.getLeadingMargin(isParaStart);
            }
        }
        x += totalMargin;
        realWidth -= totalMargin;
        // Disable/enable new paragraph
        isParaStart = isParaEnd;
        // TextAlignmentSpan block
        if (isParaEnd && lineTextAlignment == TextAlignment.JUSTIFIED) {
            lineTextAlignment = isReverse ? TextAlignment.RIGHT : TextAlignment.LEFT;
        }
        if (params.debugging) {
            Console.log(String.format("Align: %s, X: %fpx, Y: %fpx, PWidth: %fpx", lineTextAlignment, x, y, parentWidth));
        }
        switch(lineTextAlignment) {
            case RIGHT:
                {
                    float lineWidth = Styled.measureText(paint, workPaint, textCpy, start, end, fmi);
                    index = pushToken(newTokens, index, start, end, parentWidth - x - lineWidth, y, lastAscent, lastDescent, lineNumber);
                    y += lastDescent;
                    continue;
                }
            case CENTER:
                {
                    float lineWidth = Styled.measureText(paint, workPaint, textCpy, start, end, fmi);
                    index = pushToken(newTokens, index, start, end, x + (realWidth - lineWidth) / 2, y, lastAscent, lastDescent, lineNumber);
                    y += lastDescent;
                    continue;
                }
            case LEFT:
                {
                    index = pushToken(newTokens, index, start, end, x, y, lastAscent, lastDescent, lineNumber);
                    y += lastDescent;
                    continue;
                }
        }
        // FIXME: Space at the end of each line, possibly due to scrollbar offset
        //            LinkedList<Integer> tokenized = tokenize(textCpy, start, end - 1);
        // FIXME: 2016/4/16 Issue #105 bug
        LinkedList<Integer> tokenized = tokenize(textCpy, start, end);
        // If one long word without any spaces
        if (tokenized.size() == 1) {
            int stop = tokenized.get(0);
            // characters individually
            if (getTrimmedLength(textCpy, start, stop) != 0) {
                float[] textWidths = new float[stop - start];
                float sum = 0.0f, textsOffset = 0.0f, offset;
                int m = 0;
                Styled.getTextWidths(paint, workPaint, textCpy, start, stop, textWidths, fmi);
                for (float tw : textWidths) {
                    sum += tw;
                }
                offset = (realWidth - sum) / (textWidths.length - 1);
                for (int k = start; k < stop; k++) {
                    index = pushToken(newTokens, index, k, k + 1, x + textsOffset + (offset * m), y, lastAscent, lastDescent, lineNumber);
                    newTokens = ammortizeArray(newTokens, index);
                    textsOffset += textWidths[m++];
                }
            }
        } else //  Handle multiple words
        {
            int m = 1;
            int indexOffset = 0;
            int startIndex = index;
            int reqSpaces = (tokenized.size() - 1) * TOKEN_LENGTH;
            int rtlZero = 0;
            float rtlRight = 0;
            float rtlMul = 1;
            float lineWidth = 0;
            float offset;
            if (isReverse) {
                indexOffset = -2 * TOKEN_LENGTH;
                rtlRight = parentWidth;
                rtlMul = -1;
                rtlZero = 1;
                // reverse index
                index += reqSpaces;
            }
            // more space
            newTokens = ammortizeArray(newTokens, index + reqSpaces);
            for (int stop : tokenized) {
                float wordWidth = Styled.measureText(paint, workPaint, textCpy, start, stop, fmi);
                // add word
                index = pushToken(newTokens, index, start, stop, rtlRight + rtlMul * (x + lineWidth + rtlZero * wordWidth), y, lastAscent, lastDescent, lineNumber);
                lineWidth += wordWidth;
                start = stop + 1;
                // based on if rtl
                index += indexOffset;
            }
            if (isReverse) {
                index = startIndex + reqSpaces + TOKEN_LENGTH;
            }
            offset = (realWidth - lineWidth) / (float) (tokenized.size() - 1);
            if (isReverse) {
                for (int pos = index - TOKEN_LENGTH * 2; pos >= startIndex; pos -= TOKEN_LENGTH) {
                    newTokens[pos + TOKEN_X] = (int) (((float) newTokens[pos + TOKEN_X]) - (offset * (float) m++));
                }
            } else {
                for (int pos = startIndex + TOKEN_LENGTH; pos < index; pos += TOKEN_LENGTH) {
                    newTokens[pos + TOKEN_X] = (int) (((float) newTokens[pos + TOKEN_X]) + (offset * (float) m++));
                }
            }
        }
        y += lastDescent;
    }
    lineCount = lineNumber;
    tokens = newTokens;
    params.changed = false;
    textChange = !done;
    measuredHeight = (int) (y - lineHeightAdd + params.insetPaddingBottom);
    return done;
}
Also used : DirectionSpan(com.bluejamesbond.text.style.DirectionSpan) HashMap(java.util.HashMap) StaticLayout(android.text.StaticLayout) TextPaint(android.text.TextPaint) Paint(android.graphics.Paint) TextPaint(android.text.TextPaint) Paint(android.graphics.Paint) TextAlignmentSpan(com.bluejamesbond.text.style.TextAlignmentSpan) TextAlignment(com.bluejamesbond.text.style.TextAlignment) LeadingMarginSpan(android.text.style.LeadingMarginSpan) Spannable(android.text.Spannable)

Example 14 with StaticLayout

use of android.text.StaticLayout in project BGAQRCode-Android by bingoogolapple.

the class ScanBoxView method setIsBarcode.

public void setIsBarcode(boolean isBarcode) {
    mIsBarcode = isBarcode;
    if (mCustomGridScanLineDrawable != null || mIsShowDefaultGridScanLineDrawable) {
        if (mIsBarcode) {
            mGridScanLineBitmap = mOriginBarCodeGridScanLineBitmap;
        } else {
            mGridScanLineBitmap = mOriginQRCodeGridScanLineBitmap;
        }
    } else if (mCustomScanLineDrawable != null || mIsShowDefaultScanLineDrawable) {
        if (mIsBarcode) {
            mScanLineBitmap = mOriginBarCodeScanLineBitmap;
        } else {
            mScanLineBitmap = mOriginQRCodeScanLineBitmap;
        }
    }
    if (mIsBarcode) {
        mTipText = mBarCodeTipText;
        mRectHeight = mBarcodeRectHeight;
        mAnimDelayTime = (int) ((1.0f * mAnimTime * mMoveStepDistance) / mRectWidth);
    } else {
        mTipText = mQRCodeTipText;
        mRectHeight = mRectWidth;
        mAnimDelayTime = (int) ((1.0f * mAnimTime * mMoveStepDistance) / mRectHeight);
    }
    if (!TextUtils.isEmpty(mTipText)) {
        if (mIsShowTipTextAsSingleLine) {
            mTipTextSl = new StaticLayout(mTipText, mTipPaint, BGAQRCodeUtil.getScreenResolution(getContext()).x, Layout.Alignment.ALIGN_CENTER, 1.0f, 0, true);
        } else {
            mTipTextSl = new StaticLayout(mTipText, mTipPaint, mRectWidth - 2 * mTipBackgroundRadius, Layout.Alignment.ALIGN_CENTER, 1.0f, 0, true);
        }
    }
    if (mIsCenterVertical) {
        int screenHeight = BGAQRCodeUtil.getScreenResolution(getContext()).y;
        if (mToolbarHeight == 0) {
            mTopOffset = (screenHeight - mRectHeight) / 2;
        } else {
            mTopOffset = (screenHeight - mRectHeight) / 2 + mToolbarHeight / 2;
        }
    }
    calFramingRect();
    postInvalidate();
}
Also used : StaticLayout(android.text.StaticLayout) TextPaint(android.text.TextPaint) Paint(android.graphics.Paint)

Example 15 with StaticLayout

use of android.text.StaticLayout in project ExoPlayer by google.

the class SubtitlePainter method setupTextLayout.

private void setupTextLayout() {
    int parentWidth = parentRight - parentLeft;
    int parentHeight = parentBottom - parentTop;
    textPaint.setTextSize(textSizePx);
    int textPaddingX = (int) (textSizePx * INNER_PADDING_RATIO + 0.5f);
    int availableWidth = parentWidth - textPaddingX * 2;
    if (cueSize != Cue.DIMEN_UNSET) {
        availableWidth = (int) (availableWidth * cueSize);
    }
    if (availableWidth <= 0) {
        Log.w(TAG, "Skipped drawing subtitle cue (insufficient space)");
        return;
    }
    Alignment textAlignment = cueTextAlignment == null ? Alignment.ALIGN_CENTER : cueTextAlignment;
    textLayout = new StaticLayout(cueText, textPaint, availableWidth, textAlignment, spacingMult, spacingAdd, true);
    int textHeight = textLayout.getHeight();
    int textWidth = 0;
    int lineCount = textLayout.getLineCount();
    for (int i = 0; i < lineCount; i++) {
        textWidth = Math.max((int) Math.ceil(textLayout.getLineWidth(i)), textWidth);
    }
    if (cueSize != Cue.DIMEN_UNSET && textWidth < availableWidth) {
        textWidth = availableWidth;
    }
    textWidth += textPaddingX * 2;
    int textLeft;
    int textRight;
    if (cuePosition != Cue.DIMEN_UNSET) {
        int anchorPosition = Math.round(parentWidth * cuePosition) + parentLeft;
        textLeft = cuePositionAnchor == Cue.ANCHOR_TYPE_END ? anchorPosition - textWidth : cuePositionAnchor == Cue.ANCHOR_TYPE_MIDDLE ? (anchorPosition * 2 - textWidth) / 2 : anchorPosition;
        textLeft = Math.max(textLeft, parentLeft);
        textRight = Math.min(textLeft + textWidth, parentRight);
    } else {
        textLeft = (parentWidth - textWidth) / 2;
        textRight = textLeft + textWidth;
    }
    textWidth = textRight - textLeft;
    if (textWidth <= 0) {
        Log.w(TAG, "Skipped drawing subtitle cue (invalid horizontal positioning)");
        return;
    }
    int textTop;
    if (cueLine != Cue.DIMEN_UNSET) {
        int anchorPosition;
        if (cueLineType == Cue.LINE_TYPE_FRACTION) {
            anchorPosition = Math.round(parentHeight * cueLine) + parentTop;
        } else {
            // cueLineType == Cue.LINE_TYPE_NUMBER
            int firstLineHeight = textLayout.getLineBottom(0) - textLayout.getLineTop(0);
            if (cueLine >= 0) {
                anchorPosition = Math.round(cueLine * firstLineHeight) + parentTop;
            } else {
                anchorPosition = Math.round((cueLine + 1) * firstLineHeight) + parentBottom;
            }
        }
        textTop = cueLineAnchor == Cue.ANCHOR_TYPE_END ? anchorPosition - textHeight : cueLineAnchor == Cue.ANCHOR_TYPE_MIDDLE ? (anchorPosition * 2 - textHeight) / 2 : anchorPosition;
        if (textTop + textHeight > parentBottom) {
            textTop = parentBottom - textHeight;
        } else if (textTop < parentTop) {
            textTop = parentTop;
        }
    } else {
        textTop = parentBottom - textHeight - (int) (parentHeight * bottomPaddingFraction);
    }
    // Update the derived drawing variables.
    this.textLayout = new StaticLayout(cueText, textPaint, textWidth, textAlignment, spacingMult, spacingAdd, true);
    this.textLeft = textLeft;
    this.textTop = textTop;
    this.textPaddingX = textPaddingX;
}
Also used : Alignment(android.text.Layout.Alignment) StaticLayout(android.text.StaticLayout) TextPaint(android.text.TextPaint) Paint(android.graphics.Paint)

Aggregations

StaticLayout (android.text.StaticLayout)80 TextPaint (android.text.TextPaint)56 Paint (android.graphics.Paint)45 Layout (android.text.Layout)21 DynamicLayout (android.text.DynamicLayout)9 RectF (android.graphics.RectF)6 Bitmap (android.graphics.Bitmap)3 NonNull (android.support.annotation.NonNull)3 BoringLayout (android.text.BoringLayout)3 SpannableStringBuilder (android.text.SpannableStringBuilder)3 KeyEvent (android.view.KeyEvent)3 MotionEvent (android.view.MotionEvent)3 AccessibilityEvent (android.view.accessibility.AccessibilityEvent)3 SuppressLint (android.annotation.SuppressLint)2 Canvas (android.graphics.Canvas)2 Rect (android.graphics.Rect)2 Spanned (android.text.Spanned)2 TruncateAt (android.text.TextUtils.TruncateAt)2 StyleSpan (android.text.style.StyleSpan)2 Animator (android.animation.Animator)1