Advertisement
Guest User

Untitled

a guest
Sep 15th, 2017
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 37.13 KB | None | 0 0
  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
  3. android:layout_height="match_parent" tools:context=".MainActivity">
  4. <Button android:id="@+id/button1" android:layout_width="wrap_content"
  5. android:layout_height="wrap_content"
  6. android:layout_alignParentBottom="true"
  7. android:layout_centerHorizontal="true" android:text="Button" />
  8. <FrameLayout android:layout_width="match_parent"
  9. android:layout_height="wrap_content" android:layout_above="@+id/button1"
  10. android:layout_alignParentLeft="true" android:background="#ffff0000"
  11. android:layout_alignParentRight="true" android:id="@+id/container"
  12. android:layout_alignParentTop="true" />
  13.  
  14. </RelativeLayout>
  15.  
  16. public class MainActivity extends Activity
  17. {
  18. private final Random _random =new Random();
  19. private static final String ALLOWED_CHARACTERS ="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
  20.  
  21. @Override
  22. protected void onCreate(final Bundle savedInstanceState)
  23. {
  24. super.onCreate(savedInstanceState);
  25. setContentView(R.layout.activity_main);
  26. final ViewGroup container=(ViewGroup)findViewById(R.id.container);
  27. findViewById(R.id.button1).setOnClickListener(new OnClickListener()
  28. {
  29. @Override
  30. public void onClick(final View v)
  31. {
  32. container.removeAllViews();
  33. final int maxWidth=container.getWidth();
  34. final int maxHeight=container.getHeight();
  35. final FontFitTextView fontFitTextView=new FontFitTextView(MainActivity.this);
  36. final int width=_random.nextInt(maxWidth)+1;
  37. final int height=_random.nextInt(maxHeight)+1;
  38. fontFitTextView.setLayoutParams(new LayoutParams(width,height));
  39. fontFitTextView.setSingleLine();
  40. fontFitTextView.setBackgroundColor(0xff00ff00);
  41. final String text=getRandomText();
  42. fontFitTextView.setText(text);
  43. container.addView(fontFitTextView);
  44. Log.d("DEBUG","width:"+width+" height:"+height+" text:"+text);
  45. }
  46. });
  47. }
  48.  
  49. private String getRandomText()
  50. {
  51. final int textLength=_random.nextInt(20)+1;
  52. final StringBuilder builder=new StringBuilder();
  53. for(int i=0;i<textLength;++i)
  54. builder.append(ALLOWED_CHARACTERS.charAt(_random.nextInt(ALLOWED_CHARACTERS.length())));
  55. return builder.toString();
  56. }
  57. }
  58.  
  59. @Override
  60. protected void onCreate(final Bundle savedInstanceState) {
  61. super.onCreate(savedInstanceState);
  62. setContentView(R.layout.activity_main);
  63. final ViewGroup container = (ViewGroup) findViewById(R.id.container);
  64. findViewById(R.id.button1).setOnClickListener(new OnClickListener() {
  65. @Override
  66. public void onClick(final View v) {
  67. container.removeAllViews();
  68. final int maxWidth = container.getWidth();
  69. final int maxHeight = container.getHeight();
  70. final AutoResizeTextView fontFitTextView = new AutoResizeTextView(MainActivity.this);
  71. final int width = _random.nextInt(maxWidth) + 1;
  72. final int height = _random.nextInt(maxHeight) + 1;
  73. fontFitTextView.setLayoutParams(new FrameLayout.LayoutParams(
  74. width, height));
  75. int maxLines = _random.nextInt(4) + 1;
  76. fontFitTextView.setMaxLines(maxLines);
  77. fontFitTextView.setTextSize(500);// max size
  78. fontFitTextView.enableSizeCache(false);
  79. fontFitTextView.setBackgroundColor(0xff00ff00);
  80. final String text = getRandomText();
  81. fontFitTextView.setText(text);
  82. container.addView(fontFitTextView);
  83. Log.d("DEBUG", "width:" + width + " height:" + height
  84. + " text:" + text + " maxLines:" + maxLines);
  85. }
  86. });
  87. }
  88.  
  89. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  90. android:layout_width="wrap_content"
  91. android:layout_height="wrap_content"
  92. android:orientation="vertical"
  93. android:padding="16dp" >
  94.  
  95. <com.vj.widgets.AutoResizeTextView
  96. android:layout_width="match_parent"
  97. android:layout_height="100dp"
  98. android:ellipsize="none"
  99. android:maxLines="2"
  100. android:text="Auto Resized Text, max 2 lines"
  101. android:textSize="100sp" /> <!-- maximum size -->
  102.  
  103. <com.vj.widgets.AutoResizeTextView
  104. android:layout_width="match_parent"
  105. android:layout_height="100dp"
  106. android:ellipsize="none"
  107. android:gravity="center"
  108. android:maxLines="1"
  109. android:text="Auto Resized Text, max 1 line"
  110. android:textSize="100sp" /> <!-- maximum size -->
  111.  
  112. <com.vj.widgets.AutoResizeTextView
  113. android:layout_width="match_parent"
  114. android:layout_height="wrap_content"
  115. android:text="Auto Resized Text"
  116. android:textSize="500sp" /> <!-- maximum size -->
  117.  
  118. </LinearLayout>
  119.  
  120. import android.annotation.TargetApi;
  121. import android.content.Context;
  122. import android.content.res.Resources;
  123. import android.graphics.RectF;
  124. import android.os.Build;
  125. import android.text.Layout.Alignment;
  126. import android.text.StaticLayout;
  127. import android.text.TextPaint;
  128. import android.util.AttributeSet;
  129. import android.util.SparseIntArray;
  130. import android.util.TypedValue;
  131. import android.widget.TextView;
  132.  
  133. public class AutoResizeTextView extends TextView {
  134. private interface SizeTester {
  135. /**
  136. *
  137. * @param suggestedSize
  138. * Size of text to be tested
  139. * @param availableSpace
  140. * available space in which text must fit
  141. * @return an integer < 0 if after applying {@code suggestedSize} to
  142. * text, it takes less space than {@code availableSpace}, > 0
  143. * otherwise
  144. */
  145. public int onTestSize(int suggestedSize, RectF availableSpace);
  146. }
  147.  
  148. private RectF mTextRect = new RectF();
  149.  
  150. private RectF mAvailableSpaceRect;
  151.  
  152. private SparseIntArray mTextCachedSizes;
  153.  
  154. private TextPaint mPaint;
  155.  
  156. private float mMaxTextSize;
  157.  
  158. private float mSpacingMult = 1.0f;
  159.  
  160. private float mSpacingAdd = 0.0f;
  161.  
  162. private float mMinTextSize = 20;
  163.  
  164. private int mWidthLimit;
  165.  
  166. private static final int NO_LINE_LIMIT = -1;
  167. private int mMaxLines;
  168.  
  169. private boolean mEnableSizeCache = true;
  170. private boolean mInitializedDimens;
  171.  
  172. public AutoResizeTextView(Context context) {
  173. super(context);
  174. initialize();
  175. }
  176.  
  177. public AutoResizeTextView(Context context, AttributeSet attrs) {
  178. super(context, attrs);
  179. initialize();
  180. }
  181.  
  182. public AutoResizeTextView(Context context, AttributeSet attrs, int defStyle) {
  183. super(context, attrs, defStyle);
  184. initialize();
  185. }
  186.  
  187. private void initialize() {
  188. mPaint = new TextPaint(getPaint());
  189. mMaxTextSize = getTextSize();
  190. mAvailableSpaceRect = new RectF();
  191. mTextCachedSizes = new SparseIntArray();
  192. if (mMaxLines == 0) {
  193. // no value was assigned during construction
  194. mMaxLines = NO_LINE_LIMIT;
  195. }
  196. }
  197.  
  198. @Override
  199. public void setTextSize(float size) {
  200. mMaxTextSize = size;
  201. mTextCachedSizes.clear();
  202. adjustTextSize();
  203. }
  204.  
  205. @Override
  206. public void setMaxLines(int maxlines) {
  207. super.setMaxLines(maxlines);
  208. mMaxLines = maxlines;
  209. adjustTextSize();
  210. }
  211.  
  212. public int getMaxLines() {
  213. return mMaxLines;
  214. }
  215.  
  216. @Override
  217. public void setSingleLine() {
  218. super.setSingleLine();
  219. mMaxLines = 1;
  220. adjustTextSize();
  221. }
  222.  
  223. @Override
  224. public void setSingleLine(boolean singleLine) {
  225. super.setSingleLine(singleLine);
  226. if (singleLine) {
  227. mMaxLines = 1;
  228. } else {
  229. mMaxLines = NO_LINE_LIMIT;
  230. }
  231. adjustTextSize();
  232. }
  233.  
  234. @Override
  235. public void setLines(int lines) {
  236. super.setLines(lines);
  237. mMaxLines = lines;
  238. adjustTextSize();
  239. }
  240.  
  241. @Override
  242. public void setTextSize(int unit, float size) {
  243. Context c = getContext();
  244. Resources r;
  245.  
  246. if (c == null)
  247. r = Resources.getSystem();
  248. else
  249. r = c.getResources();
  250. mMaxTextSize = TypedValue.applyDimension(unit, size,
  251. r.getDisplayMetrics());
  252. mTextCachedSizes.clear();
  253. adjustTextSize();
  254. }
  255.  
  256. @Override
  257. public void setLineSpacing(float add, float mult) {
  258. super.setLineSpacing(add, mult);
  259. mSpacingMult = mult;
  260. mSpacingAdd = add;
  261. }
  262.  
  263. /**
  264. * Set the lower text size limit and invalidate the view
  265. *
  266. * @param minTextSize
  267. */
  268. public void setMinTextSize(float minTextSize) {
  269. mMinTextSize = minTextSize;
  270. adjustTextSize();
  271. }
  272.  
  273. private void adjustTextSize() {
  274. if (!mInitializedDimens) {
  275. return;
  276. }
  277. int startSize = (int) mMinTextSize;
  278. int heightLimit = getMeasuredHeight() - getCompoundPaddingBottom()
  279. - getCompoundPaddingTop();
  280. mWidthLimit = getMeasuredWidth() - getCompoundPaddingLeft()
  281. - getCompoundPaddingRight();
  282. mAvailableSpaceRect.right = mWidthLimit;
  283. mAvailableSpaceRect.bottom = heightLimit;
  284. super.setTextSize(
  285. TypedValue.COMPLEX_UNIT_PX,
  286. efficientTextSizeSearch(startSize, (int) mMaxTextSize,
  287. mSizeTester, mAvailableSpaceRect));
  288. }
  289.  
  290. private final SizeTester mSizeTester = new SizeTester() {
  291. @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
  292. @Override
  293. public int onTestSize(int suggestedSize, RectF availableSPace) {
  294. mPaint.setTextSize(suggestedSize);
  295. String text = getText().toString();
  296. boolean singleline = getMaxLines() == 1;
  297. if (singleline) {
  298. mTextRect.bottom = mPaint.getFontSpacing();
  299. mTextRect.right = mPaint.measureText(text);
  300. } else {
  301. StaticLayout layout = new StaticLayout(text, mPaint,
  302. mWidthLimit, Alignment.ALIGN_NORMAL, mSpacingMult,
  303. mSpacingAdd, true);
  304.  
  305. // Return early if we have more lines
  306. if (getMaxLines() != NO_LINE_LIMIT
  307. && layout.getLineCount() > getMaxLines()) {
  308. return 1;
  309. }
  310. mTextRect.bottom = layout.getHeight();
  311. int maxWidth = -1;
  312. for (int i = 0; i < layout.getLineCount(); i++) {
  313. if (maxWidth < layout.getLineWidth(i)) {
  314. maxWidth = (int) layout.getLineWidth(i);
  315. }
  316. }
  317. mTextRect.right = maxWidth;
  318. }
  319.  
  320. mTextRect.offsetTo(0, 0);
  321. if (availableSPace.contains(mTextRect)) {
  322.  
  323. // May be too small, don't worry we will find the best match
  324. return -1;
  325. } else {
  326. // too big
  327. return 1;
  328. }
  329. }
  330. };
  331.  
  332. /**
  333. * Enables or disables size caching, enabling it will improve performance
  334. * where you are animating a value inside TextView. This stores the font
  335. * size against getText().length() Be careful though while enabling it as 0
  336. * takes more space than 1 on some fonts and so on.
  337. *
  338. * @param enable
  339. * Enable font size caching
  340. */
  341. public void enableSizeCache(boolean enable) {
  342. mEnableSizeCache = enable;
  343. mTextCachedSizes.clear();
  344. adjustTextSize(getText().toString());
  345. }
  346.  
  347. private int efficientTextSizeSearch(int start, int end,
  348. SizeTester sizeTester, RectF availableSpace) {
  349. if (!mEnableSizeCache) {
  350. return binarySearch(start, end, sizeTester, availableSpace);
  351. }
  352. int key = getText().toString().length();
  353. int size = mTextCachedSizes.get(key);
  354. if (size != 0) {
  355. return size;
  356. }
  357. size = binarySearch(start, end, sizeTester, availableSpace);
  358. mTextCachedSizes.put(key, size);
  359. return size;
  360. }
  361.  
  362. private static int binarySearch(int start, int end, SizeTester sizeTester,
  363. RectF availableSpace) {
  364. int lastBest = start;
  365. int lo = start;
  366. int hi = end - 1;
  367. int mid = 0;
  368. while (lo <= hi) {
  369. mid = (lo + hi) >>> 1;
  370. int midValCmp = sizeTester.onTestSize(mid, availableSpace);
  371. if (midValCmp < 0) {
  372. lastBest = lo;
  373. lo = mid + 1;
  374. } else if (midValCmp > 0) {
  375. hi = mid - 1;
  376. lastBest = hi;
  377. } else {
  378. return mid;
  379. }
  380. }
  381. // Make sure to return the last best.
  382. // This is what should always be returned.
  383. return lastBest;
  384.  
  385. }
  386.  
  387. @Override
  388. protected void onTextChanged(final CharSequence text, final int start,
  389. final int before, final int after) {
  390. super.onTextChanged(text, start, before, after);
  391. adjustTextSize();
  392. }
  393.  
  394. @Override
  395. protected void onSizeChanged(int width, int height, int oldwidth,
  396. int oldheight) {
  397. mInitializedDimens = true;
  398. mTextCachedSizes.clear();
  399. super.onSizeChanged(width, height, oldwidth, oldheight);
  400. if (width != oldwidth || height != oldheight) {
  401. adjustTextSize();
  402. }
  403. }
  404. }
  405.  
  406. private void adjustTextSize(final String text) {
  407. if (!mInitialized) {
  408. return;
  409. }
  410. int heightLimit = getMeasuredHeight() - getCompoundPaddingBottom() - getCompoundPaddingTop();
  411. mWidthLimit = getMeasuredWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight();
  412.  
  413. mAvailableSpaceRect.right = mWidthLimit;
  414. mAvailableSpaceRect.bottom = heightLimit;
  415.  
  416. int maxTextSplits = text.split(" ").length;
  417. AutoResizeTextView.super.setMaxLines(Math.min(maxTextSplits, mMaxLines));
  418.  
  419. super.setTextSize(
  420. TypedValue.COMPLEX_UNIT_PX,
  421. binarySearch((int) mMinTextSize, (int) mMaxTextSize,
  422. mSizeTester, mAvailableSpaceRect));
  423. }
  424.  
  425. for (float testSize; (upperTextSize - lowerTextSize) > mThreshold;) {
  426.  
  427. // Go to the mean value...
  428. testSize = (upperTextSize + lowerTextSize) / 2;
  429.  
  430. // ... inflate the dummy TextView by setting a scaled textSize and the text...
  431. mTestView.setTextSize(TypedValue.COMPLEX_UNIT_SP, testSize / mScaledDensityFactor);
  432. mTestView.setText(text);
  433.  
  434. // ... call measure to find the current values that the text WANTS to occupy
  435. mTestView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
  436. int tempHeight = mTestView.getMeasuredHeight();
  437.  
  438. // ... decide whether those values are appropriate.
  439. if (tempHeight >= targetFieldHeight) {
  440. upperTextSize = testSize; // Font is too big, decrease upperSize
  441. }
  442. else {
  443. lowerTextSize = testSize; // Font is too small, increase lowerSize
  444. }
  445. }
  446.  
  447. <com.example.myProject.AutoFitText
  448. android:id="@+id/textView"
  449. android:layout_width="match_parent"
  450. android:layout_height="0dp"
  451. android:layout_weight="4"
  452. android:text="@string/LoremIpsum" />
  453.  
  454. final Random _random = new Random();
  455. final String ALLOWED_CHARACTERS = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
  456. final int textLength = _random.nextInt(80) + 20;
  457. final StringBuilder builder = new StringBuilder();
  458. for (int i = 0; i < textLength; ++i) {
  459. if (i % 7 == 0 && i != 0) {
  460. builder.append(" ");
  461. }
  462. builder.append(ALLOWED_CHARACTERS.charAt(_random.nextInt(ALLOWED_CHARACTERS.length())));
  463. }
  464. ((AutoFitText) findViewById(R.id.textViewMessage)).setText(builder.toString());
  465.  
  466. public class ScalableTextView extends TextView
  467. {
  468. float defaultTextSize = 0.0f;
  469.  
  470. public ScalableTextView(Context context, AttributeSet attrs, int defStyle)
  471. {
  472. super(context, attrs, defStyle);
  473. setSingleLine();
  474. setEllipsize(TruncateAt.END);
  475. defaultTextSize = getTextSize();
  476. }
  477.  
  478. public ScalableTextView(Context context, AttributeSet attrs)
  479. {
  480. super(context, attrs);
  481. setSingleLine();
  482. setEllipsize(TruncateAt.END);
  483. defaultTextSize = getTextSize();
  484. }
  485.  
  486. public ScalableTextView(Context context)
  487. {
  488. super(context);
  489. setSingleLine();
  490. setEllipsize(TruncateAt.END);
  491. defaultTextSize = getTextSize();
  492. }
  493.  
  494. @Override
  495. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
  496. {
  497. setTextSize(TypedValue.COMPLEX_UNIT_PX, defaultTextSize);
  498. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  499.  
  500. final Layout layout = getLayout();
  501. if (layout != null)
  502. {
  503. final int lineCount = layout.getLineCount();
  504. if (lineCount > 0)
  505. {
  506. int ellipsisCount = layout.getEllipsisCount(lineCount - 1);
  507. while (ellipsisCount > 0)
  508. {
  509. final float textSize = getTextSize();
  510.  
  511. // textSize is already expressed in pixels
  512. setTextSize(TypedValue.COMPLEX_UNIT_PX, (textSize - 1));
  513.  
  514. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  515. ellipsisCount = layout.getEllipsisCount(lineCount - 1);
  516. }
  517. }
  518. }
  519. }
  520. }
  521.  
  522. final String DOUBLE_BYTE_SPACE = "u3000";
  523. textView.append(DOUBLE_BYTE_SPACE);
  524.  
  525. final String DOUBLE_BYTE_SPACE = "u3000";
  526. AutoResizeTextView textView = (AutoResizeTextView) view.findViewById(R.id.aTextView);
  527. String fixString = "";
  528. if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB_MR1
  529. && android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
  530. fixString = DOUBLE_BYTE_SPACE;
  531. }
  532. textView.setText(fixString + "The text" + fixString);
  533.  
  534. <?xml version="1.0" encoding="utf-8"?>
  535. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  536. xmlns:foo="http://schemas.android.com/apk/res-auto"
  537. android:layout_width="wrap_content"
  538. android:layout_height="match_parent" >
  539.  
  540. <de.meinprospekt.androidhd.view.AutoFitText
  541. android:layout_width="wrap_content"
  542. android:layout_height="10dp"
  543. android:text="Small Text"
  544. android:textColor="#FFFFFF"
  545. android:textSize="100sp"
  546. foo:customFont="fonts/Roboto-Light.ttf" />
  547.  
  548. </FrameLayout>
  549.  
  550. import java.util.ArrayList;
  551. import java.util.List;
  552.  
  553. import android.annotation.SuppressLint;
  554. import android.content.Context;
  555. import android.content.res.TypedArray;
  556. import android.graphics.Paint;
  557. import android.graphics.Typeface;
  558. import android.os.Build;
  559. import android.util.AttributeSet;
  560. import android.util.Log;
  561. import android.util.TypedValue;
  562. import android.view.View;
  563. import android.view.ViewGroup.LayoutParams;
  564. import android.view.ViewTreeObserver;
  565. import android.view.ViewTreeObserver.OnGlobalLayoutListener;
  566. import android.widget.TextView;
  567. import de.meinprospekt.androidhd.R;
  568. import de.meinprospekt.androidhd.adapter.BrochuresHorizontalAdapter;
  569. import de.meinprospekt.androidhd.util.LOG;
  570.  
  571. /**
  572. * https://stackoverflow.com/a/16174468/2075875 This class builds a new android Widget named AutoFitText which can be used instead of a TextView to
  573. * have the text font size in it automatically fit to match the screen width. Credits go largely to Dunni, gjpc, gregm and speedplane from
  574. * Stackoverflow, method has been (style-) optimized and rewritten to match android coding standards and our MBC. This version upgrades the original
  575. * "AutoFitTextView" to now also be adaptable to height and to accept the different TextView types (Button, TextClock etc.)
  576. *
  577. * @author pheuschk
  578. * @createDate: 18.04.2013
  579. *
  580. * combined with: https://stackoverflow.com/a/7197867/2075875
  581. */
  582. @SuppressWarnings("unused")
  583. public class AutoFitText extends TextView {
  584.  
  585. private static final String TAG = AutoFitText.class.getSimpleName();
  586.  
  587. /** Global min and max for text size. Remember: values are in pixels! */
  588. private final int MIN_TEXT_SIZE = 10;
  589. private final int MAX_TEXT_SIZE = 400;
  590.  
  591. /** Flag for singleLine */
  592. private boolean mSingleLine = false;
  593.  
  594. /**
  595. * A dummy {@link TextView} to test the text size without actually showing anything to the user
  596. */
  597. private TextView mTestView;
  598.  
  599. /**
  600. * A dummy {@link Paint} to test the text size without actually showing anything to the user
  601. */
  602. private Paint mTestPaint;
  603.  
  604. /**
  605. * Scaling factor for fonts. It's a method of calculating independently (!) from the actual density of the screen that is used so users have the
  606. * same experience on different devices. We will use DisplayMetrics in the Constructor to get the value of the factor and then calculate SP from
  607. * pixel values
  608. */
  609. private float mScaledDensityFactor;
  610.  
  611. /**
  612. * Defines how close we want to be to the factual size of the Text-field. Lower values mean higher precision but also exponentially higher
  613. * computing cost (more loop runs)
  614. */
  615. private final float mThreshold = 0.5f;
  616.  
  617. /**
  618. * Constructor for call without attributes --> invoke constructor with AttributeSet null
  619. *
  620. * @param context
  621. */
  622. public AutoFitText(Context context) {
  623. this(context, null);
  624. }
  625.  
  626. public AutoFitText(Context context, AttributeSet attrs) {
  627. super(context, attrs);
  628. init(context, attrs);
  629. }
  630.  
  631. public AutoFitText(Context context, AttributeSet attrs, int defStyle) {
  632. super(context, attrs, defStyle);
  633. init(context, attrs);
  634. }
  635.  
  636. private void init(Context context, AttributeSet attrs) {
  637. //TextViewPlus part https://stackoverflow.com/a/7197867/2075875
  638. TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoFitText);
  639. String customFont = a.getString(R.styleable.AutoFitText_customFont);
  640. setCustomFont(context, customFont);
  641. a.recycle();
  642.  
  643. // AutoFitText part
  644. mScaledDensityFactor = context.getResources().getDisplayMetrics().scaledDensity;
  645. mTestView = new TextView(context);
  646.  
  647. mTestPaint = new Paint();
  648. mTestPaint.set(this.getPaint());
  649.  
  650. this.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
  651.  
  652. @Override
  653. public void onGlobalLayout() {
  654. // make an initial call to onSizeChanged to make sure that refitText is triggered
  655. onSizeChanged(AutoFitText.this.getWidth(), AutoFitText.this.getHeight(), 0, 0);
  656. // Remove the LayoutListener immediately so we don't run into an infinite loop
  657. //AutoFitText.this.getViewTreeObserver().removeOnGlobalLayoutListener(this);
  658. removeOnGlobalLayoutListener(AutoFitText.this, this);
  659. }
  660. });
  661. }
  662.  
  663. public boolean setCustomFont(Context ctx, String asset) {
  664. Typeface tf = null;
  665. try {
  666. tf = Typeface.createFromAsset(ctx.getAssets(), asset);
  667. } catch (Exception e) {
  668. LOG.e(TAG, "Could not get typeface: "+e.getMessage());
  669. return false;
  670. }
  671.  
  672. setTypeface(tf);
  673. return true;
  674. }
  675.  
  676. @SuppressLint("NewApi")
  677. public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener){
  678. if (Build.VERSION.SDK_INT < 16) {
  679. v.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
  680. } else {
  681. v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
  682. }
  683. }
  684.  
  685. /**
  686. * Main method of this widget. Resizes the font so the specified text fits in the text box assuming the text box has the specified width. This is
  687. * done via a dummy text view that is refit until it matches the real target width and height up to a certain threshold factor
  688. *
  689. * @param targetFieldWidth The width that the TextView currently has and wants filled
  690. * @param targetFieldHeight The width that the TextView currently has and wants filled
  691. */
  692. private void refitText(String text, int targetFieldWidth, int targetFieldHeight) {
  693.  
  694. // Variables need to be visible outside the loops for later use. Remember size is in pixels
  695. float lowerTextSize = MIN_TEXT_SIZE;
  696. float upperTextSize = MAX_TEXT_SIZE;
  697.  
  698. // Force the text to wrap. In principle this is not necessary since the dummy TextView
  699. // already does this for us but in rare cases adding this line can prevent flickering
  700. this.setMaxWidth(targetFieldWidth);
  701.  
  702. // Padding should not be an issue since we never define it programmatically in this app
  703. // but just to to be sure we cut it off here
  704. targetFieldWidth = targetFieldWidth - this.getPaddingLeft() - this.getPaddingRight();
  705. targetFieldHeight = targetFieldHeight - this.getPaddingTop() - this.getPaddingBottom();
  706.  
  707. // Initialize the dummy with some params (that are largely ignored anyway, but this is
  708. // mandatory to not get a NullPointerException)
  709. mTestView.setLayoutParams(new LayoutParams(targetFieldWidth, targetFieldHeight));
  710.  
  711. // maxWidth is crucial! Otherwise the text would never line wrap but blow up the width
  712. mTestView.setMaxWidth(targetFieldWidth);
  713.  
  714. if (mSingleLine) {
  715. // the user requested a single line. This is very easy to do since we primarily need to
  716. // respect the width, don't have to break, don't have to measure...
  717.  
  718. /*************************** Converging algorithm 1 ***********************************/
  719. for (float testSize; (upperTextSize - lowerTextSize) > mThreshold;) {
  720.  
  721. // Go to the mean value...
  722. testSize = (upperTextSize + lowerTextSize) / 2;
  723.  
  724. mTestView.setTextSize(TypedValue.COMPLEX_UNIT_SP, testSize / mScaledDensityFactor);
  725. mTestView.setText(text);
  726. mTestView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
  727.  
  728. if (mTestView.getMeasuredWidth() >= targetFieldWidth) {
  729. upperTextSize = testSize; // Font is too big, decrease upperSize
  730. } else {
  731. lowerTextSize = testSize; // Font is too small, increase lowerSize
  732. }
  733. }
  734. /**************************************************************************************/
  735.  
  736. // In rare cases with very little letters and width > height we have vertical overlap!
  737. mTestView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
  738.  
  739. if (mTestView.getMeasuredHeight() > targetFieldHeight) {
  740. upperTextSize = lowerTextSize;
  741. lowerTextSize = MIN_TEXT_SIZE;
  742.  
  743. /*************************** Converging algorithm 1.5 *****************************/
  744. for (float testSize; (upperTextSize - lowerTextSize) > mThreshold;) {
  745.  
  746. // Go to the mean value...
  747. testSize = (upperTextSize + lowerTextSize) / 2;
  748.  
  749. mTestView.setTextSize(TypedValue.COMPLEX_UNIT_SP, testSize / mScaledDensityFactor);
  750. mTestView.setText(text);
  751. mTestView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
  752.  
  753. if (mTestView.getMeasuredHeight() >= targetFieldHeight) {
  754. upperTextSize = testSize; // Font is too big, decrease upperSize
  755. } else {
  756. lowerTextSize = testSize; // Font is too small, increase lowerSize
  757. }
  758. }
  759. /**********************************************************************************/
  760. }
  761. } else {
  762.  
  763. /*********************** Converging algorithm 2 ***************************************/
  764. // Upper and lower size converge over time. As soon as they're close enough the loop
  765. // stops
  766. // TODO probe the algorithm for cost (ATM possibly O(n^2)) and optimize if possible
  767. for (float testSize; (upperTextSize - lowerTextSize) > mThreshold;) {
  768.  
  769. // Go to the mean value...
  770. testSize = (upperTextSize + lowerTextSize) / 2;
  771.  
  772. // ... inflate the dummy TextView by setting a scaled textSize and the text...
  773. mTestView.setTextSize(TypedValue.COMPLEX_UNIT_SP, testSize / mScaledDensityFactor);
  774. mTestView.setText(text);
  775.  
  776. // ... call measure to find the current values that the text WANTS to occupy
  777. mTestView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
  778. int tempHeight = mTestView.getMeasuredHeight();
  779. // int tempWidth = mTestView.getMeasuredWidth();
  780.  
  781. // LOG.debug("Measured: " + tempWidth + "x" + tempHeight);
  782. // LOG.debug("TextSize: " + testSize / mScaledDensityFactor);
  783.  
  784. // ... decide whether those values are appropriate.
  785. if (tempHeight >= targetFieldHeight) {
  786. upperTextSize = testSize; // Font is too big, decrease upperSize
  787. } else {
  788. lowerTextSize = testSize; // Font is too small, increase lowerSize
  789. }
  790. }
  791. /**************************************************************************************/
  792.  
  793. // It is possible that a single word is wider than the box. The Android system would
  794. // wrap this for us. But if you want to decide fo yourself where exactly to break or to
  795. // add a hyphen or something than you're going to want to implement something like this:
  796. mTestPaint.setTextSize(lowerTextSize);
  797. List<String> words = new ArrayList<String>();
  798.  
  799. for (String s : text.split(" ")) {
  800. Log.i("tag", "Word: " + s);
  801. words.add(s);
  802. }
  803. for (String word : words) {
  804. if (mTestPaint.measureText(word) >= targetFieldWidth) {
  805. List<String> pieces = new ArrayList<String>();
  806. // pieces = breakWord(word, mTestPaint.measureText(word), targetFieldWidth);
  807.  
  808. // Add code to handle the pieces here...
  809. }
  810. }
  811. }
  812.  
  813. /**
  814. * We are now at most the value of threshold away from the actual size. To rather undershoot than overshoot use the lower value. To match
  815. * different screens convert to SP first. See {@link http://developer.android.com/guide/topics/resources/more-resources.html#Dimension} for
  816. * more details
  817. */
  818. this.setTextSize(TypedValue.COMPLEX_UNIT_SP, lowerTextSize / mScaledDensityFactor);
  819. return;
  820. }
  821.  
  822. /**
  823. * This method receives a call upon a change in text content of the TextView. Unfortunately it is also called - among others - upon text size
  824. * change which means that we MUST NEVER CALL {@link #refitText(String)} from this method! Doing so would result in an endless loop that would
  825. * ultimately result in a stack overflow and termination of the application
  826. *
  827. * So for the time being this method does absolutely nothing. If you want to notify the view of a changed text call {@link #setText(CharSequence)}
  828. */
  829. @Override
  830. protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
  831. // Super implementation is also intentionally empty so for now we do absolutely nothing here
  832. super.onTextChanged(text, start, lengthBefore, lengthAfter);
  833. }
  834.  
  835. @Override
  836. protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
  837. if (width != oldWidth && height != oldHeight) {
  838. refitText(this.getText().toString(), width, height);
  839. }
  840. }
  841.  
  842. /**
  843. * This method is guaranteed to be called by {@link TextView#setText(CharSequence)} immediately. Therefore we can safely add our modifications
  844. * here and then have the parent class resume its work. So if text has changed you should always call {@link TextView#setText(CharSequence)} or
  845. * {@link TextView#setText(CharSequence, BufferType)} if you know whether the {@link BufferType} is normal, editable or spannable. Note: the
  846. * method will default to {@link BufferType#NORMAL} if you don't pass an argument.
  847. */
  848. @Override
  849. public void setText(CharSequence text, BufferType type) {
  850.  
  851. int targetFieldWidth = this.getWidth();
  852. int targetFieldHeight = this.getHeight();
  853.  
  854. if (targetFieldWidth <= 0 || targetFieldHeight <= 0 || text.equals("")) {
  855. // Log.v("tag", "Some values are empty, AutoFitText was not able to construct properly");
  856. } else {
  857. refitText(text.toString(), targetFieldWidth, targetFieldHeight);
  858. }
  859. super.setText(text, type);
  860. }
  861.  
  862. /**
  863. * TODO add sensibility for {@link #setMaxLines(int)} invocations
  864. */
  865. @Override
  866. public void setMaxLines(int maxLines) {
  867. // TODO Implement support for this. This could be relatively easy. The idea would probably
  868. // be to manipulate the targetHeight in the refitText-method and then have the algorithm do
  869. // its job business as usual. Nonetheless, remember the height will have to be lowered
  870. // dynamically as the font size shrinks so it won't be a walk in the park still
  871. if (maxLines == 1) {
  872. this.setSingleLine(true);
  873. } else {
  874. throw new UnsupportedOperationException("MaxLines != 1 are not implemented in AutoFitText yet, use TextView instead");
  875. }
  876. }
  877.  
  878. @Override
  879. public void setSingleLine(boolean singleLine) {
  880. // save the requested value in an instance variable to be able to decide later
  881. mSingleLine = singleLine;
  882. super.setSingleLine(singleLine);
  883. }
  884. }
  885.  
  886. TextWatcher changeText = new TextWatcher() {
  887. @Override
  888. public void onTextChanged(CharSequence s, int start, int before, int count) {
  889. tv3.setText(et.getText().toString());
  890. tv3.post(new Runnable() {
  891. @Override
  892. public void run() {
  893. while(tv3.getLineCount() >= 3){
  894. tv3.setTextSize((tv3.getTextSize())-1);
  895. }
  896. }
  897. });
  898. }
  899.  
  900. @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
  901.  
  902. @Override public void afterTextChanged(Editable s) { }
  903. };
  904.  
  905. public MyTextView extends TextView{
  906.  
  907. public void resize(String text, float textViewWidth, float textViewHeight) {
  908. Paint p = new Paint();
  909. Rect bounds = new Rect();
  910. p.setTextSize(1);
  911. p.getTextBounds(text, 0, text.length(), bounds);
  912. float widthDifference = (textViewWidth)/bounds.width();
  913. float heightDifference = (textViewHeight);
  914. textSize = Math.min(widthDifference, heightDifference);
  915. setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
  916. }
  917.  
  918. public void setTextCompat(final CharSequence text) {
  919. setTextCompat(text, BufferType.NORMAL);
  920. }
  921.  
  922. public void setTextCompat(final CharSequence text, BufferType type) {
  923. // Quick fix for Android Honeycomb and Ice Cream Sandwich which sets the text only on the first call
  924. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1 &&
  925. Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
  926. super.setText(DOUBLE_BYTE_WORDJOINER + text + DOUBLE_BYTE_WORDJOINER, type);
  927. } else {
  928. super.setText(text, type);
  929. }
  930. }
  931.  
  932. @Override
  933. public CharSequence getText() {
  934. String originalText = super.getText().toString();
  935. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1 &&
  936. Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
  937. // We try to remove the word joiners we added using compat method - if none found - this will do nothing.
  938. return originalText.replaceAll(DOUBLE_BYTE_WORDJOINER, "");
  939. } else {
  940. return originalText;
  941. }
  942. }
  943.  
  944. public void autoResizeTextView(final TextView tvContent, final View parent,
  945. final float originalSize, final int maxLine) {
  946.  
  947. tvContent.setVisibility(View.INVISIBLE);
  948.  
  949. tvContent.getViewTreeObserver()
  950. .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
  951.  
  952. private float mOriginalSize = originalSize;
  953. private float mParentWidth = 0f;
  954.  
  955. @Override
  956. public void onGlobalLayout() {
  957. // get parent width just only one time.
  958. if (mParentWidth == 0f) {
  959. mParentWidth = parent.getMeasuredWidth();
  960. }
  961.  
  962. if (tvContent.getMeasuredWidth() == mParentWidth
  963. && tvContent.getLineCount() > maxLine) {
  964. mOriginalSize -= 0.5f;
  965. tvContent.setTextSize(mOriginalSize);
  966. } else {
  967. tvContent.setVisibility(View.VISIBLE);
  968. tvContent.getViewTreeObserver()
  969. .removeOnGlobalLayoutListener(this);
  970. }
  971. }
  972. });
  973. }
  974.  
  975. textview.setLayoutParams(new LayoutParams(LinearLayout.MATCH_PARENT,LinearLayout.WRAP_CONTENT));
  976.  
  977. int GeneralApproxWidthOfContainer = 400;
  978. int GeneralApproxHeightOfContainer = 600;
  979. textview.setMaxWidth(400);
  980. textview.setMaxHeight(600);`
  981.  
  982. <TextView
  983. android:layout_width="wrap_content"
  984. android:layout_height="wrap_content"
  985. app:autoSizeTextType="uniform"
  986. app:autoSizeMinTextSize="12sp"
  987. app:autoSizeMaxTextSize="100sp"
  988. app:autoSizeStepGranularity="2sp"
  989. />
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement