游戏电视苹果数码历史美丽
投稿投诉
美丽时装
彩妆资讯
历史明星
乐活安卓
数码常识
驾车健康
苹果问答
网络发型
电视车载
室内电影
游戏科学
音乐整形

用Android来开发自适应机型屏幕大小的文本控件

  需求
  自适应大小的文本:
  效果图:
  项目开发中,开发人员根据UI人员提供的一套尺寸,布局了一些带文本的页面,
  往往会少考虑一些数据极限的问题,造成机型屏幕适配问题。
  例如:
  文本(或数值)长度可变,如经验值、金币数量等,如果页面同一高度使用了多个Textview布局摆放,当Textview文本长度增加时,有可能造成重叠现象。
  例子还有很多,相信很多开发人员也都曾遇到过。
  今天我们就写一个简单的例子,解决该问题。
  我们项目中的实际需求:1。文本控件单行、居中显示;2。文本控件默认有一个固定尺寸,如果文本过多,字号自动变小,文本仍然完全显示,不折行;3。文本控件尺寸变小,文本不变,字号也自动变小,文本仍然完全显示,不折行;其实2和3仔细分析一下是一个意思:文本控件的空间不够存放当前文本时,字号自动缩小。分析
  一般的情况,很多开发者做法是继承TextView,控制其属性以达到效果。
  我们换一种做法。
  TextView文本说到底,就是一个View,而我们看到的文本,其实是通过画笔绘制在View空间(即:画布)上的。
  那么我们也使用这种方式,画笔来实现吧。
  可能有开发者会担心很难,其实一点也不难,只需要简单掌握几个基础知识(1。画布、2。画笔、3。文本绘制的计算)就可以了。
  我们自定义出来的控件代码,不会比直接继承TextView多,而且大家还能学到更多有用的知识。
  那么我们现在开始分析:
  如何在一定的空间中自适应文本的大小,使其能完全显示?
  原理很简单,就是把字号变小就行了,那么变成多小?如何计算呢?1。我们要实现的控件,只是一个文本显示,界面不复杂,所以我们不需要使用XML,只写一个自定义类即可;2。自定义类直接继承View;3。View中可获得的或者外界传入的信息(即:已知条件):3。1文本信息Text(外界传入)3。2字号最大值MaxSize(外界传入,即,我们设置的默认字号,因为字号只会缩小,不会增加,所以也叫字号最大值)3。3文本使用字号最大值应显示的宽度PreWidth(可通过Paint、Text、MaxSize获得)3。4空间的宽度canvasWidth(即画布宽度,可在View的onSizeChanged方法中获得);那么,当空间不足以显示文本时,应通过已知条件计算canvasWidth应对应的字号大小X,如何计算呢?经过分析,大字体显示的宽度与小字体显示的宽度比值应是一致的,所以,公式如下:MaxSizePreWidthxcanvasWidth;xMaxSizecanvasWidthPreWidth;x就是我们需要重新设置的字号。得到字号,我们就可以为画笔设置文字大小了,也就可以通过画笔画出合适大小的文字了。4。绘制文本,文本的坐标如何处理呢?此处我们以居中显示为例:我们可以通过文本宽高与画布宽高可计算出文字应被绘制的位置(x,y)例如:容器(即画布)宽10,高10,文字宽4,高4,我们把容器和文字分别想象成两个矩形,如何使文字矩形居中显示在容器矩形里,需要我们算出文字矩形左上角的位置(x,y),即文字绘制的位置,其实也很简单:x(容器宽文字宽)21(04)33y(容器高文字高)23如果我们直接使用这个(x,y)直接绘制文本,得到的结果是文字位置向上偏移了,这不是我们想要的结果。其实,文本绘制是根据基线(baseline)来绘制的,我们还需要了解文本绘制时的结构计算。(文本如何绘制,下面会有介绍)
  好了,基础知识点分析完了,我们先熟悉一下这些基础吧!绘图基础
  本章介绍的基础知识仅介绍当前需要用到的,不会特别细致,如果有需要,请自行查询资料。
  1。Canvas画布、Paint画笔
  我们看到的控件上的内容,其实是绘制在画布上的,而绘制是使用的画笔工具。
  画布有很多方法,如:画文本、圆、矩形、线、路径、图片等;Canvas(画布)提供的画文本的方法:publicvoiddrawText(char〔〕text,intindex,intcount,floatx,floaty,Paintpaint){thrownewRuntimeException(Stub!);}publicvoiddrawText(Stringtext,floatx,floaty,Paintpaint){thrownewRuntimeException(Stub!);}publicvoiddrawText(Stringtext,intstart,intend,floatx,floaty,Paintpaint){thrownewRuntimeException(Stub!);}publicvoiddrawText(CharSequencetext,intstart,intend,floatx,floaty,Paintpaint){thrownewRuntimeException(Stub!);}
  画笔可以设置我们想要的效果,如颜色、字体、字号、线粗细等;Paint(画笔)设置文本属性的一些主要方法:设置文本大小publicvoidsetTextSize(floattextSize){thrownewRuntimeException(Stub!);}设置颜色publicvoidsetColor(intcolor){thrownewRuntimeException(Stub!);}设置文本间距publicvoidsetLetterSpacing(floatletterSpacing){thrownewRuntimeException(Stub!);}设置文本对齐方式publicvoidsetTextAlign(Paint。Alignalign){thrownewRuntimeException(Stub!);}设置文本文字类型:如:宋体、黑体、平方等字体publicTypefacesetTypeface(Typefacetypeface){thrownewRuntimeException(Stub!);}计算文本宽度(根据设置的字号大小,要绘制的文本内容,计算并返回该文本应占用的宽度)publicfloatmeasureText(Stringtext){thrownewRuntimeException(Stub!);}。。。还有很多设置文本的方法,可以自行查找!!!
  2。文本绘制
  想把文字精准的绘制到屏幕上,
  需要了解字体测量类:FontMetrics,以及该类的top,ascent,descent,bottom,leading五个成员变量;
  如果我们想在画布的最左上角(即(0,0)位置)开始绘制文本,绘制完成后,我们看到的是如上图所示的Baseline以下的部分,而上面的部分我们是看不到的。
  原因很简单,文本的绘制,是基于Baseline的,如果我们直接设置绘制的位置是(0,0),即Baseline的位置是(0,0),如上图所示,Baseline以上的文本肯定被绘制在控件上面去了,即y为负数,所以我们看不到Baseline以上的内容。
  那么,我们应该如何做才能将文字绘制在我们想要的位置呢,其实很简单,我们只需要让Baseline的位置向下偏移就可以了,但是偏移多少呢?
  再看上图,我们只需要拿到文本的上面的几个属性(ascent等),就可以算出来了。代码实现
  自定义控件类:AutoTextViewpackageiwangzhe。customautosizetextview;importandroid。content。Context;importandroid。graphics。Canvas;importandroid。graphics。Paint;importandroid。util。AttributeSet;importandroid。view。View;importandroid。widget。TextView;类:AutoTextView作者:qxc日期:201843。publicclassAutoTextViewextendsView{privateContextcontext;上下文privateintcanvasWidth;画布宽度privateintcanvasHeight;画布高度privatePaintpaint;画笔privateintmaxTextSize50;外界传入的默认字号(最大字号),单位SP,如果不传入,我们默认50sp,大家可自行修改privateStringtext;外界传入的文本内容publicAutoTextView(Contextcontext){super(context);this。contextcontext;initPaint();初始化画笔属性}publicAutoTextView(Contextcontext,AttributeSetattrs){super(context,attrs);this。contextcontext;initPaint();初始化画笔属性}初始化画笔属性privatevoidinitPaint(){设置防锯齿paintnewPaint(Paint。ANTIALIASFLAG);设置画笔宽度paint。setStrokeWidth(1);}设置文本(供外界调用)paramtext文本publicAutoTextViewsetText(Stringtext){this。texttext;returnthis;}设置支持的最大文本字号(供外界调用)paramsize文本字号publicAutoTextViewsetMaxTextSize(intsize){this。maxTextSizesize;returnthis;}OverrideprotectedvoidonSizeChanged(intw,inth,intoldw,intoldh){super。onSizeChanged(w,h,oldw,oldh);每一次外观变化,都会调用该方法this。canvasWidthgetWidth();获得画布宽度this。canvasHeightgetHeight();获得画布高度}OverrideprotectedvoidonDraw(Canvascanvas){每次重绘,绘制传递进来的文本信息drawText(canvas);}绘制文本privatevoiddrawText(Canvascanvas){根据画布宽度,获得合适的字号(即:刚好能显示满当前宽度的字号,与maxsize相比,只能小不能大)floattextSizegetRightSize();为画笔设置上合适的字号paint。setTextSize(sp2px(textSize));计算Baseline绘制的起点X轴坐标,计算方式:画布宽度的一半文字宽度的一半intx(int)(canvasWidth2paint。measureText(text)2);intx0;计算Baseline绘制的Y坐标,计算方式:画布高度的一半文字总高度的一半inty(int)((canvasHeight2)((paint。descent()paint。ascent())2));绘制文本canvas。drawText(text,x,y,paint);}获得合适的字号privatefloatgetRightSize(){paint。setTextSize(sp2px(maxTextSize));paint。setTextAlign(Paint。Align。LEFT);根据最大值,计算出当前文本占用的宽度floatpreWidthpaint。measureText(text);如果文本占用的宽度比画布宽度小,说明不用伸缩,直接返回当前字号if(preWidthcanvasWidth){returnmaxTextSize;}已知当前文本字号、文本占用宽度、画布宽度,计算出合适的字号,并返回returnmaxTextSizecanvasWidthpreWidth;}实际绘制时,需要使用像素进行绘制,此处提供sp转px的方法privateintsp2px(floatspValue){finalfloatscalecontext。getResources()。getDisplayMetrics()。density;return(int)(spValuescale0。5f);}}
  调用方类与布局文件:MainActivity
  使用SeekBar模拟文本控件宽度变化(即:容器大小变化)lt;?xmlversion1。0encodingutf8?RelativeLayoutxmlns:androidhttp:schemas。android。comapkresandroidxmlns:toolshttp:schemas。android。comtoolsandroid:ididactivitymainandroid:layoutwidthmatchparentandroid:layoutheightmatchparenttools:contextiwangzhe。customautosizetextview。MainActivityiwangzhe。customautosizetextview。AutoTextViewandroid:layoutwidthmatchparentandroid:backgroundeeeeeeandroid:layoutheight50dpandroid:layoutmarginTop20dpandroid:ididatvSeekBarandroid:layoutwidthmatchparentandroid:layoutheightwrapcontentandroid:layoutbelowidatvandroid:layoutmarginTop50dpandroid:progress100android:ididsbRelativeLayoutpackageiwangzhe。customautosizetextview;importandroid。content。Context;importandroid。content。res。Configuration;importandroid。support。v7。app。AppCompatActivity;importandroid。os。Bundle;importandroid。widget。RelativeLayout;importandroid。widget。SeekBar;publicclassMainActivityextendsAppCompatActivity{SeekBarsb;AutoTextViewatv;OverrideprotectedvoidonCreate(BundlesavedInstanceState){super。onCreate(savedInstanceState);setContentView(R。layout。activitymain);initView();initEvent();}voidinitView(){sb(SeekBar)findViewById(R。id。sb);sb。setProgress(100);atv(AutoTextView)findViewById(R。id。atv);设置测试数据atv。setText(一二三四五六七八九十)。setMaxTextSize(50);}voidinitEvent(){使用SeekBar模拟文本控件宽度变化(即:容器大小变化)sb。setOnSeekBarChangeListener(newSeekBar。OnSeekBarChangeListener(){OverridepublicvoidonProgressChanged(SeekBarseekBar,inti,booleanb){RelativeLayout。LayoutParamslinearParams(RelativeLayout。LayoutParams)atv。getLayoutParams();linearParams。heightdip2px(MainActivity。this,50);linearParams。widthisb。getWidth()100;atv。setLayoutParams(linearParams);}OverridepublicvoidonStartTrackingTouch(SeekBarseekBar){}OverridepublicvoidonStopTrackingTouch(SeekBarseekBar){}});}publicstaticintdip2px(Contextcontext,floatdpValue){finalfloatscalecontext。getResources()。getDisplayMetrics()。density;return(int)(dpValuescale0。5f);}}
  总结:
  此控件使用起来,很简单,但是技术点很实用,以后做动态报表的自定义控件时,都会用到。
  如果大家想要增加设置文本字体、加粗、下划线等样式,请参考该示例,自行扩展即可。
  本文章,主要是为了让大家了解使用画布画笔自定义控件的过程,如果想在自己的项目中使用,请根据需要自行调整优化。

