Нежелательное дополнение в таможенном Представлении с AutoresizeTextView на некоторых устройствах

Я решил свою предыдущую проблему здесь:

не Может установить силу тяжести с setGravity вертикально программно. Действительно ли это - ошибка андроида или особенность?

В основном у меня есть пользовательская кнопка с AutoResizeTextView в нем. Я хочу оживить кнопку и сосредоточить textview вертикально. Я решил его, Имея размеры и используя расположение и onLayout методы. Это хорошо работает на большинстве устройств.

Но на некоторых устройствах есть дополнительное дополнение выше текста в AutoResizeTextView, что я не могу удалить во всяком случае. Устройствами, ведущими себя ужасно, является Kindle Fire и Samsung Galaxy Tab2 7. Расположение в порядке на Nook Color на Motorola Xoom и на моем Motorola Defy (CyanogenMod 10).

Я создал типовой проект продемонстрировать проблему. Это включает 3 класса и файл расположения:

activity_main.xml:





<button
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_above="@+id/textView1"
    android:layout_alignRight="@+id/textView1"
    android:layout_marginBottom="46dp"
    android:layout_marginRight="54dp"
    android:text="Button" />



Измененный AutoResizeTextView.java:

package herrbert74.artvsample;

import android.content.Context;
import android.graphics.Canvas;
import android.text.Layout.Alignment;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;

/**
* Text view that auto adjusts text size to fit within the view. If the text
* size equals the minimum text size and still does not fit, append with an
* ellipsis.
* 
* @author Chase Colburn
* @since Apr 4, 2011
*/
public class AutoResizeTextView extends TextView {

// Minimum text size for this text view
public static final float MIN_TEXT_SIZE = 10;

// Interface for resize notifications
public interface OnTextResizeListener {
    public void onTextResize(TextView textView, float oldSize, float newSize);
}

// Off screen canvas for text size rendering
private static final Canvas sTextResizeCanvas = new Canvas();

// Our ellipse string
private static final String mEllipsis = "...";

// Registered resize listener
private OnTextResizeListener mTextResizeListener;

// Flag for text and/or size changes to force a resize
private boolean mNeedsResize = false;

// Text size that is set from code. This acts as a starting point for
// resizing
private float mTextSize;

// Temporary upper bounds on the starting text size
private float mMaxTextSize = 0;

// Lower bounds for text size
private float mMinTextSize = MIN_TEXT_SIZE;

// Text view line spacing multiplier
private float mSpacingMult = 1.0f;

// Text view additional line spacing
private float mSpacingAdd = 0.0f;

// Add ellipsis to text that overflows at the smallest text size
private boolean mAddEllipsis = true;

// Default constructor override
public AutoResizeTextView(Context context) {
    this(context, null);
}

// Default constructor when inflating from xml file
public AutoResizeTextView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

// Default constructor override
public AutoResizeTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    mTextSize = getTextSize();
}

/**
 * When text changes, set the force resize flag to true and reset the text
 * size.
 */
@Override
protected void onTextChanged(final CharSequence text, final int start,
        final int before, final int after) {
    mNeedsResize = true;
   //Since this view may be reused, it is good to reset the text size
    resetTextSize();
}

/**
 * If the text view size changed, set the force resize flag to true
 */
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    if (w != oldw || h != oldh) {
        mNeedsResize = true;
    }
}

/**
 * Register listener to receive resize notifications
 * 
 * @param listener
 */
public void setOnResizeListener(OnTextResizeListener listener) {
    mTextResizeListener = listener;
}

/**
 * Override the set text size to update our internal reference values
 */
@Override
public void setTextSize(float size) {
    super.setTextSize(size);
    mTextSize = getTextSize();

}

/**
 * Override the set text size to update our internal reference values
 */
@Override
public void setTextSize(int unit, float size) {
    super.setTextSize(unit, size);
    mTextSize = getTextSize();

}

/**
 * Override the set line spacing to update our internal reference values
 */
@Override
public void setLineSpacing(float add, float mult) {
    super.setLineSpacing(add, mult);
    mSpacingMult = mult;
    mSpacingAdd = add;
}

/**
 * Set the upper text size limit and invalidate the view
 * 
 * @param maxTextSize
 */
public void setMaxTextSize(float maxTextSize) {
    mMaxTextSize = maxTextSize;
    requestLayout();
    invalidate();
}

/**
 * Return upper text size limit
 * 
 * @return
 */
public float getMaxTextSize() {
    return mMaxTextSize;
}

/**
 * Set the lower text size limit and invalidate the view
 * 
 * @param minTextSize
 */
public void setMinTextSize(float minTextSize) {
    mMinTextSize = minTextSize;
    requestLayout();
    invalidate();
}

/**
 * Return lower text size limit
 * 
 * @return
 */
public float getMinTextSize() {
    return mMinTextSize;
}

/**
 * Set flag to add ellipsis to text that overflows at the smallest text size
 * 
 * @param addEllipsis
 */
public void setAddEllipsis(boolean addEllipsis) {
    mAddEllipsis = addEllipsis;
}

/**
 * Return flag to add ellipsis to text that overflows at the smallest text
 * size
 * 
 * @return
 */
public boolean getAddEllipsis() {
    return mAddEllipsis;
}

/**
 * Reset the text to the original size
 */
public void resetTextSize() {
    //ZBertalan:changed to mMaxTextSize
    super.setTextSize(TypedValue.COMPLEX_UNIT_PX, mMaxTextSize);
    //ZBertalan:swapped them
    //mMaxTextSize = mTextSize;
    mTextSize = mMaxTextSize;
}

/**
 * Resize text after measuring ZBertalan: I commented this out because I
 * need to resize the text in onMeasure, to layout the textview based on
 * it's size
 */
/*
 * @Override protected void onLayout(boolean changed, int left, int top, int
 * right, int bottom) { if(changed || mNeedsResize) { int widthLimit =
 * (right - left) - getCompoundPaddingLeft() - getCompoundPaddingRight();
 * int heightLimit = (bottom - top) - getCompoundPaddingBottom() -
 * getCompoundPaddingTop(); //og.d("AnswerView", "inside ARTV.onLayout() " +
 * ); resizeText(widthLimit, heightLimit); } super.onLayout(changed, left,
 * top, right, bottom); }
 */

/**
 * @author zsbertalan Moved some code here to resize the textview here and
 *         position it based on it's new size
 */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int newWidth = MeasureSpec.getSize(widthMeasureSpec);
    int newHeight = MeasureSpec.getSize(heightMeasureSpec);

    resizeText(newWidth, newHeight);

    TextPaint p = getPaint();
    newHeight = getTextHeight(getText(), p, newWidth, getTextSize());

    this.setMeasuredDimension(newWidth, newHeight);
}

/**
 * Resize the text size with default width and height
 */
public void resizeText() {
    int heightLimit = getHeight() - getPaddingBottom() - getPaddingTop();
    int widthLimit = getWidth() - getPaddingLeft() - getPaddingRight();
    resizeText(widthLimit, heightLimit);
}

