学习戚继光,一边儿读别人的源码,一边儿做笔记

代码来源:https://gist.github.com/stepango/1dcf6055a80f840f9185


/*** A {@link android.widget.TextView} that ellipsizes more intelligently.* This class supports ellipsizing multiline text through setting {@code android:ellipsize}* and {@code android:maxLines}.* <p/>* Note: {@link android.text.TextUtils.TruncateAt#MARQUEE} ellipsizing type is not supported.* <p>*/
public class EllipsizingTextView extends AppCompatTextView {public static final int ELLIPSIZE_ALPHA = 0x88;private SpannableString ELLIPSIS = new SpannableString("\u2026");//能力不够,看不懂private static final Pattern DEFAULT_END_PUNCTUATION= Pattern.compile("[\\.!?,;:\u2026]*$", Pattern.DOTALL);//监听器private final List<EllipsizeListener> mEllipsizeListeners = new ArrayList<>();//非常漂亮的策略模式private EllipsizeStrategy mEllipsizeStrategy;//配合监听器服务的private boolean isEllipsized;//为了是的reset方法只需要调用一次private boolean isStale;//用来判断调用setText()的入口是 是resetText还是其它地方调用的,这种做法很酷。private boolean programmaticChange;//文本private CharSequence mFullText;private int mMaxLines;//行间距,这点儿都考虑到了,了不起。private float mLineSpacingMult = 1.0f;private float mLineAddVertPad = 0.0f;/*** The end punctuation which will be removed when appending {@link #ELLIPSIS}.*/private Pattern mEndPunctPattern;public EllipsizingTextView(Context context) {this(context, null);}public EllipsizingTextView(Context context, AttributeSet attrs) {this(context, attrs, android.R.attr.textViewStyle);}public EllipsizingTextView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);TypedArray a = context.obtainStyledAttributes(attrs,new int[]{android.R.attr.maxLines, android.R.attr.ellipsize}, defStyle, 0);setMaxLines(a.getInt(0, Integer.MAX_VALUE));a.recycle();setEndPunctuationPattern(DEFAULT_END_PUNCTUATION);final int currentTextColor = getCurrentTextColor();final int ellipsizeColor = Color.argb(ELLIPSIZE_ALPHA, Color.red(currentTextColor), Color.green(currentTextColor), Color.blue(currentTextColor));ELLIPSIS.setSpan(new ForegroundColorSpan(ellipsizeColor), 0, ELLIPSIS.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);}public void setEndPunctuationPattern(Pattern pattern) {mEndPunctPattern = pattern;}@SuppressWarnings("unused")public void addEllipsizeListener(@NonNull EllipsizeListener listener) {mEllipsizeListeners.add(listener);}@SuppressWarnings("unused")public void removeEllipsizeListener(@NonNull EllipsizeListener listener) {mEllipsizeListeners.remove(listener);}@SuppressWarnings("unused")public boolean isEllipsized() {return isEllipsized;}/*** @return The maximum number of lines displayed in this {@link android.widget.TextView}.*/public int getMaxLines() {return mMaxLines;}@Overridepublic void setMaxLines(int maxLines) {super.setMaxLines(maxLines);mMaxLines = maxLines;isStale = true;}/*** Determines if the last fully visible line is being ellipsized.** @return {@code true} if the last fully visible line is being ellipsized;* otherwise, returns {@code false}.*/public boolean ellipsizingLastFullyVisibleLine() {return mMaxLines == Integer.MAX_VALUE;}@Overridepublic void setLineSpacing(float add, float mult) {mLineAddVertPad = add;mLineSpacingMult = mult;super.setLineSpacing(add, mult);}@Overridepublic void setText(CharSequence text, BufferType type) {if (!programmaticChange) {//区分调用来源mFullText = text instanceof Spanned ? (Spanned) text : text;isStale = true;}super.setText(text, type);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);if (ellipsizingLastFullyVisibleLine()) {//严谨,学习isStale = true;}}@Overridepublic void setPadding(int left, int top, int right, int bottom) {super.setPadding(left, top, right, bottom);if (ellipsizingLastFullyVisibleLine()) {//严谨,学习isStale = true;}}@Overrideprotected void onDraw(@NonNull Canvas canvas) {if (isStale) {resetText();}super.onDraw(canvas);}/*** Sets the ellipsized text if appropriate.*/private void resetText() {int maxLines = getMaxLines();CharSequence workingText = mFullText;boolean ellipsized = false;if (maxLines != -1) {if (mEllipsizeStrategy == null) setEllipsize(null);workingText = mEllipsizeStrategy.processText(mFullText);ellipsized = !mEllipsizeStrategy.isInLayout(mFullText);}if (!workingText.equals(getText())) {//避免无用的操作programmaticChange = true;try {setText(workingText);} finally {programmaticChange = false;}}isStale = false;//切换状态//通知监听器if (ellipsized != isEllipsized) {isEllipsized = ellipsized;for (EllipsizeListener listener : mEllipsizeListeners) {listener.ellipsizeStateChanged(ellipsized);}}}/*** Causes words in the text that are longer than the view is wide to be ellipsized* instead of broken in the middle. Use {@code null} to turn off ellipsizing.* <p/>* Note: Method does nothing for {@link android.text.TextUtils.TruncateAt#MARQUEE}* ellipsizing type.** @param where part of text to ellipsize*/@Overridepublic void setEllipsize(TruncateAt where) {if (where == null) {mEllipsizeStrategy = new EllipsizeNoneStrategy();return;}switch (where) {case END:mEllipsizeStrategy = new EllipsizeEndStrategy();break;case START:mEllipsizeStrategy = new EllipsizeStartStrategy();break;case MIDDLE:mEllipsizeStrategy = new EllipsizeMiddleStrategy();break;case MARQUEE:default:mEllipsizeStrategy = new EllipsizeNoneStrategy();break;}}/*** A listener that notifies when the ellipsize state has changed.*/public interface EllipsizeListener {void ellipsizeStateChanged(boolean ellipsized);}/*** A base class for an ellipsize strategy.*/private abstract class EllipsizeStrategy {/*** Returns ellipsized text if the text does not fit inside of the layout;* otherwise, returns the full text.** @param text text to process* @return Ellipsized text if the text does not fit inside of the layout;* otherwise, returns the full text.*/public CharSequence processText(CharSequence text) {return !isInLayout(text) ? createEllipsizedText(text) : text;}/*** Determines if the text fits inside of the layout.** @param text text to fit* @return {@code true} if the text fits inside of the layout;* otherwise, returns {@code false}.*/public boolean isInLayout(CharSequence text) {Layout layout = createWorkingLayout(text);return layout.getLineCount() <= getLinesCount();}/*** Creates a working layout with the given text.** @param workingText text to create layout with* @return {@link android.text.Layout} with the given text.*/protected Layout createWorkingLayout(CharSequence workingText) {return new StaticLayout(workingText, getPaint(),getWidth() - getCompoundPaddingLeft() - getCompoundPaddingRight(),Alignment.ALIGN_NORMAL, mLineSpacingMult,mLineAddVertPad, false /* includepad */);}/*** Get how many lines of text we are allowed to display.*/protected int getLinesCount() {if (ellipsizingLastFullyVisibleLine()) {int fullyVisibleLinesCount = getFullyVisibleLinesCount();return fullyVisibleLinesCount == -1 ? 1 : fullyVisibleLinesCount;} else {return mMaxLines;}}/*** Get how many lines of text we can display so their full height is visible.*/protected int getFullyVisibleLinesCount() {Layout layout = createWorkingLayout("");int height = getHeight() - getCompoundPaddingTop() - getCompoundPaddingBottom();int lineHeight = layout.getLineBottom(0);return height / lineHeight;}/*** Creates ellipsized text from the given text.** @param fullText text to ellipsize* @return Ellipsized text*/protected abstract CharSequence createEllipsizedText(CharSequence fullText);}/*** An {@link EllipsizingTextView.EllipsizeStrategy} that* does not ellipsize text.*/private class EllipsizeNoneStrategy extends EllipsizeStrategy {@Overrideprotected CharSequence createEllipsizedText(CharSequence fullText) {return fullText;}}/*** An {@link EllipsizingTextView.EllipsizeStrategy} that* ellipsizes text at the end.*/private class EllipsizeEndStrategy extends EllipsizeStrategy {@Overrideprotected CharSequence createEllipsizedText(CharSequence fullText) {Layout layout = createWorkingLayout(fullText);int cutOffIndex = layout.getLineEnd(mMaxLines - 1);int textLength = fullText.length();int cutOffLength = textLength - cutOffIndex;if (cutOffLength < ELLIPSIS.length()) cutOffLength = ELLIPSIS.length();//真正要显示的文本CharSequence workingText = TextUtils.substring(fullText, 0, textLength - cutOffLength).trim();t("ELLIPSIS.length()", ELLIPSIS.length());t("workingText 1", workingText);final int lastLineStart = layout.getLineStart(mMaxLines - 1);final CharSequence remainder = TextUtils.ellipsize(fullText.subSequence(lastLineStart,fullText.length()), getPaint(), getWidth(), TextUtils.TruncateAt.END);t("remainder", remainder);//看不懂,可能是为了提出一些不好的边角吧while (!isInLayout(TextUtils.concat(stripEndPunctuation(workingText), ELLIPSIS))) {workingText = workingText.subSequence(0, workingText.length() - 1);/*int lastSpace = TextUtils.lastIndexOf(workingText, ' ');if (lastSpace == -1) {break;}workingText = TextUtils.substring(workingText, 0, lastSpace).trim();*/}//链接...workingText = TextUtils.concat(stripEndPunctuation(workingText), ELLIPSIS);SpannableStringBuilder dest = new SpannableStringBuilder(workingText);t("workingText 2", workingText);//神操作if (fullText instanceof Spanned) {TextUtils.copySpansFrom((Spanned) fullText, 0, workingText.length(), null, dest, 0);}return dest;}/*** Strips the end punctuation from a given text according to {@link #mEndPunctPattern}.** @param workingText text to strip end punctuation from* @return Text without end punctuation.*/public String stripEndPunctuation(CharSequence workingText) {return mEndPunctPattern.matcher(workingText).replaceFirst("");}}/*** An {@link EllipsizingTextView.EllipsizeStrategy} that* ellipsizes text at the start.*/private class EllipsizeStartStrategy extends EllipsizeStrategy {@Overrideprotected CharSequence createEllipsizedText(CharSequence fullText) {Layout layout = createWorkingLayout(fullText);int cutOffIndex = layout.getLineEnd(mMaxLines - 1);int textLength = fullText.length();int cutOffLength = textLength - cutOffIndex;if (cutOffLength < ELLIPSIS.length()) cutOffLength = ELLIPSIS.length();CharSequence workingText = TextUtils.substring(fullText, cutOffLength, textLength).trim();while (!isInLayout(TextUtils.concat(ELLIPSIS, workingText))) {int firstSpace = TextUtils.indexOf(workingText, ' ');if (firstSpace == -1) {break;}workingText = TextUtils.substring(workingText, firstSpace, workingText.length()).trim();}workingText = TextUtils.concat(ELLIPSIS, workingText);SpannableStringBuilder dest = new SpannableStringBuilder(workingText);if (fullText instanceof Spanned) {TextUtils.copySpansFrom((Spanned) fullText, textLength - workingText.length(),textLength, null, dest, 0);}return dest;}}/*** An {@link EllipsizingTextView.EllipsizeStrategy} that* ellipsizes text in the middle.*/private class EllipsizeMiddleStrategy extends EllipsizeStrategy {@Overrideprotected CharSequence createEllipsizedText(CharSequence fullText) {Layout layout = createWorkingLayout(fullText);int cutOffIndex = layout.getLineEnd(mMaxLines - 1);int textLength = fullText.length();int cutOffLength = textLength - cutOffIndex;if (cutOffLength < ELLIPSIS.length()) cutOffLength = ELLIPSIS.length();cutOffLength += cutOffIndex % 2;    // Make it even.String firstPart = TextUtils.substring(fullText, 0, textLength / 2 - cutOffLength / 2).trim();String secondPart = TextUtils.substring(fullText, textLength / 2 + cutOffLength / 2, textLength).trim();while (!isInLayout(TextUtils.concat(firstPart, ELLIPSIS, secondPart))) {int lastSpaceFirstPart = firstPart.lastIndexOf(' ');int firstSpaceSecondPart = secondPart.indexOf(' ');if (lastSpaceFirstPart == -1 || firstSpaceSecondPart == -1) break;firstPart = firstPart.substring(0, lastSpaceFirstPart).trim();secondPart = secondPart.substring(firstSpaceSecondPart, secondPart.length()).trim();}SpannableStringBuilder firstDest = new SpannableStringBuilder(firstPart);SpannableStringBuilder secondDest = new SpannableStringBuilder(secondPart);if (fullText instanceof Spanned) {TextUtils.copySpansFrom((Spanned) fullText, 0, firstPart.length(),null, firstDest, 0);TextUtils.copySpansFrom((Spanned) fullText, textLength - secondPart.length(),textLength, null, secondDest, 0);}return TextUtils.concat(firstDest, ELLIPSIS, secondDest);}}public static void t(Object... msgs) {StringBuilder text = new StringBuilder();for (Object o : msgs) {if (o == null) {text.append("null");} else {text.append(o.toString());}text.append("     ");}Log.e("AJAX", "########## " + text);}}
复制代码

源码学习之EllipsizingTextView相关推荐

  1. Shiro源码学习之二

    接上一篇 Shiro源码学习之一 3.subject.login 进入login public void login(AuthenticationToken token) throws Authent ...

  2. Shiro源码学习之一

    一.最基本的使用 1.Maven依赖 <dependency><groupId>org.apache.shiro</groupId><artifactId&g ...

  3. mutations vuex 调用_Vuex源码学习(六)action和mutation如何被调用的(前置准备篇)...

    前言 Vuex源码系列不知不觉已经到了第六篇.前置的五篇分别如下: 长篇连载:Vuex源码学习(一)功能梳理 长篇连载:Vuex源码学习(二)脉络梳理 作为一个Web前端,你知道Vuex的instal ...

  4. vue实例没有挂载到html上,vue 源码学习 - 实例挂载

    前言 在学习vue源码之前需要先了解源码目录设计(了解各个模块的功能)丶Flow语法. src ├── compiler # 把模板解析成 ast 语法树,ast 语法树优化,代码生成等功能. ├── ...

  5. 2021-03-19Tomcat源码学习--WebAppClassLoader类加载机制

    Tomcat源码学习--WebAppClassLoader类加载机制 在WebappClassLoaderBase中重写了ClassLoader的loadClass方法,在这个实现方法中我们可以一窥t ...

  6. jQuery源码学习之Callbacks

    jQuery源码学习之Callbacks jQuery的ajax.deferred通过回调实现异步,其实现核心是Callbacks. 使用方法 使用首先要先新建一个实例对象.创建时可以传入参数flag ...

  7. JDK源码学习笔记——Integer

    一.类定义 public final class Integer extends Number implements Comparable<Integer> 二.属性 private fi ...

  8. DotText源码学习——ASP.NET的工作机制

    --本文是<项目驱动学习--DotText源码学习>系列的第一篇文章,在这之后会持续发表相关的文章. 概论 在阅读DotText源码之前,让我们首先了解一下ASP.NET的工作机制,可以使 ...

  9. Vuex源码学习(五)加工后的module

    没有看过moduleCollection那可不行!Vuex源码学习(四)module与moduleCollection 感谢提出代码块和截图建议的小伙伴 代码块和截图的区别: 代码块部分希望大家按照我 ...

最新文章

  1. 华为FusionSphere概述——计算资源、存储资源、网络资源的虚拟化,同时对这些虚拟资源进行集中调度和管理...
  2. 解释一下为什么我很少jQuery
  3. Android:安卓APP开发显示一个美女,安卓APP开发显示两个美女
  4. 字符串-拆分和拼接字符串
  5. JQuery中样式标签的处理
  6. iOS:苹果内购实践
  7. openresty json mysql_openresty 前端开发入门五之Mysql篇
  8. android node编码,android studio中的Node.js
  9. 2017蓝桥杯B组:最长公共子序列(动态规划详解(配图))
  10. 基于对比学习(Contrastive Learning)的文本表示模型为什么能学到语义相似度?
  11. Struts2类型转换--浪曦视频第三讲
  12. bp教学视频完整版,BPA是什么软件
  13. java冒泡排序算法代码降序_Java排序算法总结之冒泡排序
  14. RTC 技术的试金石:火山引擎视频会议场景技术实践
  15. 李学龙当选美国计算机杰出科学家的报道,我校李学龙教授当选美国医学与生物工程院会士...
  16. php 邮件服务器 群发,发送使用PHP群发电子邮件发送使用PHP群发电子邮件(Sending mass email usin...
  17. 达人评测 酷睿i5 12450h和锐龙r7 5700u选哪个好 i512450h和r75700u对比
  18. 计算机视觉二值分类器及判别模型,基于计算机视觉的龙井茶叶嫩芽识别方法-毕业论文.doc...
  19. java ikvm viewer,通过IPMI KVM安装操作系统
  20. encodeURI()、encodeURIComponent()区别及使用场景

热门文章

  1. java个人所得税计算方法计算方法 : 全月应纳税所得额 =工资薪金所得-3500 应纳税额 = 应纳税所得额 *税率-速算扣除数
  2. scp复制文件夹,scp复制文件
  3. 电子信息工程专业的发展方向(读此明志)
  4. 计算形参x所指数组中N个数的平均值(规定所有数均为正数)
  5. 读书笔记:算法图解 using Python
  6. 2011最具技术影响力评选——图书篇(引进):2011年整个行业都在百花齐放,
  7. 【游戏】金融帝国2:金融帝国实验室(Capitalism Lab)市长模式DLC+简单教程
  8. 云服务器 linux设置Redis 的连接 详情版
  9. 服务型移动机器人如何实现室内路径全覆盖清扫给你一个清爽干净的家
  10. golang中的随机数rand