3月新游预览佳作频出,GT7幽灵线东京领衔2月随着《艾尔登法环》的发售步入尾声,在即将到来的3月还有多款制作精良的大作即将发售,包括索尼第一方赛车竞速游戏《GT7》、B社被微软收购后唯一登陆PS的《幽灵线:东京》,此外……世界杯啦啦队颜值大比拼!身材火辣长腿惹眼,多位成员撞脸明星近日,2022年卡塔尔世界杯开幕,全世界各地的球迷们摩拳擦掌,为了第一时间掌握到赛情,熬夜也在所不惜,开幕式已经结束,整体评价不错,除了亚洲歌手田柾国和中东歌手合作的solo曲……刚发表!20生信文章,工作量简直太友好了今天要分享的一篇是于2023年3月27号发表在JournalofMedicalVirology〔IF20。69〕的Integrativebulkandsinglecelltra……奥运冠军现身环球影城!谷爱凌包裹严实被认出,一身名牌装扮显时日前,炙手可热的冬奥冠军谷爱凌现身北京的环球影城,在现场谷爱凌和粉丝们亲切互动,再次展现了自己平易近人的一面,丝毫没有明星的架子。据悉,趁着难得的休息时间,谷爱凌和朋友们相约来……兔年手链一般多少钱?如何买的性价比高,可以简单看这几点今年是兔年,很多属兔的人都会在今年购买兔子饰品进行佩戴,就是为了让自己的运气变得更好。其中兔子手链是目前最受欢迎的,因为佩戴方便,并且会增添佩戴者的可爱属性。那么你知道兔年手链……建议中老年人,夏季喝菊花茶谨记三不喝二喝,才能喝好喝对导语:建议中老年人,夏季喝菊花茶谨记三不喝二喝,才能喝好喝对想必大家家里最不缺少的就是菊花茶了吧,几乎是每家必备的茶品之一,那是因为菊花茶本身的好处非常多,可谓是深受大众……TNT?平板电脑二合一?也许迷你电脑才是目前办公娱乐的最优选近几年,PC市场属实是过于安静了,自从罗老师的TNT落下帷幕后,几乎没有什么太大的创新,只有微软在孜孜不倦的宣传自家的surface。但其实,在迷你电脑这个领域,以零刻为代表的……中秋节将至,餐桌必备6道宴客菜,百吃不厌还有面子,上桌就抢光中秋节月儿圆,月圆人团圆,亲朋好友难得聚一次,所以中秋家宴一定要用心准备,怎样既能满足全家老小的口味,又能让家人感到浓浓的情谊呢?别样味道今天月月给大家分享6道中秋家宴必……U17女足世界杯2哥伦比亚凯塞多双响,末轮死磕西班牙北京时间10月15日,U17女足世界杯小组赛第二轮,中国对阵哥伦比亚。上半场中国队因为实力差距,更多是在后场进行防守,场面落于下风。哥伦比亚两次打穿中国队防线,凯塞多梅开二度。……出水芙蓉女明星怪不得前几任仍忘不掉她要说这出水芙蓉女明星指的是谁,那非殷桃莫属。现在的殷桃42岁了,身材那可不是42岁的身材更像是24岁少女的身材。最最重要的是演技在线,实力派明星。好了咱要说就……司马迁的行万里路《史记》的伟大成就,有当时的时代精神为条件,而司马迁的文化理想、学术资质、历史理念与人生意志,也都起着重要的作用。他的行旅实践,以行迹之遥远,旅程之漫长,特别是与史学考察相结合……怀斯曼在NBA夏季联赛中给人留下深刻印象,勇士变得更加可怕勇士队中锋詹姆斯怀斯曼期待已久的复出并没有让他在周日的NBA夏季联赛处子秀中失望。怀斯曼是2020年NBA选秀中的第2顺位新秀,他在身体表现中展示了他的运动能力,其中包括……
正式留队!北控顶薪内线不走了,手握600万年薪,马布里有苦难北控男篮这个休赛期还没有透露新的引援计划,可以确定的是主教练马布里不会离开,球队还引进了CBA名宿张劲松。目前,除了队内确定侯逸凡已经离队,外援方面,兰兹博格和托多罗维奇都不会……航天人10年太空之约见证载人航天跨越之旅来源:人民日报从航天任务连战连捷到重大航天工程深入推进,从空间科学探索到航天科技成果服务经济社会发展,10年来,一次次振奋人心的火箭腾飞,一项项令人惊叹的航天成就,勾勒出……国乒女将03惨败,早田希娜晋级!张本智和一轮游,猛将跪地庆祝7月14日,WTT球星挑战赛布达佩斯站展开女单116决赛较量。在师姐陈梦退赛后,刘炜珊没有顶住压力,输给日本主力早田希娜,止步32强。王艺迪在先丢一局后上演逆转,战胜徐孝元,晋……跑跑卡丁车手游传说道具车狂野鲨狂野鲨是2022年10月5日S20赛季通过幸运翻翻乐获得的一辆传说道具车。是一辆辅助上位车。使用磁铁和黄金磁铁时高概率获得的胎印导弹可以保证狂野鲨有稳定的输出和上位能力,胎印导……价值6。8亿的天下第一宴,到底都有些什么菜?一起来看看在中国新疆哈密的一座博物馆之内,竟然赫然陈列着一桌超级丰盛的菜,然而这桌菜的标价竟然达到了6。8亿,让所有观看的游客感到瞠目结舌。这一大桌菜光是桌子直接就达到16。8米,……收评A股三大指数震荡收跌,两市成交额创一年多新低金融界9月19日消息周一A股三大指数纷纷低开,随后在早盘展开震荡整理,午后一小时A股持续走弱,创业板指跌超1,随后市场止跌有所反弹。截至收盘,沪指跌0。35,报3115。……儿子婚礼父亲感人致辞儿子成亲,做父亲的无论怎样也得上台说几句!那么婚礼父亲致辞要说些什么呢?下面由品学网小编给大家带来的儿子婚礼父亲感人致辞,希望各位客官喜欢!儿子婚礼父亲感人致辞1大家好……2018区民政局工作计划范文xx年,区民政局将在区委、区政府的正确领导下,在市民政局的具体指导下,继续围绕保发展、保民生、保稳定的工作大局,以贯彻落实党的xx届四中全会会议精神为抓手,以打造诚信、贴心、高……2021年最新个人廉洁自律自查报告(通用5篇)时间过得太快,让人不知所措,工作已经告一段落了,回顾这段时间的工作,取得了成绩,也存在着问题,好好地做个总结并写一份自查报告吧。那么大家知道正规的自查报告怎么写吗?以下是小编为……中层干部培训班学习心得尊敬的各位领导:下午好!我很荣幸代表第三小组对本次培训班学习体会进行发言。这次培训内容丰富,有学习贯彻云南省第九次党代会精神的专题讲座;有深入学习贯彻省第九次……幼儿园财务管理规定范文3篇幼儿园财务应真实、准确和完整地反映财务收支情况,按月编制财务报表,按规定期限报送登记管理机关、业务主管单位和财政部门,并接受监督和检查。幼儿园的财务管理都有哪些制度?下面是相关……热门放假通知7篇在学习、工作生活中,越来越多人会去使用通知,通知是运用广泛的知照性公文。如何写一份恰当的通知呢?以下是小编收集整理的放假通知7篇,欢迎阅读,希望大家能够喜欢。放假通知篇1……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网