Bug 1325931 - Implement ViewUtil.setCenteredText() for TextViews with compound drawables draft
authorAndrzej Hunt <ahunt@mozilla.com>
Thu, 09 Feb 2017 13:26:43 -0800
changeset 481479 da17e49e06328320082d1654b9ec92e86aeb4e53
parent 481478 f2dac7a4d8d9c6ca0f0c5bdc19a86a6776adc87e
child 481480 5e09e52aa19bcaf5525ca8d2431c9cad98daa43c
push id44814
push userahunt@mozilla.com
push dateThu, 09 Feb 2017 22:32:53 +0000
bugs1325931
milestone54.0a1
Bug 1325931 - Implement ViewUtil.setCenteredText() for TextViews with compound drawables Compound drawables shift the point where text is "centered". This hack dynamically adds equivalent padding on the opposite side from a compound drawable, to force the text to be centered again. (We can't set this padding under all circumstances, it's unneeded when the text is longer than the available space, i.e. when we wrap text we might as well use the full width without fake padding.) MozReview-Commit-ID: 8WDXCNOs2DX
mobile/android/base/java/org/mozilla/gecko/util/ViewUtil.java
--- a/mobile/android/base/java/org/mozilla/gecko/util/ViewUtil.java
+++ b/mobile/android/base/java/org/mozilla/gecko/util/ViewUtil.java
@@ -1,16 +1,17 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 package org.mozilla.gecko.util;
 
 import android.annotation.TargetApi;
 import android.content.res.TypedArray;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.support.v4.text.TextUtilsCompat;
 import android.support.v4.view.MarginLayoutParamsCompat;
 import android.support.v4.view.ViewCompat;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
@@ -68,16 +69,72 @@ public class ViewUtil {
 
         // Restore the padding on certain devices, as explained above:
         if (!AppConstants.Versions.feature21Plus) {
             view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
         }
     }
 
     /**
+     * Set text for a TextView, while ensuring it remains centered, regardless of any compound
+     * drawables that might be set. When compound drawables exist, text might be shifted left- or
+     * right- of centre - this method hacks around that by shifting text back as necessary.
+     */
+    public static void setCenteredText(final TextView textView, final String label, final int defaultPadding) {
+        textView.setText(label);
+
+        // getCompoundDrawables always returns a valid 4 item array (individual drawables may be null,
+        // but the array is always non-null).
+        final Drawable[] drawables = textView.getCompoundDrawables();
+        final Drawable drawableLeft = drawables[0];
+        final Drawable drawableRight = drawables[2];
+
+        // The amount by which the left (positive) or right (negative) side has been shifted
+        // by drawables:
+        final int leftRightDelta = (drawableLeft != null ? drawableLeft.getIntrinsicWidth() : 0)
+                - (drawableRight != null ? drawableRight.getIntrinsicWidth() : 0);
+
+        final int leftAdjustment;
+        final int rightAdjustment;
+        if (leftRightDelta == 0) {
+            // No drawables: keep default padding (we still need to make sure we set the padding, since
+            // it could have previously been adjusted if there used to be a compound drawable).
+            leftAdjustment = 0;
+            rightAdjustment = 0;
+        } else {
+            // We need to decide whether we really want to center: if the text is longer than the available
+            // space, we want to keep the maximum available space, if it's shorter we use fake padding
+            // to center the text:
+            final Rect bounds = new Rect();
+            textView.getPaint().getTextBounds(label.toString(), 0, label.length(), bounds);
+
+            // This is the width that would be available _after_ additional padding has been set,
+            // i.e. the icon width + mirrored padding + existing paddings:
+            final int availableWidth = textView.getWidth() - 2 * Math.abs(leftRightDelta) - 2 * defaultPadding - 2 * textView.getCompoundDrawablePadding();
+            final int textWidth = bounds.width();
+
+            if (textWidth > availableWidth) {
+                leftAdjustment = 0;
+                rightAdjustment = 0;
+            } else {
+                if (leftRightDelta > 0) {
+                    leftAdjustment = 0;
+                    rightAdjustment = leftRightDelta;
+                } else {
+                    leftAdjustment = -leftRightDelta;
+                    rightAdjustment = 0;
+                }
+            }
+        }
+
+        textView.setPadding(defaultPadding + leftAdjustment, textView.getPaddingTop(), defaultPadding + rightAdjustment, textView.getPaddingBottom());
+    }
+
+
+    /**
      * Android framework have a bug margin start/end for RTL between 19~22. We can only use MarginLayoutParamsCompat before 17 and after 23.
      * @param layoutParams
      * @param marginStart
      * @param isLayoutRtl
      */
     public static void setMarginStart(ViewGroup.MarginLayoutParams layoutParams, int marginStart, boolean isLayoutRtl) {
         if (AppConstants.Versions.feature17Plus && AppConstants.Versions.preN) {
             if (isLayoutRtl) {