Java tutorial
/** * Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0/ * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.amazon.android.ui.widget; import com.amazon.utils.R; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; import android.support.v4.content.ContextCompat; import android.text.Layout; import android.util.AttributeSet; import android.widget.TextView; import uk.co.chrisjenx.calligraphy.CalligraphyConfig; import uk.co.chrisjenx.calligraphy.CalligraphyUtils; /** * The default text view for the read dialog. * <p> * Fades the text at top and bottom to hint when scrolling is available and makes sure it fades * text, not just empty lines. */ public class ReadTextView extends TextView { /** * Defines the percentage of a page that the system will scroll when receive a Up/Down event * <p> * Set to 18% this was determined with inspection with the current size and font size to be * two lines of text. A better solution would be to get the current height and inspect * the text metrics and calculate dynamically. */ private static final float MAX_SCROLL_AMOUNT = 0.18f; private TextView mText; private ScrollViewPlus mScrollView; /** * {@inheritDoc} */ public ReadTextView(final Context context) { super(context); } /** * {@inheritDoc} */ public ReadTextView(final Context context, final AttributeSet attrs, final int defStyle) { super(context, attrs, defStyle); } /** * {@inheritDoc} */ public ReadTextView(final Context context, final AttributeSet attrs) { super(context, attrs); } /** * {@inheritDoc} */ @Override protected void onFinishInflate() { super.onFinishInflate(); mText = (TextView) findViewById(R.id.txt); // Font needs to be applied since this was created dynamically. CalligraphyUtils.applyFontToTextView(getContext(), mText, CalligraphyConfig.get(), null); mText.setTextColor(ContextCompat.getColor(getContext(), R.color.primary_text)); } /** * {@inheritDoc} */ @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (mText != null && mText.getParent() != null && mText.getParent() instanceof ScrollViewPlus) { // For some reason setScrollbarFadingEnabled is not working, // hence adding very long duration before the scroll bar starts fading. mScrollView = (ScrollViewPlus) mText.getParent(); mScrollView.setMaxScrollAmount(MAX_SCROLL_AMOUNT); mScrollView.setScrollBarFadeDuration(500000); mScrollView.setScrollBarStyle(SCROLLBARS_OUTSIDE_INSET); mScrollView.setPadding(14, 0, 14, 0); } } /** * {@inheritDoc} */ @Override protected void onDraw(final Canvas canvas) { // Update the gradient each time the text is drawn. updateGradient(); super.onDraw(canvas); } /** * Draw a gradient on the text so that the bottom and top line have a faded effect if the user * can scroll in that direction. */ private void updateGradient() { if (mText == null || mScrollView == null) { return; } final Layout layout = mText.getLayout(); assert layout != null; final Rect bounds = new Rect(); getTextBounds(bounds); final int topLine = topVisibleLineOfText(layout, bounds); final int bottomLine = bottomVisibleLineOfText(layout, bounds); final int fullHeight = layout.getHeight(); if (fullHeight > 0) { final float bottomLineHeight = layout.getLineBottom(bottomLine) - layout.getLineTop(bottomLine); final float topLineHeight = layout.getLineBottom(topLine) - layout.getLineTop(topLine); this.setFadingEdgeLength((int) Math.max(topLineHeight, bottomLineHeight)); } } /** * Which line in the layout is the top visible line. * * @param layout Calculated text layout. * @param bounds Visible bounds in the coordinates of the TextView and layout. * @return The top visible line. */ private int topVisibleLineOfText(final Layout layout, final Rect bounds) { final int lineCount = layout.getLineCount(); for (int lineNum = 0; lineNum < lineCount; lineNum++) { final int top = layout.getLineTop(lineNum); if (top >= bounds.top && top <= bounds.bottom) { return lineNum; } } return lineCount; } /** * Which line in the layout is the bottom visible line. * * @param layout Calculated text layout. * @param bounds Visible bounds in the coordinates of the TextView and layout. * @return The bottom visible line */ private int bottomVisibleLineOfText(final Layout layout, final Rect bounds) { final int lineCount = layout.getLineCount(); for (int lineNum = lineCount - 1; lineNum >= 0; lineNum--) { final int bottom = layout.getLineBottom(lineNum); if (bottom >= bounds.top && bottom <= bounds.bottom) { return lineNum; } } return 0; } /** * The out Rect will contain the visible area of the scrolled mText in mText coordinates * * @param outRect The outer rectangle. */ private void getTextBounds(final Rect outRect) { mScrollView.getDrawingRect(outRect); mScrollView.offsetRectIntoDescendantCoords(mText, outRect); } }