@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mDurationStringWidth = (int) mTextPaint.measureText(mDurationString); mTotalDurationStringWidth = (int) mTextPaint.measureText(mTotalDurationString); mTextAscent = (int) mTextPaint.ascent(); mTextDescent = (int) mTextPaint.descent(); }
/** * Returns the ascent of the text at start. This is used for scaling emoji. * * @param pos the line-relative position * @return the ascent of the text at start */ float ascent(int pos) { if (mSpanned == null) { return mPaint.ascent(); } pos += mStart; MetricAffectingSpan[] spans = mSpanned.getSpans(pos, pos + 1, MetricAffectingSpan.class); if (spans.length == 0) { return mPaint.ascent(); } TextPaint wp = mWorkPaint; wp.set(mPaint); for (MetricAffectingSpan span : spans) { span.updateMeasureState(wp); } return wp.ascent(); }
private void drawMonth(Canvas canvas) { final float x = mPaddedWidth / 2f; // Vertically centered within the month header height. final float lineHeight = mMonthPaint.ascent() + mMonthPaint.descent(); final float y = (mMonthHeight - lineHeight) / 2f; canvas.drawText(getTitle().toString(), x, y, mMonthPaint); }
private void initIfNecessary(TextPaint tp) { if (jumpAnimator != null) { return; } shift = (int) tp.ascent() / 2; jumpAnimator = ValueAnimator.ofInt(0, shift, 0); jumpAnimator.setDuration(loopDuration).setStartDelay(delay); jumpAnimator.setInterpolator(new JumpInterpolator(animatedRange)); jumpAnimator.setRepeatCount(ValueAnimator.INFINITE); jumpAnimator.setRepeatMode(ValueAnimator.RESTART); jumpAnimator.addUpdateListener(this); jumpAnimator.start(); }
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); float delta = Math.max(finishedStrokeWidth, unfinishedStrokeWidth); finishedOuterRect.set(delta, delta, getWidth() - delta, getHeight() - delta); unfinishedOuterRect.set(delta, delta, getWidth() - delta, getHeight() - delta); // float innerCircleRadius = (getWidth() - Math.min(finishedStrokeWidth, // unfinishedStrokeWidth) + Math.abs // (finishedStrokeWidth - unfinishedStrokeWidth)) / 2f; float innerCircleRadius = (getWidth() - delta) / 2; // Log.d(TAG, "width:" + getWidth()); // Log.d(TAG, "height:" + getHeight()); // Log.d(TAG, "R:" + innerCircleRadius); // Log.d(TAG, "finishedStrokeWidth:" + finishedStrokeWidth); // Log.d(TAG, "unfinishedStrokeWidth:" + unfinishedStrokeWidth); canvas.drawCircle(getWidth() / 2.0f, getHeight() / 2.0f, innerCircleRadius, innerCirclePaint); canvas.drawArc( finishedOuterRect, getStartingDegree(), getProgressAngle(), false, finishedPaint); canvas.drawArc( unfinishedOuterRect, getStartingDegree() + getProgressAngle(), 360 - getProgressAngle(), false, unfinishedPaint); String innerText = getInnerText(); if (!TextUtils.isEmpty(innerText)) { float innerTextHeight = innerTextPaint.descent() + innerTextPaint.ascent(); canvas.drawText( innerText, (getWidth() - innerTextPaint.measureText(innerText)) / 2, (getHeight() - innerTextHeight) / 2, innerTextPaint); } }
private void drawDaysOfWeek(Canvas canvas) { final TextPaint p = mDayOfWeekPaint; final int headerHeight = mMonthHeight; final int rowHeight = mDayOfWeekHeight; final int colWidth = mCellWidth; // Text is vertically centered within the day of week height. final float halfLineHeight = (p.ascent() + p.descent()) / 2f; final int rowCenter = headerHeight + rowHeight / 2; for (int col = 0; col < DAYS_IN_WEEK; col++) { final int colCenter = colWidth * col + colWidth / 2; final int colCenterRtl; if (isLayoutRtl()) { colCenterRtl = mPaddedWidth - colCenter; } else { colCenterRtl = colCenter; } final int dayOfWeek = (col + mWeekStart) % DAYS_IN_WEEK; final String label = getDayOfWeekLabel(dayOfWeek); canvas.drawText(label, colCenterRtl, rowCenter - halfLineHeight, p); } }
/** * Sets up the text and style properties for painting. Override this if you want to use a * different paint. */ @Override protected void initView() { super.initView(); if (!mInitialized) { Resources resources = getContext().getResources(); mShowDetailsInMonth = Utils.getConfigBool(getContext(), R.bool.show_details_in_month); TEXT_SIZE_EVENT_TITLE = resources.getInteger(R.integer.text_size_event_title); TEXT_SIZE_MONTH_NUMBER = resources.getInteger(R.integer.text_size_month_number); SIDE_PADDING_MONTH_NUMBER = resources.getInteger(R.integer.month_day_number_margin); CONFLICT_COLOR = resources.getColor(R.color.month_dna_conflict_time_color); EVENT_TEXT_COLOR = resources.getColor(R.color.calendar_event_text_color); if (mScale != 1) { TOP_PADDING_MONTH_NUMBER *= mScale; TOP_PADDING_WEEK_NUMBER *= mScale; SIDE_PADDING_MONTH_NUMBER *= mScale; SIDE_PADDING_WEEK_NUMBER *= mScale; SPACING_WEEK_NUMBER *= mScale; TEXT_SIZE_MONTH_NUMBER *= mScale; TEXT_SIZE_EVENT *= mScale; TEXT_SIZE_EVENT_TITLE *= mScale; TEXT_SIZE_MORE_EVENTS *= mScale; TEXT_SIZE_MONTH_NAME *= mScale; TEXT_SIZE_WEEK_NUM *= mScale; DAY_SEPARATOR_OUTER_WIDTH *= mScale; DAY_SEPARATOR_INNER_WIDTH *= mScale; DAY_SEPARATOR_VERTICAL_LENGTH *= mScale; DAY_SEPARATOR_VERTICAL_LENGHT_PORTRAIT *= mScale; EVENT_X_OFFSET_LANDSCAPE *= mScale; EVENT_Y_OFFSET_LANDSCAPE *= mScale; EVENT_Y_OFFSET_PORTRAIT *= mScale; EVENT_SQUARE_WIDTH *= mScale; EVENT_SQUARE_BORDER *= mScale; EVENT_LINE_PADDING *= mScale; EVENT_BOTTOM_PADDING *= mScale; EVENT_RIGHT_PADDING *= mScale; DNA_MARGIN *= mScale; DNA_WIDTH *= mScale; DNA_ALL_DAY_HEIGHT *= mScale; DNA_MIN_SEGMENT_HEIGHT *= mScale; DNA_SIDE_PADDING *= mScale; DEFAULT_EDGE_SPACING *= mScale; DNA_ALL_DAY_WIDTH *= mScale; TODAY_HIGHLIGHT_WIDTH *= mScale; } if (!mShowDetailsInMonth) { TOP_PADDING_MONTH_NUMBER += DNA_ALL_DAY_HEIGHT + DNA_MARGIN; } mInitialized = true; } mPadding = DEFAULT_EDGE_SPACING; loadColors(getContext()); // TODO modify paint properties depending on isMini mMonthNumPaint = new Paint(); mMonthNumPaint.setFakeBoldText(false); mMonthNumPaint.setAntiAlias(true); mMonthNumPaint.setTextSize(TEXT_SIZE_MONTH_NUMBER); mMonthNumPaint.setColor(mMonthNumColor); mMonthNumPaint.setStyle(Style.FILL); mMonthNumPaint.setTextAlign(Align.RIGHT); mMonthNumPaint.setTypeface(Typeface.DEFAULT); mMonthNumAscentHeight = (int) (-mMonthNumPaint.ascent() + 0.5f); mMonthNumHeight = (int) (mMonthNumPaint.descent() - mMonthNumPaint.ascent() + 0.5f); mEventPaint = new TextPaint(); mEventPaint.setFakeBoldText(true); mEventPaint.setAntiAlias(true); mEventPaint.setTextSize(TEXT_SIZE_EVENT_TITLE); mEventPaint.setColor(mMonthEventColor); mSolidBackgroundEventPaint = new TextPaint(mEventPaint); mSolidBackgroundEventPaint.setColor(EVENT_TEXT_COLOR); mFramedEventPaint = new TextPaint(mSolidBackgroundEventPaint); mDeclinedEventPaint = new TextPaint(); mDeclinedEventPaint.setFakeBoldText(true); mDeclinedEventPaint.setAntiAlias(true); mDeclinedEventPaint.setTextSize(TEXT_SIZE_EVENT_TITLE); mDeclinedEventPaint.setColor(mMonthDeclinedEventColor); mEventAscentHeight = (int) (-mEventPaint.ascent() + 0.5f); mEventHeight = (int) (mEventPaint.descent() - mEventPaint.ascent() + 0.5f); mEventExtrasPaint = new TextPaint(); mEventExtrasPaint.setFakeBoldText(false); mEventExtrasPaint.setAntiAlias(true); mEventExtrasPaint.setStrokeWidth(EVENT_SQUARE_BORDER); mEventExtrasPaint.setTextSize(TEXT_SIZE_EVENT); mEventExtrasPaint.setColor(mMonthEventExtraColor); mEventExtrasPaint.setStyle(Style.FILL); mEventExtrasPaint.setTextAlign(Align.LEFT); mExtrasHeight = (int) (mEventExtrasPaint.descent() - mEventExtrasPaint.ascent() + 0.5f); mExtrasAscentHeight = (int) (-mEventExtrasPaint.ascent() + 0.5f); mExtrasDescent = (int) (mEventExtrasPaint.descent() + 0.5f); mEventDeclinedExtrasPaint = new TextPaint(); mEventDeclinedExtrasPaint.setFakeBoldText(false); mEventDeclinedExtrasPaint.setAntiAlias(true); mEventDeclinedExtrasPaint.setStrokeWidth(EVENT_SQUARE_BORDER); mEventDeclinedExtrasPaint.setTextSize(TEXT_SIZE_EVENT); mEventDeclinedExtrasPaint.setColor(mMonthDeclinedExtrasColor); mEventDeclinedExtrasPaint.setStyle(Style.FILL); mEventDeclinedExtrasPaint.setTextAlign(Align.LEFT); mWeekNumPaint = new Paint(); mWeekNumPaint.setFakeBoldText(false); mWeekNumPaint.setAntiAlias(true); mWeekNumPaint.setTextSize(TEXT_SIZE_WEEK_NUM); mWeekNumPaint.setColor(mWeekNumColor); mWeekNumPaint.setStyle(Style.FILL); mWeekNumPaint.setTextAlign(Align.RIGHT); mWeekNumAscentHeight = (int) (-mWeekNumPaint.ascent() + 0.5f); mDNAAllDayPaint = new Paint(); mDNATimePaint = new Paint(); mDNATimePaint.setColor(mMonthBusyBitsBusyTimeColor); mDNATimePaint.setStyle(Style.FILL_AND_STROKE); mDNATimePaint.setStrokeWidth(DNA_WIDTH); mDNATimePaint.setAntiAlias(false); mDNAAllDayPaint.setColor(mMonthBusyBitsConflictTimeColor); mDNAAllDayPaint.setStyle(Style.FILL_AND_STROKE); mDNAAllDayPaint.setStrokeWidth(DNA_ALL_DAY_WIDTH); mDNAAllDayPaint.setAntiAlias(false); mEventSquarePaint = new Paint(); mEventSquarePaint.setStrokeWidth(EVENT_SQUARE_BORDER); mEventSquarePaint.setAntiAlias(false); if (DEBUG_LAYOUT) { Log.d("EXTRA", "mScale=" + mScale); Log.d( "EXTRA", "mMonthNumPaint ascent=" + mMonthNumPaint.ascent() + " descent=" + mMonthNumPaint.descent() + " int height=" + mMonthNumHeight); Log.d( "EXTRA", "mEventPaint ascent=" + mEventPaint.ascent() + " descent=" + mEventPaint.descent() + " int height=" + mEventHeight + " int ascent=" + mEventAscentHeight); Log.d( "EXTRA", "mEventExtrasPaint ascent=" + mEventExtrasPaint.ascent() + " descent=" + mEventExtrasPaint.descent() + " int height=" + mExtrasHeight); Log.d( "EXTRA", "mWeekNumPaint ascent=" + mWeekNumPaint.ascent() + " descent=" + mWeekNumPaint.descent()); } }
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int radius = 0; int shadowColor = changeColorAlpha(mShadowColor, MIN_SHADOW_COLOR_ALPHA); long elapsed = System.currentTimeMillis() - mStartTime; switch (mState) { case StateNormal: shadowColor = changeColorAlpha(mShadowColor, MIN_SHADOW_COLOR_ALPHA); break; case StateTouchDown: ripplePaint.setAlpha(255); if (elapsed < ANIMATION_DURATION) { radius = Math.round(elapsed * getWidth() / 2 / ANIMATION_DURATION); float shadowAlpha = (MAX_SHADOW_COLOR_ALPHA - MIN_SHADOW_COLOR_ALPHA) * elapsed / ANIMATION_DURATION + MIN_SHADOW_COLOR_ALPHA; shadowColor = changeColorAlpha(mShadowColor, shadowAlpha); } else { radius = getWidth() / 2; shadowColor = changeColorAlpha(mShadowColor, MAX_SHADOW_COLOR_ALPHA); } postInvalidate(); break; case StateTouchUp: if (elapsed < ANIMATION_DURATION) { int alpha = Math.round((ANIMATION_DURATION - elapsed) * 255 / ANIMATION_DURATION); ripplePaint.setAlpha(alpha); radius = getWidth() / 2 + Math.round(elapsed * getWidth() / 2 / ANIMATION_DURATION); float shadowAlpha = (MAX_SHADOW_COLOR_ALPHA - MIN_SHADOW_COLOR_ALPHA) * (ANIMATION_DURATION - elapsed) / ANIMATION_DURATION + MIN_SHADOW_COLOR_ALPHA; shadowColor = changeColorAlpha(mShadowColor, shadowAlpha); } else { mState = StateNormal; radius = 0; ripplePaint.setAlpha(0); shadowColor = changeColorAlpha(mShadowColor, MIN_SHADOW_COLOR_ALPHA); } postInvalidate(); break; } backgroundPaint.setShadowLayer(mShadowRadius, mShadowOffsetX, mShadowOffsetY, shadowColor); canvas.drawRoundRect(getRectF(), mCornerRadius, mCornerRadius, backgroundPaint); canvas.save(); if (mState == StateTouchDown || mState == StateTouchUp) { if (rippleClipPath == null) { rippleClipPath = new Path(); rippleClipPath.addRoundRect(getRectF(), mCornerRadius, mCornerRadius, Path.Direction.CW); } canvas.clipPath(rippleClipPath); } canvas.drawCircle(mTouchPoint.x, mTouchPoint.y, radius, ripplePaint); canvas.restore(); if (mText != null && mText.length() > 0) { int y = (int) (getHeight() / 2 - ((textPaint.descent() + textPaint.ascent()) / 2)); canvas.drawText(mText.toString(), getWidth() / 2, y, textPaint); } }
/** Draws the month days. */ private void drawDays(Canvas canvas) { final TextPaint p = mDayPaint; final int headerHeight = mMonthHeight + mDayOfWeekHeight; final int rowHeight = mDayHeight; final int colWidth = mCellWidth; // Text is vertically centered within the row height. final float halfLineHeight = (p.ascent() + p.descent()) / 2f; int rowCenter = headerHeight + rowHeight / 2; for (int day = 1, col = findDayOffset(); day <= mDaysInMonth; day++) { final int colCenter = colWidth * col + colWidth / 2; final int colCenterRtl; if (isLayoutRtl()) { colCenterRtl = mPaddedWidth - colCenter; } else { colCenterRtl = colCenter; } int stateMask = 0; final boolean isDayEnabled = isDayEnabled(day); if (isDayEnabled) { stateMask |= StateSet.VIEW_STATE_ENABLED; } final boolean isDayActivated = mActivatedDay == day; if (isDayActivated) { stateMask |= StateSet.VIEW_STATE_ACTIVATED; // Adjust the circle to be centered on the row. canvas.drawCircle(colCenterRtl, rowCenter, mDaySelectorRadius, mDaySelectorPaint); } else if (mTouchedItem == day) { stateMask |= StateSet.VIEW_STATE_PRESSED; if (isDayEnabled) { // Adjust the circle to be centered on the row. canvas.drawCircle(colCenterRtl, rowCenter, mDaySelectorRadius, mDayHighlightPaint); } } final boolean isDayToday = mToday == day; final int dayTextColor; if (isDayToday && !isDayActivated) { dayTextColor = mDaySelectorPaint.getColor(); } else { final int[] stateSet = StateSet.get(stateMask); dayTextColor = mDayTextColor.getColorForState(stateSet, 0); } p.setColor(dayTextColor); canvas.drawText(mDayFormatter.format(day), colCenterRtl, rowCenter - halfLineHeight, p); col++; if (col == DAYS_IN_WEEK) { col = 0; rowCenter += rowHeight; } } }
@Override public void updateDrawState(@NonNull TextPaint tp) { initIfNecessary(tp.ascent()); tp.baselineShift = shift; }