/**
 * 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
    //ZBertalan: Bollocks. I changed to use mMaxTextSize all the time
    //float targetTextSize = mMaxTextSize > 0 ? Math.min(mTextSize, mMaxTextSize) : mTextSize;
    float targetTextSize = mMaxTextSize;

   //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
        TextPaint paint = new TextPaint(textPaint);
        StaticLayout layout = new StaticLayout(text, paint, 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 = paint.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);
    setTextSize(TypedValue.COMPLEX_UNIT_PX, targetTextSize);
    setLineSpacing(mSpacingAdd, mSpacingMult);

   //Notify the listener if registered
    if (mTextResizeListener != null) {
        mTextResizeListener.onTextResize(this, oldTextSize, targetTextSize);
    }

   //Reset force resize flag
    mNeedsResize = false;
}

// Set the text size of the text paint object and use a static layout to
// render text off screen before measuring
private int getTextHeight(CharSequence source, TextPaint originalPaint, int width,
        float textSize) {
    TextPaint paint = new TextPaint(originalPaint);
   //Update the text paint object
    paint.setTextSize(textSize);
   //Draw using a static layout
    StaticLayout layout = new StaticLayout(source, paint, width,
            Alignment.ALIGN_NORMAL, mSpacingMult, mSpacingAdd, true);
    layout.draw(sTextResizeCanvas);
    return layout.getHeight();
}

}

MyButton.java: пакет herrbert74.artvsample;

import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.WindowManager;
import android.widget.LinearLayout;

public class MyButton extends LinearLayout {
private AutoResizeTextView tv;
Context ctx;

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    AutoResizeTextView tv = (AutoResizeTextView) getChildAt(0);
    int padding = getHeight()/8;
    int left = padding;
    int top = (getHeight() - tv.getMeasuredHeight())/2;
    int right = padding + tv.getMeasuredWidth();
    int bottom = getHeight()/2 + tv.getMeasuredHeight()/2;
    tv.layout(left, top, right, bottom);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int w = MeasureSpec.getSize(widthMeasureSpec);
    int h = MeasureSpec.getSize(heightMeasureSpec);

    if (w == 0) {
        WindowManager wm = (WindowManager) ctx
                .getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics metrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(metrics);
        w = metrics.widthPixels;
        h = metrics.heightPixels;
    }
    tv.measure(MeasureSpec.makeMeasureSpec(w - 40, MeasureSpec.AT_MOST),
            MeasureSpec.makeMeasureSpec(h - 20, MeasureSpec.AT_MOST));
    setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),
            MeasureSpec.getSize(heightMeasureSpec));
}

public MyButton(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
    tv = new AutoResizeTextView(context);
    tv.setMaxTextSize(54);
    tv.setTextColor(context.getResources().getColor(android.R.color.white));
    tv.setClickable(true);
    tv.setBackgroundResource(android.R.color.darker_gray);
    addView(tv);
}

public MyButton(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs);
    ctx = context;
}

protected MyButton(Context context) {
    super(context, null);

}

public void setText(String text) {
    tv.setText(text);
}

public String getText() {
    return tv.getText().toString();
}

public void setTextSize(float f) {
    tv.setTextSize(f);
}
}

MainActivity.java: пакет herrbert74.artvsample;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity {
int x;
MyButton tv;

@Override
protected void onCreate(Bundle savedInstanceState) {
    x = -1;
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    final String[] texts = { "normal text", "a bit longer text", "even longer text by a word", "Long. Longest text ever. Long. Long." };
    tv = (MyButton) findViewById(R.id.textView1);
    Button b = (Button) findViewById(R.id.button1);
    b.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            if (x < texts.length - 1)
                x++;
            else
                x = 0;
            tv.setText(texts[x]);
            Log.d("AnswerView", "Text: " + texts[x]);
        }

    });
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
   //Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

}

В проекте в качестве примера есть кнопка, чтобы изменить текст. Сначала нет никакого текста, тогда тексты становятся более длинными. Вы видите различие на картинах.

Фоны кнопки черные, textview фоны серые.

Вот Бросание вызов textviews с правильными кнопками:

Defy without text First text Second text Third text Fourth text

Заметьте, что на Kindle textview уже требует некоторого места без текста! Неправильные расположения на Kindle Fire:

enter image description here First text Second text Third text Fourth text

В myButton конструкторе я попробовал следующее никакой пользы:

tv.setPadding(0, 0, 0, 0);
tv.setLineSpacing(0f, 1f);
tv.setCompoundDrawablePadding(0);
tv.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
tv.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
2
nl ja de
У нас в настоящее время есть та же самая проблема с Галактикой S3
добавлено автор Baconbeastnz, источник
Mobile Dev Jobs — вакансии и аналитика
Mobile Dev Jobs — вакансии и аналитика
6 187 участник(ов)

Публикуем вакансии и запросы на поиск работы по направлению iOS, Android, Xamarin и т.д. ВАЖНО: Правила публикации и правила канала: Ссылка – https://telegra.ph/Pravila-oformleniya-vakansij-i-rezyume-11-09-2

Android Developers
Android Developers
4 476 участник(ов)

Общаемся на темы, посвященным Android-разработке, SDK, Kotlin, Realm и т.д.

Android Architecture
Android Architecture
2 186 участник(ов)

Русскоязычный чат по архитектуре в андроид приложениях. Подробнее: http://telegra.ph/Android-Architecture-12-24

rus-speaking/android
rus-speaking/android
1 705 участник(ов)

Основной чат по Android разработке (вопрос-ответ). ПРАВИЛА: bit.ly/andr-rules. NEWS: bit.ly/AnrdResId ЧАТЫ: Основной: bit.ly/andr-main IDE, сборка, Git, сервисы: bit.ly/andr-tools Оффтоп: bit.ly/andr-offtop Конференции, события: bit.ly/andr-events Вакансии, найм: bit.ly/andr-job Архитектура: bit.ly/andr-patterns Rx: bit.ly/andr-rx Тестирование: bit.ly/andr-test Kotlin: bit.ly/andr-kotlin Хаmarin: bit.ly/andr-xamarin За мат, спам, агрессию, предложения о работе, оффтоп в этом канале - бан на сутки и более ☢☢☢

Android Dev Подкаст
Android Dev Подкаст
1 325 участник(ов)

Комната для обсуждения Android Dev подкаста apptractor.ru/AndroidDev/ Общее обсуждение Android: https://t.me/android_ru Остальные чаты про Android: http://t.me/devChats Наши новости https://t.me/androiddevpodcast_news

Android Guards
Android Guards
602 участник(ов)

Обсуждение любых вопросов касающихся безопасности Android. - Защита системы и приложений - Уязвимости и эксплойты - Вредоносное ПО - Копание в кишках системы и приложений (RE)

Android JOB
Android JOB
466 участник(ов)

Публикуем вакансии и запросы на поиск работы по направлению Android (full-time, part-time, remote и разовые подработки)

AndroidDev :: Разработка. It's Android time now!
AndroidDev :: Разработка. It's Android time now!
458 участник(ов)

It's Android time now! Чат разработчиков Android. Вакансии, резюме и информацию о митапах размещать можно. Публикацию скрытой и явной рекламы ваших каналов и сайтов после получения разрешения от @olegushakov

Aandroid Talks!
Aandroid Talks!
212 участник(ов)

Чат об общих вопросах по ОС Android. Чат для разработки под андроид - pro.android: https://t.me/joinchat/AAAAAEKIFKnmRT9cMebb9w

Android Rus
Android Rus
68 участник(ов)