精华内容
下载资源
问答
  • 产品span图
    2021-06-12 03:35:21

    在我的shopify产品页面上,我设置了它,所以当我点击色样时,会打印出颜色选择。它遵循本文的原则:

    我的第二个目标是,当选择其中一种颜色时,我可以打印出具有该颜色描述的页面的page.content。

    我遇到的问题是,当我尝试将变量(在.liquid中)设置为等于正在打印的颜色时,我无法获取内容,因为它正从.js文件传递到.liquid文件通过类(.liquid中的span的实际内容为空)。

    以下是代码示例,以便您了解:

    .js文件

    if (variant.option1) {

    var fabric = variant.title;

    fabric = fabric.replace(/\s+/g, '-').toLowerCase(); //new object assigned to var str

    var fabricContent = fabric

    $('.variant-fabric-name').text(variant.option1);

    if (variant.title) {

    $('.variant-fabric-description').text(fabricContent);

    }

    .liquid文件。

    {% if product.options[0] %}

    {% capture my_variable %}{% endcapture %}

    {% endif %}

    我已经使用了变体标题,并将其设置为小写,并在单词之间添加了一个短划线,以便它可以是我可以创建并匹配的页面句柄。

    正如您所看到的,我正在尝试将fabricContent(页面句柄)的值放入.liquid变量my_variable中,以便我可以将其输入页面[page] .content代码,但我不能因为跨度是实际上是空的

    更多相关内容
  • 通过对浮选产品的粒度分析发现,SPAN80对粗粒级浮选的促进作用要大于细粒级,而且对>0.25mm的粗粒作用效果更加明显。此外,还研究了SPAN80的促进作用机理,发现SPAN80对煤油产生了乳化作用,改变了煤表面的润湿性,并消除...
  • 大唐移动SPAN ADT自动路测产品介绍v10.pptx
  • 使用ImageSpan图片不能与文字对齐问题实现如下产品需求 - 1. 图片与文字中间对齐 - 2. 文字不能超过三行,多余使用…,但是保持价格可见。实现功能一:图片与文字中间对齐看到设计就想到使用TextView....

    Android使用ImageSpan,图片不能与文字对齐问题

    实现如下产品需求
    - 1. 图片与文字中间对齐
    - 2. 文字不能超过三行,多余使用…,但是保持价格可见。

    实现功能一:图片与文字中间对齐

    看到设计图就想到使用TextView.drawableLeft属性,加上Html,发现图片居中于全部文字,而不是居中与第一行文字。后面采用Html.img,代码如下:

            String text = String.format(Locale.CHINA, getResources().getString(R.string.qa_channel_ques_str), imageHtml, this.quesStr, price);
    
            setText(Html.fromHtml(text, getQuestionImageGetter(), null));
        private Html.ImageGetter getQuestionImageGetter(){
            final int textSize = (int) getTextSize();
            return new Html.ImageGetter() {
                public Drawable getDrawable(String source) {
                    InsetDrawable insetDrawable = new InsetDrawable(mIconDrawable, 0, 0, (int) dipRight, (int) dipBottom);
                    insetDrawable.setBounds(0, 0, textSize, textSize);
                    return insetDrawable;
                }
            };
        }
    <string name="qa_channel_ques_str"><![CDATA[<src src="%1$s">&nbsp;%2$s<font color="#999999">(¥%3$s)</font>]]></string>

    如果不设置android:lineSpacingExtra属性时,能很好的显示,但是如果设置了该属性后,图片会下移,占用行间距:如图

    这一点很烦人,没办法只好先究其原因。发现,Html.fromHtml会一步步解析给定的在String里面包含的标签,如标签会最终生成一个ImageSpan,传递一个TextView,最红会调用ImageSpandraw()方法,这个方法在DynamicDrawableSpan实现

    @Override
    public void draw(Canvas canvas, CharSequence text,
                     int start, int end, float x, 
                     int top, int y, int bottom, Paint paint) {
        Drawable b = getCachedDrawable();
        canvas.save();
        //计算画笔移动距离
        int transY = bottom - b.getBounds().bottom;
        if (mVerticalAlignment == ALIGN_BASELINE) {
            transY -= paint.getFontMetricsInt().descent;
        }
        //移动画笔
        canvas.translate(x, transY);
        b.draw(canvas);
        canvas.restore();
    }

    可以看到就是应为移动了画笔,所以图片才会不与上面的文字对齐,想办法自己重新一个就可以了。但是如果使用Html.fromHtml这个ImageSpan是在`Html自己生成的,如法传入自定义的ImageSpan,但是发现方法public static Spanned fromHtml(String source, ImageGetter imageGetter, TagHandler tagHandler)可以传入自定义的TagHandler

        private class ImageHandler implements Html.TagHandler {
    
            private boolean isFirst = false;
            private int textSize;
    
            ImageHandler(float textSize) {
                this.textSize = (int) textSize;
            }
    
            @Override
            public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
    
                if (!"drawable".equalsIgnoreCase(tag) || tag == null || isFirst) {
                    return;
                }
                InsetDrawable insetDrawable = new InsetDrawable(mIconDrawable, 0, 0, (int) dipRight, (int) dipBottom);
                insetDrawable.setBounds(0, 0, textSize, textSize);
    
                isFirst = true;
                int len = output.length();
                output.append("\uFFFC");
                //设置自定义ImageSpan
                output.setSpan(new MyImageSpan(insetDrawable), len, output.length(),
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    
    }

    MyImageSpan这个直接拷贝ImageSpan代码,主要修改器父类DynamicDrawableSpandraw

    @Override
    public void draw(Canvas canvas, CharSequence text,
                     int start, int end, float x,
                     int top, int y, int bottom, Paint paint) {
        Drawable b = getCachedDrawable();
        canvas.save();
        //与descent线对齐
        canvas.translate(x, paint.getFontMetricsInt().descent);
        b.draw(canvas);
        canvas.restore();
    }

    最终调用

    public void setTextStr(String quesStr, String price) {
        if (quesStr == null || price == null) {
            return;
        }
        priceWordCount = price.length() + PRICE_EXTRA_WORD_COUNT;
        this.quesStr = quesStr;
        this.quesPriceStr = price;
    
        String text = String.format(Locale.CHINA, getResources()
                .getString(R.string.qa_channel_ques_str), "", this.quesStr, price);
    
        setText(Html.fromHtml(text, null, new ImageHandler(getTextSize())));
    }

    效果如下:

    实现功能二:文字不能超过三行,多余使用…,但是保持价格可见

    上图可以看到超过三行之后,在问题的后面是显示了...,但是价格依然在那里。这又是如何做到的的呢?

    基本思路是:先让TextView自己测量,在绘制之前,判断是否超过三行,如果超过则获取三行最后一个字符的位置,然后减去价格字符窜的字数,然后重新调用setText()方法。

    @Override
    protected void onDraw(Canvas canvas) {
        if (getLineCount() > MAX_LINE) {
            //获取指定行数的最后一个字的位置
            int endLineNum = getLayout().getLineEnd(MAX_LINE - 1) - priceWordCount;
            if (endLineNum > 0) {
                this.quesStr = this.quesStr.substring(0, endLineNum) + "...";
                setTextStr(quesStr, quesPriceStr);
            }
            //下次如果还是超过指定行数,增加价格字数,知道不超过三行
            PRICE_EXTRA_WORD_COUNT++;
            return;
        }
        super.onDraw(canvas);
    }

    完整TextView:代码:

    public class QAQuestionView extends AppCompatTextView {
        protected final int MAX_LINE = 3;
        protected  int PRICE_EXTRA_WORD_COUNT = 3;
        private int priceWordCount = 0;
        private String quesStr;
        private String quesPriceStr;
    
        private Drawable mIconDrawable;
    
        public QAQuestionView(Context context) {
            this(context, null);
        }
    
        public QAQuestionView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public QAQuestionView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mIconDrawable = getResources().getDrawable(R.drawable.icon_ask_blue);
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            if (getLineCount() > MAX_LINE) {
                //获取指定行数的最后一个字的位置
                int endLineNum = getLayout().getLineEnd(MAX_LINE - 1) - priceWordCount;
                if (endLineNum > 0) {
                    this.quesStr = this.quesStr.substring(0, endLineNum) + "...";
                    setTextStr(quesStr, quesPriceStr);
                }
                //下次如果还是超过指定行数,增加价格字数,知道不超过三行
                PRICE_EXTRA_WORD_COUNT++;
                return;
            }
            super.onDraw(canvas);
        }
    
    
        public void setTextStr(String quesStr, String price) {
            if (quesStr == null || price == null) {
                return;
            }
            priceWordCount = price.length() + PRICE_EXTRA_WORD_COUNT;
            this.quesStr = quesStr;
            this.quesPriceStr = price;
    
            String text = String.format(Locale.CHINA, getResources()
                    .getString(R.string.qa_channel_ques_str), "", this.quesStr, price);
    
            setText(Html.fromHtml(text, null, new ImageHandler(getTextSize())));
        }
    
        private class ImageHandler implements Html.TagHandler {
    
            private boolean isFirst = false;
            private int textSize;
    
            ImageHandler(float textSize) {
                this.textSize = (int) textSize;
            }
    
            @Override
            public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
    
                if (!"drawable".equalsIgnoreCase(tag) || tag == null || isFirst) {
                    return;
                }
                InsetDrawable insetDrawable = new InsetDrawable(mIconDrawable, 0, 0, 0, 0);
                insetDrawable.setBounds(0, 0, textSize, textSize);
    
                isFirst = true;
                int len = output.length();
                output.append("\uFFFC");
                //设置自定义ImageSpan
                output.setSpan(new MyImageSpan(insetDrawable), len, output.length(),
                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    
    }
    展开全文
  • Zipkin的Span模型

    千次阅读 2018-01-17 17:29:44
    本文将详细介绍Zipkin的Span模型,以及其他“另类”Span模型的设计。  这里多一句嘴,其实专业点的叫法应该是分布式追踪系统——Distributed TracingSystem,跟踪比较适合用于人的场景,比如某人被跟踪了,而追踪...

    zipkin 加上监控的功能+ 通过 tracid 将如虎添翼. 稳定性监控和定位都搞定了.

    本文将详细介绍Zipkin的Span模型,以及其他“另类”Span模型的设计。

              这里多一句嘴,其实专业点的叫法应该是分布式追踪系统——Distributed TracingSystem,跟踪比较适合用于人的场景,比如某人被跟踪了,而追踪更适合用于计算机领域。然并卵?本文将继续使用“跟踪”。

            Zipkin的Span模型几乎完全仿造了Dapper中Span模型的设计,我们知道,Span用来描述一次RPC调用,所以一个RPC调用只应该关联一个spanId(不算父spanId),Zipkin中的Span主要包含三个数据部分:

    • 基础数据:用于跟踪树中节点的关联和界面展示,包括traceId、spanId、parentId、name、timestamp和duration,其中parentId为null的Span将成为跟踪树的根节点来展示,当然它也是调用链的起点,为了节省一次spanId的创建开销,让顶级Span变得更明显,顶级Span中spanId将会和traceId相同。timestamp用于记录调用的起始时间,而duration表示此次调用的总耗时,所以timestamp+duration将表示成调用的结束时间,而duration在跟踪树中将表示成该Span的时间条的长度。需要注意的是,这里的name用于在跟踪树节点的时间条上展示。
    • Annotation数据:用来记录关键事件,只有四种,cs(Client Send)、sr(Server Receive)、ss(Server Send)、cr(Client Receive),所以在Span模型中,Annotation是一个列表,长度最多为4。每种关键事件包含value、timestamp和endpoint,value就是cs、sr、ss和cr中的一种,timestamp表示发生的时间,endpoint用于记录发生的机器(ip)和服务名称(serviceName)。可以很自然的想到,cs和cr、sr和ss的机器名称是相同的,为了简单起见,cs和cr的服务名称可以一样,sr和ss的服务名称可以一样。Annotation数据主要用于用户点击一个Span节点时展示具体的Span信息。
    • BinaryAnnotation数据:我们并不满足在跟踪树上只展示调用链的时间信息,如果需要绑定一些业务数据(日志)的话,可以将数据写入BinaryAnnotation中,它的结构和Annotation数据一模一样,在Span中也是一个列表,这里就不再阐述,但BinaryAnnotation中不宜放太多数据,不然将导致性能和体验的下降。



    1.

    2.

    3.

    这两个图的区别是 图1 spandId 代表着一次夸度调用.,Zipkin的设计那样,需要传递traceId、spanId还有parentSpanId

    图2 spanId 代表着 服务器节点 id.   都调用 server2,server3的 spanId 和 parentId都相同,无法区分.

    图3 spanId 同图2, 但是没有了 parentId, 多了个 childSpandId. childSpanId由父亲节点生成并传递给子节点.只需要传递 cspandId.

    [1]  分布式跟踪系统(二):Zipkin的Span模型


    展开全文
  • 通过对浮选产品的粒度分析,发现SPAN80对粗粒级浮选的促进作用要大于细粒级,而且对>0.25mm的粗粒作用效果更加明显;此外,还研究了SPAN80的促进作用机理,发现SPAN80对煤油产生了乳化作用,改变了煤表面的润湿性,并通过氢...
  • 前言 我们现在在 Android App 中几乎天天都能见到 ImageSpan,比如 App 自定义的 emoji ...要做这玩意儿肯定还是产品提的需求啦,想自己原创一些比较 贱 的表情吧。现在好多输入法都自带的 emoji 只是一串字符,Te...

    前言

    我们现在在 Android App 中几乎天天都能见到 ImageSpan,比如 App 自定义的 emoji 表情和文本中带的一些小图标等。


    你可能要问了既然都有 emoji 了,为啥还要自定义呢,输入法里的 emoji 和 ImageSpan 的有啥不一样呢?。要做这玩意儿肯定还是产品提的需求啦,想自己原创一些比较 的表情吧。现在好多输入法都自带的 emoji 只是一串字符,TextView 在渲染的时候会用系统自带的表情把它们画出来,而ImageSpan的话就需要自己手动画对应的图片。
    我在使用ImageSpan的过程中也遇到了一些坑,在这里就做下总结,分享出来,有什么不对的地方,也请各路大佬批评指正。

    ImageSpan

    1、ImageSpan 来自 ReplacementSpan


    ReplacementSpan中空实现了updateMeasureStateupdateDrawState

    /**
     * This method does nothing, since ReplacementSpans are measured
     * explicitly instead of affecting Paint properties.
     */
    public void updateMeasureState(TextPaint p) { }
    
    /**
     * This method does nothing, since ReplacementSpans are drawn
     * explicitly instead of affecting Paint properties.
     */
    public void updateDrawState(TextPaint ds) { }
    

    而新增了getSizedraw来进行图片位置的确定以及图片内容的绘制

    
    /**
     * Returns the width of the span. Extending classes can set the height of the span by updating
     * attributes of {@link android.graphics.Paint.FontMetricsInt}. If the span covers the whole
     * text, and the height is not set,
     * {@link #draw(Canvas, CharSequence, int, int, float, int, int, int, Paint)} will not be
     * called for the span.
     *
     * @param paint Paint instance.
     * @param text Current text.
     * @param start Start character index for span.
     * @param end End character index for span.
     * @param fm Font metrics, can be null.
     * @return Width of the span.
     */
    public abstract int getSize(@NonNull Paint paint, CharSequence text,
                        @IntRange(from = 0) int start, @IntRange(from = 0) int end,
                        @Nullable Paint.FontMetricsInt fm);
    
    /**
     * Draws the span into the canvas.
     *
     * @param canvas Canvas into which the span should be rendered.
     * @param text Current text.
     * @param start Start character index for span.
     * @param end End character index for span.
     * @param x Edge of the replacement closest to the leading margin.
     * @param top Top of the line.
     * @param y Baseline.
     * @param bottom Bottom of the line.
     * @param paint Paint instance.
     */
    public abstract void draw(@NonNull Canvas canvas, CharSequence text,
                              @IntRange(from = 0) int start, @IntRange(from = 0) int end, float x,
                              int top, int y, int bottom, @NonNull Paint paint);
    
    

    getSize中的各个参数注释中已经解释的很清楚啦,但是这个FontMetricsInt是干啥的,注释中是我们可以通过它改变高度。其实它还会改变绘制图片时候的基线baseline和 TextView 的布局,布局的问题稍后再说,这个baseline又是啥呢,这个网上资料就太多了,简单的说就是文字的绘制都是通过这个baseline对齐的,除此之外还有topascentdescentbottomleading,可以参考下图,详细的就需要上网查资料吧。顺便附上扔物线大神的HenCoder教程: 自定义 View 1-3 drawText() 文字的绘制

    draw方法就比较直白一点,就是画图嘛(当然需要一定的自定义绘制基础,不懂的可以参考上面的HenCoder教程),其中的y就是刚才说的baseline,整个一行的文本(或图片)都是以他对齐的,draw方法需要注意的是在使用ellipsize时要自己处理(你说的你行你上呀,画布画笔都给你了,省略号也自己画吧)。
    而继承它的DynamicDrawableSpan只是简单的实现了ALIGN_BOTTOMALIGN_BASELINE两种对齐方式,同时给了public abstract Drawable getDrawable();让其子类实现获得图片资源的方法,而继承DynamicDrawableSpanImageSpan则实现了该方法,提供了通过drawableresouce iduri等方式获得图片的方法。
    由此可见,DynamicDrawableSpanImageSpan其实没有干太多的事情,真正要用好ImageSpan还是需要熟悉getSizedraw两个方法,接下来就稍微深入地讨论下这两个方法使用过程中的坑。

    2、ImageSpan 的 getSize 和 draw 都干了啥

    其实这两个方法的实现都在DynamicDrawableSpan中,getSize简单粗暴的设置了FontMetricsIntfm.top = fm.ascent = -drawable高度; fm.bottom = fm.descent = 0;,并返回drawable的宽度,乍一看没问题,但是这一块是有坑的,稍后详细说。
    draw方法中处理了对齐方式,底部对齐的就设置transY = bottom - b.getBounds().bottom;,然后把画布挪过去再进行绘制。基线对齐的还要transY -= paint.getFontMetricsInt().descent;,原因是baselinebottom上面距descent的地方,所以底部对齐后再减去descent就与baseline对齐了。
    注:这里的“底部对齐”指的是整行文本的底部,而不是文字的底部
    接下来就来试一下不同对齐的效果吧。

    图中的笑脸从左到右,第一个是ALIGN_BOTTOM,第二个是ALIGN_BASELINE,用了三种字号来展示效果,图中红线大致就是baseline的位置。
    接下来重写下draw方法,搞一个顶部对齐的ImageSpandraw的时候把画布移动到顶部canvas.translate(x, top);,效果如下图所示,第三个就是顶部对齐的。

    3、居中对齐的 ImageSpan 怎么搞

    当然,我们最想看的还是文字居中对齐,看起来更舒服一点。既然要与文字对齐,那就需要有与文字对齐的参考系,上面用的bottomtop注释中也都写了,是Bottom of the lineTop of the line,所以它们都是整行的,而不是文字的,要想与文字对齐,只能用baseline,因为绘制文字时也是以它对齐,然后再算出图片需要相对偏移多少就行了。
    那么问题就来了,图片的baseline在哪里呢?这就要用到之前提到过的getSize中的FontMetricsInt,它设置了图片的ascentdescent等东西,其实也就设置了baseline的相对位置,这里注意的是,ascentdescent都是参考baseline的,以baseline = 0ascent < 0在上面,descent > 0在下面。从DynamicDrawableSpangetSize实现中可以知道图片的baseline是与descent重合的,要与文字居中就是文字的ascentdescent要和图片的居中,这样我们知道了图片的baseline,就可以确定图片与文字居中对齐时的位置了。


    上图中绿线为文字的ascent,红线是baseline,蓝线是文字的descent,黄线是图片的ascenttop。设transY为画布最终要偏移的纵坐标,ybaseline坐标,fm为文字的FontMetricstextHeight = fm.descent - fm.ascent为文字高度,drawableHeight为图片高度。
    首先图片是与文字baseline对齐的,我们要先把图片底部与文字的descent对齐,transY = y - fm.descent

    图片与文字的高度差为offsetHeight = textHeight - drawableHeight,图片在往上移动一半的高度差,transY -= offsetHeight / 2得到图片底部坐标,再减去图片的高度就得到最终的纵坐标偏移量,trasnY -= drawableHeight
    化简下就是transY = y + (fm.descent + fm.ascent) / 2 - drawableHeight / 2

    当然你也可以理解为,y + (fm.descent + fm.ascent) / 2得到文字中间的纵坐标,在减去drawableHeight / 2得到图片顶部的位置。
    最终绘制出来的效果如下图,从左数第四个笑脸就是居中对齐的:

    一切都是那么的美好,放在不同大小的字体中都显得十分的和谐,但如果文章就写到这里,那就各位观众老爷太不负责了。
    当我们还沉浸在“居中对齐”的美好中时,QA 同学突然提 Bug 了:“你这个图片底部怎么被截了一部分?”,“。。。啥?”

    和谐自由间的笑脸,之前为了显示清楚,也为了扩大TextView的画布范围,我给它们都加了padding,现在把padding都设为0就出现了这种情况。究其原因,居中对齐相对其他对齐方式都往下移了一小部分,导致ImageSpan绘制的图片超出了TextView的范围,所以就画不出来了。
    要解决这类问题就要用到最开始说的能够改变baseline和布局的getSize。大致浏览下TextView的源码也能看到,TextViewonMeasure时会通过它的Layout去计算高度,在StaticLayout中会有Span高度计算之类的代码,TextViewLayout通过计算一行文本或Span的高度生成一些LineHeightSpan用于表示每行的高度,这里就不再深入源码了,免得无法自拔。

    简单画下示意图,红线表示bottom,绿框表示文字计算出的区域,蓝色是图片计算的区域。图片为了居中对齐往下挪了一点,导致上面留出了空白,而下面缺画不出来了。我们可以通过重写getSize来改变图片计算的绘制区域,从而改变TextView测量时得到的绘制范围,图片就能正常绘制出来了。
    这部分代码比较简单,原理也跟draw居中对齐的处理类似,就直接贴代码了。

    @Override
        public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
    //        return super.getSize(paint, text, start, end, fm);
            Drawable d = getDrawable();
            Rect rect = d.getBounds();
    
            float drawableHeight = rect.height();
            Paint.FontMetrics paintFm = paint.getFontMetrics();
            float textHeight = paintFm.descent - paintFm.ascent;
    
            if (fm != null) {
                float textCenter = (paintFm.descent + paintFm.ascent) / 2;
                fm.ascent = fm.top = (int) (textCenter - drawableHeight / 2);
                fm.descent = fm.bottom = (int) (drawableHeight + fm.ascent);
            }
    
            return rect.right;
        }
    


    效果也很直观,每一行最右边的是修改后的居中对齐ImageSpan,倒数第二个是没有重写getSize的,它也由于扩宽了显示范围而显示完整了,布局大致如下图所示。

    由于图片的绘制区域整体往下移了一点,TextView的这一整行都被顶高一点,这在TexView上倒是没啥影响,但在EditText上就不一样了。你想呀,本来只有文字的时候是这么高,加了图片(表情)之后这一行变高了,就会抖动一下,删掉时也会抖一下。大家可以拿微信试一下,在纯文本加第一个表情,或者纯表情加第一个文本的时候,都会轻微地抖一下,也都是这个原因。
    这种抖动的问题也不是不能解决,其实在getSize的时候把图片高度设置成和文字高度一样,再手动把图片的Bitmap调整到对应大小,重写getDrawable自己做下图片缓存,就没问题了。但是这样也带了性能损耗和内存浪费,有点得不偿失,怎么选还是看需求吧。

    4、Ellipsize 的省略号被“吃”掉了


    这三行文本,第一行在字上加一个ImageSpan,第二行在各加一个,第三行把后面的也加上ImageSpan。可以明显看出省略号被ImageSpan掉了。
    要解决这个问题就要知道啥时候是倒末尾了,不能在往后画了。其实TextViewLayout中有getEllipsisStartgetEllipsisCount可以知道哪里被省略了,但draw里面并没有TextView的引用,而且你拿到的text里的内容虽然变了,但它的长度还是折叠之前的长度(WTF),那怎么办呢?

    不知道你有没有想过,那既然text被折叠了,但它的长度又没变,那省略号后面的是啥东西呢。

    这个没问题。

    这个就是我们折叠后的省略号,它不是三个'.',而是一个字符'…'

    再往后,一直到最后就都是这玩意儿了'\uFEFF',上网一查,原来是 BOM(Byte Order Mark)Big-Endian 时为'\uFEFF'Little-Endian时为'\uFFFE',这些字符不影响显示,但影响长度判断,需要去掉。在draw的前面加上

    text = text.toString().replace("\uFEFF", "").replace("\uFFFE", "");
    if (start >= text.length()) {
        return;
    }
    

    这里为了安全起见,把'\uFFFE'也给替换掉,这样超过省略号的部分也就不会再绘制了。

    但是省略号还没画出来,为了把它也画出来,我们需要自己判断下当前传给我们的text是不是要画'…',是的话就画'…',不是的话就画原来的图片。

    if (end > text.length()) {
        end = text.length();
    }
    String subText = text.subSequence(start, end).toString();
    if ("…".equals(subText)) {
        canvas.drawText(text, start, end, x, y, paint);
        return;
    }
    

    这样就 OK 啦!

    结束

    罗嗦了这么多,也算是把使用ImageSpan时遇到的问题说清楚了,由于没有详细研究TextView及其Layout的源码,那里讲的有问题还请各位大佬批评指正。下面附上做实验用的源码,https://github.com/funnywolfdadada/RichTextDemo。下一篇会讲一下ClickableSpan的坑和我的解决方法。

    展开全文
  • Delphi- 一些H8记录 CheckOrder方法写在uDataModConn类里. 415. Add Strings 没什么限定的话,先翻转,在一位一位加,记得进位就行了.. public class Solution { public ...在我看来线程堆栈分析技术是Java EE产品 ...
  • 设置隐藏溢出部分,但有的应用场景下我们希望内容能够自动换行,比如商城的产品信息展示里的产品名称。这里我们需要用到的就是CSS里的white-space属性。white-space 属性设置如何处理元素内的空白。相关属性值如下:...
  • HTML5中的<b> vs <span>

    2021-06-15 01:43:06
    我一直难以决定何时使用b以及何时使用span . b元素的新语义似乎含糊不清 .b元素代表一系列文本,在没有传达任何额外重要性且没有其他声音或情绪的暗示的情况下,为实用目的而引起注意听起来就像你不能使用strong,em...
  • 网页制作Webjx文章简介:我们通常的做法是,把日期写在span标签里,然后把span标签写在li里,css定义span(float:right),让span浮动在列表的右边。 近日,被同事问及一个产品列表的做法怎么实现?一个产品列表,每个...
  • span-java包含以下内容: 代码来构建您在与LiveRisk和其他项目相关的所有其他商品分析项目中所需的mongo dbs。 针对CME产品的实验跨度计算器,需要完成,但适用于许多主要的CME产品。 请参阅...
  • 目录什么是网络分路器TAP网络分路器TAP推荐产品什么是SAPN网络流量分析工具使用TAP和SPAN的区别 什么是网络分路器TAP 光纤或者电气结构的网络TAP(Test Access Point)都是提供网络可视化的基础,并且高度可靠性至关...
  • js 实现span点击倒计时

    2019-08-21 18:40:51
    <span class="btn">发送</span> var btn = document.querySelector('.btn'), sum = 10, timer; btn.onclick = function () { // 判断sum是不是在倒计时, 如果正在倒计时,点击之后不执行后面代码 if (sum ...
  • css span label 长度无效

    2021-06-13 07:54:38
    有时需要给 span 或 label 标签定义长度,例如用 span 或 label 定义表格,为了使各列对齐,就需定义每一列的长度;此时,你会发现无论怎么定义长度,span 或 label 就是保持原来的长度不变。为什么会出现这种情况呢...
  • 设置隐藏溢出部分,但有的应用场景下我们希望内容能够自动换行,比如商城的产品信息展示里的产品名称。这里我们需要用到的就是CSS里的white-space属性。white-space 属性设置如何处理元素内的空白。相关属性值如下:...
  • 锚点和div,span标签

    2021-04-06 09:47:48
    锚点 锚点的设置 给标签设置name或id属性 通过另外一个a标签href属性去链接这个锚点,可以链接到当前页面中的指定位置, ...span:文本级的标签,只能放文字、图片、表单元素等,用来修饰部分文本的效果
  • Android自定义Span示例

    2017-07-05 00:33:45
    实现它们有多种方式,比如imageView、iconfont矢量span,其中span可以方便的进行图文混排,并设置文字的样式,下面我就来介绍一种自定义imageSpan的实现。 public class FixedSizeImageSpan extends...
  • 原文地址:Underspanding spans 原文作者:Florina Muntenescu 译文出自:掘金翻译计划 ...Span 够为文字和段落设置样式,它是通过让用户使用 TextPaint 和 Canvas 等组件来实现这些功能的。在上一篇文章中,我...
  • element-ui table :span-method(行合并)

    千次阅读 2019-03-12 14:46:08
    :span-method="cellMerge">  ...... 注:后台获取数据的时候根据要在前台进行合并的字段进行排序,使要合并的字段值相同的记录依次相邻。 完整示例: :data="tableData" :span-method=...
  • SPAN总结

    2013-02-17 00:04:22
    SPAN 1、为什么需要端口镜像 ? 在进行网络故障排查、网络数据流量分析的过程中,有时需要对网络节点...通常为了部署 IDS 产品需要监听网络流量,但是在目前广泛采用的交换网络中监听所有流量有相当大的困难,...
  • 上面是产品图片【img】, 中间是提示库存信息【span】(始终存在,有库存则不显示文字,但元素占位。所以设置display:inline-block), 下面是产品名称【div】。 效果如下: 我们发现,没有文字的时候,span...
  • ProductAction.classpublic function index(){ ... //1是产品一级分类的id } $pro_data = $this-&gt;getPro($tid,$this-&gt;lang,0,1,0,0); $this-&gt;assign("pro_data",$pro_data)...
  • SPAN 是一种交换机的端口镜像技术,用于向入侵防御产品提供网络数据流,在不影响源端口的数据通信的情况下,将源端口发送或接收的数据包复制一份发送到监控端口,分为 Local SPAN(被监听者与监听端口处于同一...
  • span&gt;是两个不可缺少的元素。它们没有特别的含义,但是作用却非常大,利用&lt;div&gt;和&lt;span&gt;课余将各种HTML元素组合起来。HTML 块元素大多数 HTML 元素被定义为块级元素或内联元素。...
  • 在默认的情况下,利用css样式对span进行宽度设定是无效,但有时为了某种排版的要求,需要对span进行宽度设定,那么如何在html中利用css样式设定span的宽度? 思路:这看上去是个很简单的问题,似乎用style中的width...
  • textView 后面跟上 一个图片加文字,自然文字可配置。
  • 天旦公司基于交换机镜像端口的实时数据采集,协议解码服务

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 33,359
精华内容 13,343
热门标签
关键字:

产品span图