Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import android.annotation.TargetApi;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.DrawFilter;
- import android.graphics.Matrix;
- import android.graphics.Paint;
- import android.graphics.Path;
- import android.graphics.Picture;
- import android.graphics.PorterDuff;
- import android.graphics.Rect;
- import android.graphics.RectF;
- import android.graphics.Region;
- import android.os.Build;
- import android.support.annotation.NonNull;
- import android.support.annotation.Nullable;
- import android.support.annotation.RequiresApi;
- import android.support.design.widget.TextInputLayout;
- import android.util.AttributeSet;
- import java.lang.reflect.Field;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- /**
- * A TextInputLayout that draws multiline text.
- * <p>
- * api18+ is required, because versions below use its own texture for drawing, and it calls
- * {@code new Canvas()} which is too difficult to git rid of.
- */
- @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
- public class MultilineHintTextInputLayout extends TextInputLayout {
- private static final String TAG = "MlHintTextInputLayout";
- public MultilineHintTextInputLayout(Context context) {
- super(context);
- init();
- }
- public MultilineHintTextInputLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- init();
- }
- public MultilineHintTextInputLayout(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- init();
- }
- private CanvasWrapper mCanvasWrapper = new CanvasWrapper();
- private Object mCollapsingTextHelper = null;
- private Method mCollapsingTextHelper_draw = null;
- private Field mHintEnabledField = null;
- private Field mCollapsingTextHelper_mText = null;
- private Field mCollapsingTextHelper_mTextToDraw = null;
- private void init() {
- mCanvasWrapper.setCanvas(null);
- try {
- mHintEnabledField = TextInputLayout.class.getDeclaredField("mHintEnabled");
- mHintEnabledField.setAccessible(true);
- final Field field = TextInputLayout.class.getDeclaredField("mCollapsingTextHelper");
- field.setAccessible(true);
- mCollapsingTextHelper = field.get(this);
- final Class klassCollapsingTextHelper = Class.forName("android.support.design.widget.CollapsingTextHelper");
- //noinspection unchecked
- mCollapsingTextHelper_draw = klassCollapsingTextHelper.getDeclaredMethod("draw", Canvas.class);
- mCollapsingTextHelper_mText = klassCollapsingTextHelper.getDeclaredField("mText");
- mCollapsingTextHelper_mTextToDraw = klassCollapsingTextHelper.getDeclaredField("mTextToDraw");
- mCollapsingTextHelper_mText.setAccessible(true);
- mCollapsingTextHelper_mTextToDraw.setAccessible(true);
- } catch (IllegalAccessException | NoSuchFieldException | NoSuchMethodException | ClassNotFoundException ex) {
- mCanvasWrapper = null;
- mCollapsingTextHelper = null;
- mCollapsingTextHelper_draw = null;
- mHintEnabledField = null;
- mCollapsingTextHelper_mText = null;
- mCollapsingTextHelper_mTextToDraw = null;
- }
- }
- @Override
- public void draw(Canvas canvas) {
- if (mCollapsingTextHelper == null) {
- super.draw(canvas);
- return;
- }
- try {
- final boolean hint = (boolean) mHintEnabledField.get(this);
- if (hint)
- mHintEnabledField.set(this, false);
- super.draw(canvas);
- if (hint) {
- mCollapsingTextHelper_mTextToDraw.set(mCollapsingTextHelper, mCollapsingTextHelper_mText.get(mCollapsingTextHelper));
- mHintEnabledField.set(this, true);
- mCanvasWrapper.setCanvas(canvas);
- mCollapsingTextHelper_draw.invoke(mCollapsingTextHelper, mCanvasWrapper);
- mCanvasWrapper.setCanvas(null); // do not hold a ref
- }
- } catch (IllegalAccessException | InvocationTargetException ex) {
- mCanvasWrapper = null;
- mCollapsingTextHelper = null;
- mCollapsingTextHelper_draw = null;
- mHintEnabledField = null;
- mCollapsingTextHelper_mText = null;
- mCollapsingTextHelper_mTextToDraw = null;
- // failed, try again with super only.
- postInvalidate();
- }
- }
- private static final class CanvasWrapper extends Canvas {
- private boolean mConstructed = false;
- // this dummy canvas is just for super's c-tor...
- private Canvas mCanvas = null;
- CanvasWrapper() {
- super();
- mConstructed = true;
- }
- void setCanvas(Canvas canvas) {
- mCanvas = canvas;
- }
- private int nextNewLineAt(@NonNull CharSequence text, int start, int end) {
- while (start < end) {
- if (text.charAt(start) == '\n')
- return start;
- ++start;
- }
- return end;
- }
- // only this one is used
- @Override
- public void drawText(@NonNull CharSequence text, int start, int end, float x, float y, @NonNull Paint paint) {
- // Log.d(TAG, "drawText(): size = " + paint.measureText(text, start, end) + ", text = \"" + text + "\"");
- final float spacing = paint.getFontSpacing();
- while (start < end) {
- final int newline = nextNewLineAt(text, start, end);
- // Log.d(TAG, "drawText(): y = " + y + ", size = " + paint.measureText(text, start, end) + ", subSequence = \"" + text.subSequence(start, end) + "\"");
- mCanvas.drawText(text, start, newline, x, y, paint);
- y += spacing;
- start = newline + 1;
- }
- }
- @Override
- public boolean isHardwareAccelerated() {
- return mConstructed ? mCanvas.isHardwareAccelerated() : super.isHardwareAccelerated();
- }
- @Override
- public void setBitmap(@Nullable Bitmap bitmap) {
- mCanvas.setBitmap(bitmap);
- }
- @Override
- public boolean isOpaque() {
- return mCanvas.isOpaque();
- }
- @Override
- public int getWidth() {
- return mCanvas.getWidth();
- }
- @Override
- public int getHeight() {
- return mCanvas.getHeight();
- }
- @Override
- public int getDensity() {
- return mCanvas.getDensity();
- }
- @Override
- public void setDensity(int density) {
- mCanvas.setDensity(density);
- }
- @Override
- public int getMaximumBitmapWidth() {
- return mCanvas.getMaximumBitmapWidth();
- }
- @Override
- public int getMaximumBitmapHeight() {
- return mCanvas.getMaximumBitmapHeight();
- }
- @Override
- public int save() {
- return mCanvas.save();
- }
- @Override
- public int save(int saveFlags) {
- return mCanvas.save(saveFlags);
- }
- @Override
- public int saveLayer(@Nullable RectF bounds, @Nullable Paint paint, int saveFlags) {
- return mCanvas.saveLayer(bounds, paint, saveFlags);
- }
- @Override
- public int saveLayer(@Nullable RectF bounds, @Nullable Paint paint) {
- return mCanvas.saveLayer(bounds, paint);
- }
- @Override
- public int saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint, int saveFlags) {
- return mCanvas.saveLayer(left, top, right, bottom, paint, saveFlags);
- }
- @Override
- public int saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint) {
- return mCanvas.saveLayer(left, top, right, bottom, paint);
- }
- @Override
- public int saveLayerAlpha(@Nullable RectF bounds, int alpha, int saveFlags) {
- return mCanvas.saveLayerAlpha(bounds, alpha, saveFlags);
- }
- @Override
- public int saveLayerAlpha(@Nullable RectF bounds, int alpha) {
- return mCanvas.saveLayerAlpha(bounds, alpha);
- }
- @Override
- public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha, int saveFlags) {
- return mCanvas.saveLayerAlpha(left, top, right, bottom, alpha, saveFlags);
- }
- @Override
- public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha) {
- return mCanvas.saveLayerAlpha(left, top, right, bottom, alpha);
- }
- @Override
- public void restore() {
- mCanvas.restore();
- }
- @Override
- public int getSaveCount() {
- return mCanvas.getSaveCount();
- }
- @Override
- public void restoreToCount(int saveCount) {
- mCanvas.restoreToCount(saveCount);
- }
- @Override
- public void translate(float dx, float dy) {
- mCanvas.translate(dx, dy);
- }
- @Override
- public void scale(float sx, float sy) {
- mCanvas.scale(sx, sy);
- }
- @Override
- public void rotate(float degrees) {
- mCanvas.rotate(degrees);
- }
- @Override
- public void skew(float sx, float sy) {
- mCanvas.skew(sx, sy);
- }
- @Override
- public void concat(@Nullable Matrix matrix) {
- mCanvas.concat(matrix);
- }
- @Override
- public void setMatrix(@Nullable Matrix matrix) {
- mCanvas.setMatrix(matrix);
- }
- @Override
- @Deprecated
- public void getMatrix(@NonNull Matrix ctm) {
- mCanvas.getMatrix(ctm);
- }
- @Override
- public boolean clipRect(@NonNull RectF rect, @NonNull Region.Op op) {
- return mCanvas.clipRect(rect, op);
- }
- @Override
- public boolean clipRect(@NonNull Rect rect, @NonNull Region.Op op) {
- return mCanvas.clipRect(rect, op);
- }
- @Override
- public boolean clipRect(@NonNull RectF rect) {
- return mCanvas.clipRect(rect);
- }
- @Override
- public boolean clipRect(@NonNull Rect rect) {
- return mCanvas.clipRect(rect);
- }
- @Override
- public boolean clipRect(float left, float top, float right, float bottom, @NonNull Region.Op op) {
- return mCanvas.clipRect(left, top, right, bottom, op);
- }
- @Override
- public boolean clipRect(float left, float top, float right, float bottom) {
- return mCanvas.clipRect(left, top, right, bottom);
- }
- @Override
- public boolean clipRect(int left, int top, int right, int bottom) {
- return mCanvas.clipRect(left, top, right, bottom);
- }
- @Override
- public boolean clipPath(@NonNull Path path, @NonNull Region.Op op) {
- return mCanvas.clipPath(path, op);
- }
- @Override
- public boolean clipPath(@NonNull Path path) {
- return mCanvas.clipPath(path);
- }
- @Override
- @Deprecated
- public boolean clipRegion(@NonNull Region region, @NonNull Region.Op op) {
- return mCanvas.clipRegion(region, op);
- }
- @Override
- @Deprecated
- public boolean clipRegion(@NonNull Region region) {
- return mCanvas.clipRegion(region);
- }
- @Nullable
- @Override
- public DrawFilter getDrawFilter() {
- return mCanvas.getDrawFilter();
- }
- @Override
- public void setDrawFilter(@Nullable DrawFilter filter) {
- mCanvas.setDrawFilter(filter);
- }
- @Override
- public boolean quickReject(@NonNull RectF rect, @NonNull EdgeType type) {
- return mCanvas.quickReject(rect, type);
- }
- @Override
- public boolean quickReject(@NonNull Path path, @NonNull EdgeType type) {
- return mCanvas.quickReject(path, type);
- }
- @Override
- public boolean quickReject(float left, float top, float right, float bottom, @NonNull EdgeType type) {
- return mCanvas.quickReject(left, top, right, bottom, type);
- }
- @Override
- public boolean getClipBounds(@Nullable Rect bounds) {
- return mCanvas.getClipBounds(bounds);
- }
- @Override
- public void drawRGB(int r, int g, int b) {
- mCanvas.drawRGB(r, g, b);
- }
- @Override
- public void drawARGB(int a, int r, int g, int b) {
- mCanvas.drawARGB(a, r, g, b);
- }
- @Override
- public void drawColor(int color) {
- mCanvas.drawColor(color);
- }
- @Override
- public void drawColor(int color, @NonNull PorterDuff.Mode mode) {
- mCanvas.drawColor(color, mode);
- }
- @Override
- public void drawPaint(@NonNull Paint paint) {
- mCanvas.drawPaint(paint);
- }
- @Override
- public void drawPoints(float[] pts, int offset, int count, @NonNull Paint paint) {
- mCanvas.drawPoints(pts, offset, count, paint);
- }
- @Override
- public void drawPoints(@NonNull float[] pts, @NonNull Paint paint) {
- mCanvas.drawPoints(pts, paint);
- }
- @Override
- public void drawPoint(float x, float y, @NonNull Paint paint) {
- mCanvas.drawPoint(x, y, paint);
- }
- @Override
- public void drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint) {
- mCanvas.drawLine(startX, startY, stopX, stopY, paint);
- }
- @Override
- public void drawLines(@NonNull float[] pts, int offset, int count, @NonNull Paint paint) {
- mCanvas.drawLines(pts, offset, count, paint);
- }
- @Override
- public void drawLines(@NonNull float[] pts, @NonNull Paint paint) {
- mCanvas.drawLines(pts, paint);
- }
- @Override
- public void drawRect(@NonNull RectF rect, @NonNull Paint paint) {
- mCanvas.drawRect(rect, paint);
- }
- @Override
- public void drawRect(@NonNull Rect r, @NonNull Paint paint) {
- mCanvas.drawRect(r, paint);
- }
- @Override
- public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) {
- mCanvas.drawRect(left, top, right, bottom, paint);
- }
- @Override
- public void drawOval(@NonNull RectF oval, @NonNull Paint paint) {
- mCanvas.drawOval(oval, paint);
- }
- @Override
- public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) {
- mCanvas.drawOval(left, top, right, bottom, paint);
- }
- @Override
- public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) {
- mCanvas.drawCircle(cx, cy, radius, paint);
- }
- @Override
- public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint) {
- mCanvas.drawArc(oval, startAngle, sweepAngle, useCenter, paint);
- }
- @Override
- public void drawArc(float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean useCenter, @NonNull Paint paint) {
- mCanvas.drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint);
- }
- @Override
- public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) {
- mCanvas.drawRoundRect(rect, rx, ry, paint);
- }
- @Override
- public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, @NonNull Paint paint) {
- mCanvas.drawRoundRect(left, top, right, bottom, rx, ry, paint);
- }
- @Override
- public void drawPath(@NonNull Path path, @NonNull Paint paint) {
- mCanvas.drawPath(path, paint);
- }
- @Override
- public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
- mCanvas.drawBitmap(bitmap, left, top, paint);
- }
- @Override
- public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst, @Nullable Paint paint) {
- mCanvas.drawBitmap(bitmap, src, dst, paint);
- }
- @Override
- public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst, @Nullable Paint paint) {
- mCanvas.drawBitmap(bitmap, src, dst, paint);
- }
- @Override
- @Deprecated
- public void drawBitmap(@NonNull int[] colors, int offset, int stride, float x, float y, int width, int height, boolean hasAlpha, @Nullable Paint paint) {
- mCanvas.drawBitmap(colors, offset, stride, x, y, width, height, hasAlpha, paint);
- }
- @Override
- @Deprecated
- public void drawBitmap(@NonNull int[] colors, int offset, int stride, int x, int y, int width, int height, boolean hasAlpha, @Nullable Paint paint) {
- mCanvas.drawBitmap(colors, offset, stride, x, y, width, height, hasAlpha, paint);
- }
- @Override
- public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
- mCanvas.drawBitmap(bitmap, matrix, paint);
- }
- @Override
- public void drawBitmapMesh(@NonNull Bitmap bitmap, int meshWidth, int meshHeight, @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset, @Nullable Paint paint) {
- mCanvas.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint);
- }
- @Override
- public void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts, int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors, int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount, @NonNull Paint paint) {
- mCanvas.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, colors, colorOffset, indices, indexOffset, indexCount, paint);
- }
- @Override
- public void drawText(@NonNull char[] text, int index, int count, float x, float y, @NonNull Paint paint) {
- mCanvas.drawText(text, index, count, x, y, paint);
- }
- @Override
- public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
- mCanvas.drawText(text, x, y, paint);
- }
- @Override
- public void drawText(@NonNull String text, int start, int end, float x, float y, @NonNull Paint paint) {
- mCanvas.drawText(text, start, end, x, y, paint);
- }
- @TargetApi(Build.VERSION_CODES.M)
- @Override
- public void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex, int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint) {
- mCanvas.drawTextRun(text, index, count, contextIndex, contextCount, x, y, isRtl, paint);
- }
- @TargetApi(Build.VERSION_CODES.M)
- @Override
- public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart, int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) {
- mCanvas.drawTextRun(text, start, end, contextStart, contextEnd, x, y, isRtl, paint);
- }
- @Override
- @Deprecated
- public void drawPosText(@NonNull char[] text, int index, int count, @NonNull float[] pos, @NonNull Paint paint) {
- mCanvas.drawPosText(text, index, count, pos, paint);
- }
- @Override
- @Deprecated
- public void drawPosText(@NonNull String text, @NonNull float[] pos, @NonNull Paint paint) {
- mCanvas.drawPosText(text, pos, paint);
- }
- @Override
- public void drawTextOnPath(@NonNull char[] text, int index, int count, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint) {
- mCanvas.drawTextOnPath(text, index, count, path, hOffset, vOffset, paint);
- }
- @Override
- public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset, float vOffset, @NonNull Paint paint) {
- mCanvas.drawTextOnPath(text, path, hOffset, vOffset, paint);
- }
- @Override
- public void drawPicture(@NonNull Picture picture) {
- mCanvas.drawPicture(picture);
- }
- @Override
- public void drawPicture(@NonNull Picture picture, @NonNull RectF dst) {
- mCanvas.drawPicture(picture, dst);
- }
- @Override
- public void drawPicture(@NonNull Picture picture, @NonNull Rect dst) {
- mCanvas.drawPicture(picture, dst);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement