3月3日上午,南通市委书记徐惠民、市委副书记、市长王晖在通州志浩、海门叠石调研家纺市场,研究家纺市场协调发展三年行动计划,强调要牢固树立新的发展理念,促进协调发...
-
上图效果可以在微博和bilibili上找到。这里我选择继承AppCompatTextView实现。
主体
实现理念
当内容超过指定行数后,计算最大行数第一个(start)和最后一个字符(end)在整个字符串里面的位置测量要拼接的内容(demo中是... 全文)的宽度计算跟拼接内容宽度相当的字符个数(num)将整个字符串从0到(end-num)进行截取拼接要显示的内容,设置点击事件设置文字这里会有点小问题。提示内容紧跟着原文,不在TextView的边界上。点击事件用点击面板设置。如果文本视图设置了点击事件,它们将与文本视图本身的点击事件同时被触发。如果没有设置,点击换句话说,点击事件不会传输到父视图,而是被TextView消费掉。如下图:
-
先说具体实施的关键步骤:
内容截取SpannableStringBuilder span = NewsAnnablestringbuilder();
int start = layout . getlinestart(mShowMaxLine-1);
intent = layout . GetLineEnd(MsHowMaxLine-1);
if(mTipGravity == END) {
TextPaint paint = getPaint();
string builder builder = NewStringBuilder(ELLIPSize _ END)。追加(" ")。追加(MFoldText);
end-= paint . BreakText(Moriginaltext,start,end,false,paint . MeasureText(builder . ToString()),null);
} else{
end-;
}
当内容行数超过最大行数时,文本将被拦截。布局是TextView的布局,其中getLineStart()和getLineEnd()分别获取该行第一个和最后一个字符的位置(这里的位置是从第一个字符开始计算的)。breakText()方法计算要截取的字符数。
下面是breakText()方法的简要描述:
参数:
测量的字符串测量开始的位置测量结束的位置测量方向,true从前往后,false从后往前截取的字符串最大宽度截取字符串实际宽度最后,返回要拦截的字符数。截取内容后,对提示文本进行处理,并简要说明以下两种方法
方法1:直接拼接内容,设置点击事件
CharSequence elli psize = Moriginaltext . subsequence(0,end);
span . append(ellipsize);
span . append(ELLIPSize _ END);
if(mTipGravity == END) {
span . append(" ");
} else{
span . append(" n ");
}
intlength
if(isExpand) {
span . append(MexpandText);
length = mexpandtext . length();
} else{
span . append(mFoldText);
length = mfoldtext . length();
}
if(mTipClickable) {
span.setSpan(mSpan,span.length() - length,span.length(),Spanned。SPAN _ INCLUSIVE _ EXCLUSIVE
setMovementMethod(Linkmovementmethod . GetInstance());
}
span . set span(NewForeGroundColorspan(MTIPColor),span.length() - length,span.length(),跨区数。SPAN _ INCLUSIVE _ EXCLUSIVE
}
super.setText(span,type);
通过SpannableString将文本拼接在截取的内容上,并设置相应的点击事件。
方法二:重写onDraw()方法绘制提示文本,重写onTouchEvent()设置click事件
折叠状态
@覆盖
protectedvoidonDraw(画布画布){
super . ondraw(canvas);
if(isOverMaxLine & amp;& amp!isExpand) {
//折叠
if(mTipGravity == END) {
minx = getwidth()-getpaddingslip()-getpaddinglight()-gettextwidth("全文");
maxX = getWidth()-getpadding left()-getpadding right();
minY = getHeight() - (getPaint()。getFontMetrics()。下降- getPaint()。getFontMetrics()。ascent)-getPaddingBottom();
maxY = getHeight()-getPaddingBottom();
Canvas.drawText("全文",minX,
getHeight() - getPaint()。getFontMetrics()。下降- getPaddingBottom(),mPaint);
} else{
minX = GetPaddingLeft();
MaxX = minX+getTextWidth("全文");
minY = getHeight() - (getPaint()。getFontMetrics()。下降- getPaint()。getFontMetrics()。ascent)-getPaddingBottom();
maxY = getHeight()-getPaddingBottom();
Canvas.drawText("全文",minx,getheight ()-getpaint()。getfontmetrics()。depression-getpadding bitmap(),MPa int);
}
}
}
文本截取后,重写onDraw()方法计算坐标,绘制文本。
PS: minx、maxx、miny、maxy四个值用于后续的点击事件,如果不需要可以忽略。这四个值分别对应于提示左上角和右下角的坐标。
扩展状态
//文本扩展
SpannableStringBuilder span enable = NewsAnnablestringbuilder(Moriginaltext);
if(IsShowTiptafterExpand){
Spannable.append("折叠全文");
span enable . set SPan(NewForeGroundColorSPan(MTipColor),span enable . length()-5,span enable . length(),跨区数。SPAN _ INCLUSIVE _ EXCLUSIVE
}
super . SetText(span enable,type);
这里的坐标计算比上面稍微复杂一点,这里的提示可能会换线。
所以要多加一个变量才能多记录一个y值。
intmLineCount = getLineCount();
layout layout = GetLayout();
minx = getpadding foot()+布局。get primary水平(spannable。tostring()。last index of(" closed ")-1);
maxx = getpaddingslip()+layout . getsecondariholizontal(span enable . tostring()。last indexof(" text ")+1);
rect bound = NewRect();
if(mLineCount & gt;originalinecount){
//不在一条线上
layout . getlinebounds(originalinecount-1,bound);
minY = getPaddingTop()+bound . top;
middleY = minY + getPaint()。getFontMetrics()。下降- getPaint()。getFontMetrics()。上升;
maxY = middleY + getPaint()。getFontMetrics()。下降- getPaint()。getFontMetrics()。上升;
} else{
//同一行
layout . getlinebounds(originalinecount-1,bound);
minY = getPaddingTop()+bound . top;
maxY = minY + getPaint()。getFontMetrics()。下降- getPaint()。getFontMetrics()。上升;
}
PS:这里我选择直接拼接的方法。如果展开状态也需要贴边界,请参考折叠状态自行实现。
最后,重写onTouchEvent()来设置点击事件
@覆盖
public booleanTouchEvent(MotionEvent事件){
if(mTipClickable) {
switch(event . Getactionmasked()){
caseMotionEvent。动作_向下:
click time = system . current timemillis();
if(!isClickable()) {
if(isInRange(event.getX()、event . GetY()){
returntrue
}
}
打破;
caseMotionEvent。操作_取消:
caseMotionEvent。动作_向上:
long deltime = system . current timemillis()-点击time;
点击时间= 0L
if(DelTiME & lt;view configuration . gettaptimeout()& amp;& ampis RanGe(event . GetX()、event . GetY()){
isExpand =!isExpand
setText(Moriginaltext);
returntrue
}
打破;
默认:
打破;
}
}
returnsuper.onTouchEvent(事件);
}
PS: action _ down在这里,我们需要判断点击事件是否是在TextView本身设置的。如果没有,我们需要人工retrun true,否则点击事件无法传输。如果点击范围太小,我们可以自行调整isInRange方法。
让我们看看方法1中两个问题的原因
我们先来看看TextView的onTouchEvent()方法
privateavotixficfocusableandclickablesettings(){
如果(移动!= null|| (mEditor!= null & amp& ampmEditor.mKeyListener!= null)) {
setFocusable(FOCUSABLE);
setClickable(true);
setLongClickable(true);
} else{
setFocusable(FOCUSABLE _ AUTO);
setClickable(false);
setLongClickable(false);
}
}
发现这里的设置被更改了,导致了上面的一系列问题。因此,我们还需要在设置了ClickableSpan之后调用
setFocusable(false);
setClickable(false);
setLongClickable(false);
这样,事件就可以传递给父视图
初二上册生词和四字词 扫盲一 合适(合适)(不合适)(景色宜人) 实(果)(诚)(实) 颜色(金色)(风景)(颜色) 华(中国)(华丽)(中国) 谷(粟)(谷)(粮) 金色(金色)(金色)(金...
优惠券是拼多多商家提高转化率和客户单价的重要工具。之前我给商家介绍过,品多多哪些优惠券可以叠加,哪些不可以;另外要了解叠加规则,叠加后如何计算价格。如果你不清...
温馨提示:阅读本文前请先点击“订阅”,每天可以免费接收智能建筑网络集成推送的网络、宽带等内容。谢谢大家的关注和转发! 其实路由器可以和手机一样智能,也可以刷机...
据The Verge报道,10月30日,在今天于硅谷圣何塞举行的2019三星开发者大会上,三星展示了一款可折叠垂直屏幕的新型手机的概念。三星没有命名这个新的概念设计。该设备...
距离上次销售时间已经快五个月了。今天三星折叠屏手机Galaxy Fold在韩国正式上线。为什么要等到现在?原来之前手机折叠屏有问题,官方要撤改。在出售之前,该官员还强...
最近有网友回应,复制粘贴到朋友圈的一大块文字被折叠,只显示一行灰色背景色。只有点击了这一行文字,才能看到全文。对此,腾讯公关总监张军回应称,这是朋友圈原有的保护...
最后一英里旅行 总有一些折叠车 酪。这样真的方便吗?? 。。。 然而,今天将要推出的折叠自行车可能会让你眼前一亮,因为它真的可以装进包里。。。 就像这样轻松地放进...