private void refitText(String text, int textWidth, int textHeight, boolean layout) { if (textWidth > 0) { // Drawable left = getCompoundDrawables()[0]; // Drawable right = getCompoundDrawables()[2]; // float availableWidth = textWidth - this.getPaddingLeft() // - this.getPaddingRight() - this.getCompoundDrawablePadding() // - (left != null ? left.getMinimumWidth() : 0) // - (right != null ? right.getMinimumWidth() : 0); float availableWidth = textWidth; TextPaint tp = getPaint(); tp.setTextSize(MAX_TEXT_SIZE); int lines = text.length() / 25 + 1; Rect rect = new Rect(); tp.getTextBounds(text, 0, text.length(), rect); while (rect.width() > (availableWidth + 5) * lines || rect.height() * lines > textHeight) { tp.setTextSize(tp.getTextSize() - 1); tp.getTextBounds(text, 0, text.length(), rect); // setTextScaleX(availableWidth / size); } // if (getLineCount() != lines) { setLines(lines); setMaxLines(lines); setGravity(Gravity.TOP); // } setTextSize(TypedValue.COMPLEX_UNIT_PX, tp.getTextSize()); } }
// 下面代码是利用上面计算的显示行数,将文字画在画布上,实时更新。 @Override public void onDraw(Canvas canvas) { if (textList.size() == 0) return; for (int i = 0; i < textList.size(); i++) { if (step < this.getHeight() + textList.size() * tp.getTextSize()) { canvas.drawText( textList.get(i), 0, this.getHeight() + (i + 1) * tp.getTextSize() - step, tp); canvas.drawText(" ", 0, 40, tp); } else { step = 0; } } invalidate(); // System.out.println("this.getHeight(): " + this.getHeight()); if (this.getHeight() < textList.size() * textSize) { step = step + speed; } else { step = this.getHeight(); } // if (step >= this.getHeight() + textList.size() * tp.getTextSize()) { // step = 0; // } }
protected void updateTextPaint(TextPaint ds) { if (isVisible()) { ds.setTextSize(ds.getTextSize() * 1.0f); ds.setAlpha(ds.getAlpha()); } else { ds.setTextSize(ds.getTextSize() * mInvisibleSize); ds.setAlpha(0); // ensure the text is not visible } }
private static String glyphMetricsString(TextPaint paint) { int metricsInt = paint.getFontMetricsInt(paint.getFontMetricsInt()); float textSize = paint.getTextSize(); float textScale = paint.getTextScaleX(); float textSkew = paint.getTextSkewX(); Typeface typeface = paint.getTypeface(); return String.format("%i%.2f%.2f%.2f", metricsInt, textSize, textScale, textSkew); }
/** * @param textSizePx * @param applyNow */ private void setTextSizePx(float textSizePx, boolean applyNow) { // update text size field (checked elsewhere) this.textSizePx = textSizePx; if (applyNow && paint.getTextSize() != textSizePx) { paint.setTextSize(textSizePx); updateLayout(); } }
public void initPaint(@NonNull TextPaint base) { paint.set(base); paint.setColor(color); paint.setAlpha(intAlpha()); final Typeface typeface = base.getTypeface(); if (typeface != null && typeface.getStyle() != Typeface.NORMAL) { paint.setTypeface(Typeface.create(typeface, Typeface.NORMAL)); } // pre-calculate fixed height paint.setTextSize(Math.max(base.getTextSize() * DEF_SCALE, minTextSize)); paint.getTextBounds("|", 0, 1, bounds); fixedTextHeight = bounds.height(); // set real text size value paint.setTextSize(Math.max(base.getTextSize() * scale, minTextSize)); initPaintShadow(); invalidate(true); }
/** * Sets the switch text color, size, style, hint color, and highlight color from the specified * TextAppearance resource. * * @attr ref android.R.styleable#Switch_switchTextAppearance */ public void setSwitchTextAppearance(Context context, int resid) { TypedArray appearance = context.obtainStyledAttributes(resid, R.styleable.TextAppearanceSwitch); ColorStateList colors; int ts; colors = appearance.getColorStateList(R.styleable.TextAppearanceSwitch_textColor); if (colors != null) { mTextColors = colors; } else { // If no color set in TextAppearance, default to the view's textColor mTextColors = getTextColors(); } ts = appearance.getDimensionPixelSize(R.styleable.TextAppearanceSwitch_textSize, 0); if (ts != 0) { if (ts != mTextPaint.getTextSize()) { mTextPaint.setTextSize(ts); requestLayout(); } } int typefaceIndex, styleIndex; typefaceIndex = appearance.getInt(R.styleable.TextAppearanceSwitch_typeface, -1); styleIndex = appearance.getInt(R.styleable.TextAppearanceSwitch_textStyle, -1); setSwitchTypefaceByIndex(typefaceIndex, styleIndex); boolean allCaps = appearance.getBoolean(R.styleable.TextAppearanceSwitch_textAllCaps, false); if (allCaps) { mSwitchTransformationMethod = new AllCapsTransformationMethod(getContext()); mSwitchTransformationMethod.setLengthChangesAllowed(true); } else { mSwitchTransformationMethod = null; } appearance.recycle(); }
@Override protected void drawCallout(Canvas canvas, NMapView mapView, boolean shadow, long when) { adjustTextBounds(mapView); stepAnimations(canvas, mapView, when); drawBackground(canvas); float left, top; // draw title mOffsetX = mTempPoint.x - mTempRect.width() / 2; mOffsetX -= mPaddingOffset; mOffsetY = mTempRectF.top + mPaddingY + mTextPaint.getTextSize() + mTitleOffsetY; canvas.drawText(mTitleTruncated, mOffsetX, mOffsetY, mTextPaint); // draw right button if (mDrawableRightButton != null) { left = mTempRectF.right - mPaddingX - mCalloutRightButtonWidth; top = mTempRectF.top + (mBackgroundHeight - mCalloutRightButtonHeight) / 2; // Use background drawables depends on current state mRightButtonRect.left = (int) (left + 0.5F); mRightButtonRect.top = (int) (top + 0.5F); mRightButtonRect.right = (int) (left + mCalloutRightButtonWidth + 0.5F); mRightButtonRect.bottom = (int) (top + mCalloutRightButtonHeight + 0.5F); int itemState = super.getItemState(0); Drawable drawable = getDrawable(0, itemState); if (drawable != null) { drawable.setBounds(mRightButtonRect); drawable.draw(canvas); } if (mRightButtonText != null) { mTextPaint.getTextBounds(mRightButtonText, 0, mRightButtonText.length(), mTempRect); left = mRightButtonRect.left + (mCalloutRightButtonWidth - mTempRect.width()) / 2; top = mRightButtonRect.top + (mCalloutRightButtonHeight - mTempRect.height()) / 2 + mTempRect.height() + mTitleOffsetY; canvas.drawText(mRightButtonText, left, top, mTextPaint); } } // draw tail text if (mTailText != null) { if (mRightButtonRect != null) { left = mRightButtonRect.left; } else { left = mTempRectF.right; } left -= mPaddingX + mTailTextWidth; top = mOffsetY; canvas.drawText(mTailText, left, top, mTextPaint); } }
/** * Resize the text size with specified width and height * * @param width * @param height */ public void resizeText(int width, int height) { CharSequence text = getText(); // Do not resize if the view does not have dimensions or there is no text if (text == null || text.length() == 0 || height <= 0 || width <= 0 || mTextSize == 0) { return; } // Get the text view's paint object TextPaint textPaint = getPaint(); // Store the current text size float oldTextSize = textPaint.getTextSize(); // If there is a max text size set, use the lesser of that and the default text size float targetTextSize = mMaxTextSize > 0 ? Math.min(mTextSize, mMaxTextSize) : mTextSize; // Get the required text height int textHeight = getTextHeight(text, textPaint, width, targetTextSize); // Until we either fit within our text view or we had reached our min text size, incrementally // try smaller sizes while (textHeight > height && targetTextSize > mMinTextSize) { targetTextSize = Math.max(targetTextSize - 2, mMinTextSize); textHeight = getTextHeight(text, textPaint, width, targetTextSize); } // If we had reached our minimum text size and still don't fit, append an ellipsis if (mAddEllipsis && targetTextSize == mMinTextSize && textHeight > height) { // Draw using a static layout StaticLayout layout = new StaticLayout( text, textPaint, width, Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, false); // Check that we have a least one line of rendered text if (layout.getLineCount() > 0) { // Since the line at the specific vertical position would be cut off, // we must trim up to the previous line int lastLine = layout.getLineForVertical(height) - 1; // If the text would not even fit on a single line, clear it if (lastLine < 0) { setText(""); } // Otherwise, trim to the previous line and add an ellipsis else { int start = layout.getLineStart(lastLine); int end = layout.getLineEnd(lastLine); float lineWidth = layout.getLineWidth(lastLine); float ellipseWidth = textPaint.measureText(mEllipsis); // Trim characters off until we have enough room to draw the ellipsis while (width < lineWidth + ellipseWidth) { lineWidth = textPaint.measureText(text.subSequence(start, --end + 1).toString()); } setText(text.subSequence(0, end) + mEllipsis); } } } // Some devices try to auto adjust line spacing, so force default line spacing // and invalidate the layout as a side effect textPaint.setTextSize(targetTextSize); setLineSpacing(mSpacingAdd, mSpacingMult); // Notify the listener if registered if (mTextResizeListener != null) { mTextResizeListener.onTextResize(this, oldTextSize, targetTextSize); } // Reset force resize flag mNeedsResize = false; }
/** * Utility function for measuring and rendering text. The text must not include a tab or emoji. * * @param wp the working paint * @param start the start of the text * @param end the end of the text * @param runIsRtl true if the run is right-to-left * @param c the canvas, can be null if rendering is not needed * @param x the edge of the run closest to the leading margin * @param top the top of the line * @param y the baseline * @param bottom the bottom of the line * @param fmi receives metrics information, can be null * @param needWidth true if the width of the run is needed * @return the signed width of the run based on the run direction; only valid if needWidth is true */ private float handleText( TextPaint wp, int start, int end, int contextStart, int contextEnd, boolean runIsRtl, Canvas c, float x, int top, int y, int bottom, FontMetricsInt fmi, boolean needWidth) { // Get metrics first (even for empty strings or "0" width runs) if (fmi != null) { /// M: new FontMetrics method for complex text support. expandMetricsFromPaint(fmi, wp, mText); } int runLen = end - start; // No need to do anything if the run width is "0" if (runLen == 0) { return 0f; } float ret = 0; int contextLen = contextEnd - contextStart; if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) { int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR; if (mCharsValid) { ret = wp.getTextRunAdvances(mChars, start, runLen, contextStart, contextLen, flags, null, 0); } else { int delta = mStart; ret = wp.getTextRunAdvances( mText, delta + start, delta + end, delta + contextStart, delta + contextEnd, flags, null, 0); } } if (c != null) { if (runIsRtl) { x -= ret; } if (wp.bgColor != 0) { int previousColor = wp.getColor(); Paint.Style previousStyle = wp.getStyle(); wp.setColor(wp.bgColor); wp.setStyle(Paint.Style.FILL); c.drawRect(x, top, x + ret, bottom, wp); wp.setStyle(previousStyle); wp.setColor(previousColor); } if (wp.underlineColor != 0) { // kStdUnderline_Offset = 1/9, defined in SkTextFormatParams.h float underlineTop = y + wp.baselineShift + (1.0f / 9.0f) * wp.getTextSize(); int previousColor = wp.getColor(); Paint.Style previousStyle = wp.getStyle(); boolean previousAntiAlias = wp.isAntiAlias(); wp.setStyle(Paint.Style.FILL); wp.setAntiAlias(true); wp.setColor(wp.underlineColor); c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThickness, wp); wp.setStyle(previousStyle); wp.setColor(previousColor); wp.setAntiAlias(previousAntiAlias); } drawTextRun(c, wp, start, end, contextStart, contextEnd, runIsRtl, x, y + wp.baselineShift); } return runIsRtl ? -ret : ret; }
public float getTextSize() { return baseTextPaint.getTextSize(); }
/** * Resize the text size with specified width and height * * @param width * @param height */ public void resizeText(int width, int height) { CharSequence text = getText(); // Do not resize if the view does not have dimensions or there is no // text // or if mTextSize has not been initialized if (text == null || text.length() == 0 || height <= 0 || width <= 0 || mTextSize == 0) { return; } // Get the text view's paint object TextPaint textPaint = getPaint(); // Store the current text size float oldTextSize = textPaint.getTextSize(); // If there is a max text size set, use the lesser of that and the // default text size float targetTextSize = mMaxTextSize > 0 ? Math.min(mTextSize, mMaxTextSize) : mTextSize; // Get the required text height int textHeight = getTextHeight(text, textPaint, width, targetTextSize); int textWidth = getTextWidth(text, textPaint, width, targetTextSize); int lineHeight = getTextHeight(text, textPaint, width * 10, targetTextSize); // Until we either fit within our text view or we had reached our min // text size, incrementally try smaller sizes while (((textHeight > height) || (textWidth > width) || (textHeight > lineHeight)) && targetTextSize > mMinTextSize) { targetTextSize = Math.max(targetTextSize - 2, mMinTextSize); textHeight = getTextHeight(text, textPaint, width, targetTextSize); textWidth = getTextWidth(text, textPaint, width, targetTextSize); lineHeight = getTextHeight(text, textPaint, width * 10, targetTextSize); } // If we had reached our minimum text size and still don't fit, append // an ellipsis if (mAddEllipsis && targetTextSize == mMinTextSize && textHeight > height) { // Draw using a static layout StaticLayout layout = new StaticLayout( text, textPaint, width, Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, false); layout.draw(sTextResizeCanvas); int lastLine = layout.getLineForVertical(height) - 1; int start = layout.getLineStart(lastLine); int end = layout.getLineEnd(lastLine); float lineWidth = layout.getLineWidth(lastLine); float ellipseWidth = textPaint.measureText(mEllipsis); // Trim characters off until we have enough room to draw the // ellipsis while (width < lineWidth + ellipseWidth) { lineWidth = textPaint.measureText(text.subSequence(start, --end + 1).toString()); } setText(text.subSequence(0, end) + mEllipsis); } // Some devices try to auto adjust line spacing, so force default line // spacing // and invalidate the layout as a side effect textPaint.setTextSize(targetTextSize); setLineSpacing(mSpacingAdd, mSpacingMult); // Notify the listener if registered if (mTextResizeListener != null) { mTextResizeListener.onTextResize(this, oldTextSize, targetTextSize); } // Reset force resize flag mNeedsResize = false; }
public int getTextSize() { return (int) textPaint.getTextSize(); }
public void build(MessageWireframe wireframe, int desiredWidth, StelsApplication application) { Logger.d(TAG, "Build layout start"); checkResources(application); senderPaint = initTextPaint(); senderPaint.setTypeface(FontController.loadTypeface(application, "regular")); senderPaint.setTextSize(bodyPaint.getTextSize()); senderPaint.setColor(0xff000000); forwardingPaint = initTextPaint(); forwardingPaint.setTypeface(FontController.loadTypeface(application, "light")); forwardingPaint.setTextSize(bodyPaint.getTextSize()); forwardingPaint.setColor(0xff000000); this.layoutDesiredWidth = desiredWidth; this.isOut = wireframe.message.isOut(); this.showState = isOut; this.isGroup = wireframe.message.getPeerType() == PeerType.PEER_CHAT && !isOut; if (isGroup) { User user = wireframe.senderUser; this.senderName = user.getDisplayName(); if (!wireframe.message.isForwarded()) { senderPaint.setColor( Placeholders.USER_PLACEHOLDERS_COLOR[ wireframe.message.getSenderId() % Placeholders.USER_PLACEHOLDERS_COLOR.length]); forwardingPaint.setColor( Placeholders.USER_PLACEHOLDERS_COLOR[ wireframe.message.getSenderId() % Placeholders.USER_PLACEHOLDERS_COLOR.length]); } } if (wireframe.message.isForwarded()) { isForwarded = true; this.forwarderName = wireframe.forwardUser.getDisplayName(); if (isOut) { forwardingPaint.setColor(0xff739f53); senderPaint.setColor(0xff739f53); } else { forwardingPaint.setColor(0xff4884cf); senderPaint.setColor(0xff4884cf); } } else { isForwarded = false; } if (isGroup) { User user = application.getEngine().getUser(wireframe.message.getSenderId()); this.senderName = user.getDisplayName(); } if (wireframe.message.isForwarded()) { isForwarded = true; this.forwarderName = wireframe.forwardUser.getDisplayName(); } else { isForwarded = false; } layoutDesiredWidth = desiredWidth; long start = SystemClock.uptimeMillis(); this.spannable = application .getEmojiProcessor() .processEmojiCompatMutable( wireframe.message.getMessage(), EmojiProcessor.CONFIGURATION_BUBBLES); // spannable = new SpannableString(wireframe.message.getMessage()); Logger.d(TAG, "Emoji processed in " + (SystemClock.uptimeMillis() - start) + " ms"); start = SystemClock.uptimeMillis(); Linkify.addLinks( this.spannable, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS | Linkify.EMAIL_ADDRESSES); fixLinks(spannable); Logger.d(TAG, "Added links in " + (SystemClock.uptimeMillis() - start) + " ms"); start = SystemClock.uptimeMillis(); layout = new StaticLayout( spannable, bodyPaint, desiredWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true); Logger.d(TAG, "Built base layout in " + (SystemClock.uptimeMillis() - start) + " ms"); if (layout.getLineCount() < 20) { int layoutTextWidth = 0; for (int i = 0; i < layout.getLineCount(); i++) { layoutTextWidth = (int) Math.max(layout.getLineWidth(i), layoutTextWidth); } if (layoutTextWidth < layout.getWidth() - px(10)) { layout = new StaticLayout( spannable, bodyPaint, layoutTextWidth + px(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true); } } layoutRealWidth = layout.getWidth(); timeWidth = (int) clockOutPaint.measureText(wireframe.date) + px((showState ? 23 : 0) + 6); if (layout.getLineCount() == 1) { boolean isLastRtl = layout.getParagraphDirection(0) == Layout.DIR_RIGHT_TO_LEFT; if (!isLastRtl && desiredWidth - layoutRealWidth > timeWidth) { layoutRealWidth += timeWidth; layoutHeight = layout.getHeight() + px(3); } else if (isLastRtl && desiredWidth - layout.getWidth() > timeWidth) { layoutRealWidth = layout.getWidth() + timeWidth; layoutHeight = layout.getHeight() + px(3); } else { if (isLastRtl) { layoutRealWidth = layout.getWidth(); } layoutHeight = layout.getHeight() + px(17); } } else { boolean isLastRtl = layout.getParagraphDirection(layout.getLineCount() - 1) == Layout.DIR_RIGHT_TO_LEFT; if (!isLastRtl && (desiredWidth - layout.getLineWidth(layout.getLineCount() - 1) > timeWidth)) { layoutRealWidth = (int) Math.max( layoutRealWidth, layout.getLineWidth(layout.getLineCount() - 1) + timeWidth); layoutHeight = layout.getHeight() + px(3); } else if (isLastRtl && (desiredWidth - layout.getWidth() > timeWidth)) { layoutRealWidth = (int) Math.max(layoutRealWidth, layout.getWidth() + timeWidth); layoutHeight = layout.getHeight() + px(3); } else { layoutHeight = layout.getHeight() + px(17); } } if (layoutRealWidth < timeWidth) { layoutRealWidth = timeWidth; } if (isForwarded) { layoutHeight += px(19) * 2; forwardOffset = (int) forwardingPaintBase.measureText("From "); layoutRealWidth = (int) Math.max(layoutRealWidth, forwardingPaintBase.measureText("Forwarded message")); forwarderNameMeasured = TextUtils.ellipsize( forwarderName, senderPaintBase, desiredWidth - forwardOffset, TextUtils.TruncateAt.END) .toString(); layoutRealWidth = (int) Math.max( layoutRealWidth, forwardOffset + senderPaintBase.measureText(forwarderNameMeasured)); } if (isGroup && !isOut && !isForwarded) { layoutHeight += px(19); senderNameMeasured = TextUtils.ellipsize(senderName, senderPaintBase, desiredWidth, TextUtils.TruncateAt.END) .toString(); int width = (int) senderPaintBase.measureText(senderNameMeasured); layoutRealWidth = Math.max(layoutRealWidth, width); } Logger.d(TAG, "Build layout end"); }
@Override protected void onDraw(Canvas canvas) { // Location x = getWidth() / 2; y = getHeight() / 2; int pos = (int) (textSize / 2); int framesPerSecond = 60; // Brushes Paint blueBrush = new Paint(Paint.ANTI_ALIAS_FLAG); blueBrush.setColor(mContext.getResources().getColor(R.color.sunshine_blue)); blueBrush.setStrokeWidth(3f); Paint whiteBrush = new Paint(Paint.ANTI_ALIAS_FLAG); whiteBrush.setColor(mContext.getResources().getColor(R.color.background_wind_speed)); whiteBrush.setStrokeWidth(3f); Paint redBrush = new Paint(Paint.ANTI_ALIAS_FLAG); redBrush.setColor(Color.RED); redBrush.setStrokeWidth(3f); TextPaint textPaint = new TextPaint(); textPaint.setColor(Color.YELLOW); textPaint.setFakeBoldText(true); textPaint.setStrokeWidth(2f); textPaint.setTextSize(textSize); textSize = textPaint.getTextSize(); // External Circle canvas.drawCircle(x, y, height / 2, blueBrush); // Internal Circle canvas.drawCircle(x, y, (height / 2) - textSize, whiteBrush); // Indicator Circle canvas.drawCircle(x, y, (height / 17), redBrush); mCanvas = canvas; mCanvas.save(); // Direction labels canvas.drawText(mContext.getString(R.string.north), x - pos, textSize, textPaint); canvas.drawText(mContext.getString(R.string.south), x - pos, y * 2 - 2, textPaint); canvas.drawText(mContext.getString(R.string.east), (x * 2) - textSize + 2, y + pos, textPaint); canvas.drawText(mContext.getString(R.string.west), textSize - (pos * 2), y + pos, textPaint); // Layers for rotated labels Canvas canNE = canvas; Canvas canNW = canvas; canNE.save(); canNW.save(); // Indicator setWindSpeedDirection(direction); canNE.rotate(45, x, y); canNE.drawText(mContext.getString(R.string.north_east), x - (pos * 2), textSize, textPaint); canNE.drawText(mContext.getString(R.string.south_west), x - (pos * 2), y * 2 - 2, textPaint); canNW.rotate(270, x, y); canNW.drawText(mContext.getString(R.string.north_west), x - (pos * 2), textSize, textPaint); canNW.drawText(mContext.getString(R.string.south_east), x - (pos * 2), y * 2 - 2, textPaint); canvas.restore(); if (!finishAnimation) { postInvalidateDelayed(1000 / framesPerSecond); } }