范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

AndroidShapeableImageView使用详解,告别shape三方库

  效果
  前言
  先来看一下ShapeableImageView是什么
  由上图可以看到ShapeableImageView也没有什么神秘的,不过是ImageView的一个子类而已,但是从效果图来看,在不写shape、不引入三方库的情况下,还是挺容易实现预期效果的,而且扩展性良好。使用引入material包implementation "com.google.android.material:material:1.2.1" 常规
  
  和ImageView正常使用没有区别圆角
  
   
  没有直接设置圆角的属性,需要用到app:shapeAppearance,后面会说cornerFamily 角的处理方式,rounded圆角,cut裁剪cornerSize 圆角大小圆
  
   
  圆角的大小可以用百分比,也可以自己计算,比如宽高100dp,圆角50dp描边
  
  app:strokeColor 描边颜色app:strokeWidth 描边宽度注意这里padding的数值是描边宽度的一半,后面会说切角
  
   
  cornerFamily:cut 处理模式变为裁剪菱形
  
   
  同样,裁剪模式下圆角大小也可以计算叶子
  
   
  cornerSizeTopLeft 左上圆角cornerSizeBottomRight 右下圆角以此类推,左上、左下、右上、右下等半圆
  
    六边形
  
   
  author:yechaoa属性
  关于xml属性,我也做了一个整理,属性不多,只有4个
  扩展
  前面为了整体的排版,埋了几个伏笔,下面来一一解答。
  会涉及到源码,但是经过去繁从简,看起来也非常轻松的。shapeAppearance
  Shape appearance overlay style reference for ShapeableImageView.ShapeableImageView的形状外观覆盖样式参考。
  前面可以看到我们设置圆角其实是用的style,那为什么不直接用attrs呢,不是更加直观方便吗,带着疑问来看看源码是怎么处理的。
  直接看ShapeableImageView的次构造方法:
  public class ShapeableImageView extends AppCompatImageView implements Shapeable {    ...    public ShapeableImageView(Context context, @Nullable AttributeSet attrs, int defStyle) {     super(wrap(context, attrs, defStyle, DEF_STYLE_RES), attrs, defStyle);     // Ensure we are using the correctly themed context rather than the context that was passed in.     context = getContext();      clearPaint = new Paint();     clearPaint.setAntiAlias(true);     clearPaint.setColor(Color.WHITE);     clearPaint.setXfermode(new PorterDuffXfermode(Mode.DST_OUT));     destination = new RectF();     maskRect = new RectF();     maskPath = new Path();     TypedArray attributes =         context.obtainStyledAttributes(             attrs, R.styleable.ShapeableImageView, defStyle, DEF_STYLE_RES);      strokeColor =         MaterialResources.getColorStateList(             context, attributes, R.styleable.ShapeableImageView_strokeColor);      strokeWidth = attributes.getDimensionPixelSize(R.styleable.ShapeableImageView_strokeWidth, 0);      borderPaint = new Paint();     borderPaint.setStyle(Style.STROKE);     borderPaint.setAntiAlias(true);     shapeAppearanceModel =         ShapeAppearanceModel.builder(context, attrs, defStyle, DEF_STYLE_RES).build();     shadowDrawable = new MaterialShapeDrawable(shapeAppearanceModel);     if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {       setOutlineProvider(new OutlineProvider());     }   } }
  常规操作,获取自定义属性。
  关键的两行代码:
  shapeAppearanceModel = ShapeAppearanceModel.builder(context, attrs, defStyle, DEF_STYLE_RES).build();     shadowDrawable = new MaterialShapeDrawable(shapeAppearanceModel);
  也就是说我们给shapeAppearance设置的style,并不是ShapeableImageView自己来处理的,而是由ShapeAppearanceModel来构建的,然后又交给MaterialShapeDrawable来绘制的。ShapeAppearanceModel
  这个类就厉害了,有点像Flutter中的Decoration,可以构建出花里胡哨的效果。
  来看ShapeAppearanceModel部分源码:
  public class ShapeAppearanceModel {    /** Builder to create instances of {@link ShapeAppearanceModel}s. */   public static final class Builder {      @NonNull     private CornerTreatment topLeftCorner = MaterialShapeUtils.createDefaultCornerTreatment();      @NonNull     private CornerTreatment topRightCorner = MaterialShapeUtils.createDefaultCornerTreatment();      @NonNull     private CornerTreatment bottomRightCorner = MaterialShapeUtils.createDefaultCornerTreatment();      @NonNull     private CornerTreatment bottomLeftCorner = MaterialShapeUtils.createDefaultCornerTreatment();      @NonNull private CornerSize topLeftCornerSize = new AbsoluteCornerSize(0);     @NonNull private CornerSize topRightCornerSize = new AbsoluteCornerSize(0);     @NonNull private CornerSize bottomRightCornerSize = new AbsoluteCornerSize(0);     @NonNull private CornerSize bottomLeftCornerSize = new AbsoluteCornerSize(0);      @NonNull private EdgeTreatment topEdge = MaterialShapeUtils.createDefaultEdgeTreatment();     @NonNull private EdgeTreatment rightEdge = MaterialShapeUtils.createDefaultEdgeTreatment();     @NonNull private EdgeTreatment bottomEdge = MaterialShapeUtils.createDefaultEdgeTreatment();     @NonNull private EdgeTreatment leftEdge = MaterialShapeUtils.createDefaultEdgeTreatment();      public Builder() {}     ...   }   ... }
  可以看到有各种边和角的属性,这里注意两个点:
  MaterialShapeUtils.createDefaultCornerTreatment() 创建默认角的处理方式MaterialShapeUtils.createDefaultEdgeTreatment() 创建默认边的处理方式
  也就意味着,边和角除了默认,是可以自定义的,这就有极大的想象空间了,比如这样:
  // 代码设置 角和边 val shapeAppearanceModel2 = ShapeAppearanceModel.builder().apply {     setAllCorners(RoundedCornerTreatment())     setAllCornerSizes(50f)     setAllEdges(TriangleEdgeTreatment(50f, false)) }.build() val drawable2 = MaterialShapeDrawable(shapeAppearanceModel2).apply {     setTint(ContextCompat.getColor(this@ShapeableImageViewActivity, R.color.colorPrimary))     paintStyle = Paint.Style.FILL_AND_STROKE     strokeWidth = 50f     strokeColor = ContextCompat.getColorStateList(this@ShapeableImageViewActivity, R.color.red) } mBinding.text2.setTextColor(Color.WHITE) mBinding.text2.background = drawable2
  再比如这样:
  // 代码设置 聊天框效果 val shapeAppearanceModel3 = ShapeAppearanceModel.builder().apply {     setAllCorners(RoundedCornerTreatment())     setAllCornerSizes(20f)     setRightEdge(object : TriangleEdgeTreatment(20f, false) {         // center 位置 , interpolation 角的大小         override fun getEdgePath(length: Float, center: Float, interpolation: Float, shapePath: ShapePath) {             super.getEdgePath(length, 35f, interpolation, shapePath)         }     }) }.build() val drawable3 = MaterialShapeDrawable(shapeAppearanceModel3).apply {     setTint(ContextCompat.getColor(this@ShapeableImageViewActivity, R.color.colorPrimary))     paintStyle = Paint.Style.FILL } (mBinding.text3.parent as ViewGroup).clipChildren = false // 不限制子view在其范围内 mBinding.text3.setTextColor(Color.WHITE) mBinding.text3.background = drawable3 MaterialShapeDrawable
  源码(有删减):
  public class MaterialShapeDrawable extends Drawable implements TintAwareDrawable, Shapeable { ...   @Override   public void draw(@NonNull Canvas canvas) {     fillPaint.setColorFilter(tintFilter);     final int prevAlpha = fillPaint.getAlpha();     fillPaint.setAlpha(modulateAlpha(prevAlpha, drawableState.alpha));      strokePaint.setColorFilter(strokeTintFilter);     strokePaint.setStrokeWidth(drawableState.strokeWidth);      final int prevStrokeAlpha = strokePaint.getAlpha();     strokePaint.setAlpha(modulateAlpha(prevStrokeAlpha, drawableState.alpha));      if (pathDirty) {       calculateStrokePath();       calculatePath(getBoundsAsRectF(), path);       pathDirty = false;     }      maybeDrawCompatShadow(canvas);     if (hasFill()) {       drawFillShape(canvas);     }     if (hasStroke()) {       drawStrokeShape(canvas);     } ...   static final class MaterialShapeDrawableState extends ConstantState {     ...     public MaterialShapeDrawableState(@NonNull MaterialShapeDrawableState orig) {       shapeAppearanceModel = orig.shapeAppearanceModel;       elevationOverlayProvider = orig.elevationOverlayProvider;       strokeWidth = orig.strokeWidth;       colorFilter = orig.colorFilter;       fillColor = orig.fillColor;       strokeColor = orig.strokeColor;       tintMode = orig.tintMode;       tintList = orig.tintList;       alpha = orig.alpha;       scale = orig.scale;       shadowCompatOffset = orig.shadowCompatOffset;       shadowCompatMode = orig.shadowCompatMode;       useTintColorForShadow = orig.useTintColorForShadow;       interpolation = orig.interpolation;       parentAbsoluteElevation = orig.parentAbsoluteElevation;       elevation = orig.elevation;       translationZ = orig.translationZ;       shadowCompatRadius = orig.shadowCompatRadius;       shadowCompatRotation = orig.shadowCompatRotation;       strokeTintList = orig.strokeTintList;       paintStyle = orig.paintStyle;       if (orig.padding != null) {         padding = new Rect(orig.padding);       }     }   ...   } ... }
  没什么特别的,你只需要知道除了可以设置描边之外,还可以设置背景、阴影等其他属性。说明ShapeAppearanceModel只能是实现Shapeable接口的View才可以设置,比如Chip、MaterialButtom等。而MaterialShapeDrawable其实就是Drawable,是所有View都可以设置的。描边问题
  这里借github一张图
  又是自定义view的常规操作,有一半画笔是在边界外面的,所以需要设置padding为strokeWidth的一半。默认圆角问题
  有细心的同学会发现啊,第一个常规的ShapeableImageView还是有一点圆角的,没错,属于默认的,跟踪一下源码来看一下:
  
  第一个是颜色,很明显不是我们要找的,继续看shapeAppearanceMediumComponent
  只是一个简单的属性,继续查找关联引用
         @style/ShapeAppearance.MaterialComponents.MediumComponent     
  又引用了一个style,继续看ShapeAppearance.MaterialComponents.MediumComponent这个style
  
  哦豁,看到了熟悉的属性cornerSize,藏的还挺深,继续看看数值是多少
  4dp
  默认4dp。
  那如果不想要这个圆角怎么办呢,可以学习源码仿写一个,不过上面也看到了,有点绕,不如直接写个style搞定:
       
  然后引用
  app:shapeAppearance="@style/Corner0Style"
  效果:
  ok,到这里就差不多了,虽然还有很多相关知识点没有提及,但是也不少了,不如自己去尝试一番,慢慢消化。Github
  https://github.com/yechaoa/MaterialDesign感谢ShapeableImageView 官方文档ShapeAppearanceModel 官方文档Android Material组件使用详解Android Notes 玩转 ShapeableImageViewMaterial Components——Shape的处理最后
  写作不易,如果对你有一丢丢帮助或启发,感谢点赞支持 ^ - ^

经常吃鸡蛋的人,要注意5点禁忌,为了家人健康,及时了解导语想必大家对鸡蛋都非常了解,不管是早中晚哪一餐,鸡蛋总会被摆上餐桌,特别是早上吃饭的时候,习惯做水煮鸡蛋,可以补充身体当中欠缺的营养。鸡蛋当中含有蛋白质较多,鸡蛋进入人体后,肠胃2个中成药,改善冠心病心绞痛,多靶点抗动脉粥样硬化,缩小斑块动脉粥样硬化的临床表现多种多样,病因也很复杂,但最根本的原因在于血液和血管内皮,血液瘀滞黏附血小板聚集高胆固醇高甘油三酯血管内皮损伤等,这些都是最基本的原因。近年来临床实践证明,活上了年纪以后,牢记不睡两觉,远离四水,关乎你的健康导语对于长寿,从古至今一直是大家共同的追求目标。但是生老病死是大自然的规律。每天都会有年老的人去世。新生命的诞生。我们没有办法改变自己走向死亡的道路。但是我们可以在这一个道路上给自长期吃素食,会对身体有危害吗?在这个全民养生时代吃素成为一种潮流因为吃素不仅能减肥改善新陈代谢还能降低心脏病等健康问题的风险一般来说,素食多指不食肉家禽海鲜等动物性食物的膳食模式,可分为不吃肉,但吃蛋类和牛奶的长期吃面条,真的对身体好吗?爱吃面条的朋友要清楚如今生活节奏越来越快,对于很多上班族来说,感觉每天的节奏特别紧凑,上完一天班回到家也会感觉到非常疲惫,很多人就不想做饭,要么点外卖,要么就会自己在家里煮一点面。不光在家里煮面条,我有个前辈告诉我静脉曲张就是一团淤血,这张方子他记了一辈子有个老中医告诉我静脉曲张就是一团淤血,这张千古名方,他记了一辈子!静脉曲张有什么表现?我们肉眼能看到,患者小腿上的青筋凸起,有的部位甚至扭曲在一起。这些青筋其实就是静脉,是血液运行很少生病的人为什么一生就是大病?医生告诉你真相平常很少生病不用吃一点药的人,一旦生病大多是较严重或者是致死型的疾病了。李大爷是一个土生土长的农村大爷,平常除了干活后还是干活基本上没有什么爱好,更不懂得养生,一辈子的憨厚农民粗茶益康耳穴支气管炎为什么总是缠着你?这个方法你知道吗?支气管炎此类病症在我们的生活中也经常遇到,此病症常有急慢性之别。急性支气管炎常因上呼吸道感染细菌和病毒,或受理化刺激而致气管或支气管的急性炎症。慢性支气管炎可由急性支气管炎反复发作颈部出现3个异常,别轻视,有可能是食道癌来了食道癌来了会有啥症状你知道吗?很多人都不愿意谈及癌症,停到癌症两个字就觉得内心充满了恐惧。在2018年的时候,全球患食道癌的人数就已经达到了57。2万了,而我国食道癌患者占据第一位别让胆囊息肉找上门都市工作节奏快,上班早的,往往为了多睡一会而放弃吃早餐上班晚的,起得迟干脆选择早午饭一起吃。殊不知,长此以往,将显著增加罹患胆囊息肉的风险。大多数的胆囊息肉症状与慢性胆囊炎非常相似吃完猪血总排黑便,意味着排毒素?猪血,真的是排毒神器?吃猪血说到猪血,几乎每个地方都有关于它的代表作。比如湖南人最爱的猪血丸子,比如广东人最爱的韭菜猪血汤,比如东北人经常做的猪血肠。。被号称为血豆腐或者是液体肉的猪血,其实营养元素也蛮
当红数播北京师旷AP20到底是哪些地方更优秀北京师旷的AP10一直以来以工作稳定性不错的声音表现以及操作方便和超高的性价比等等优势受到许多音乐爱好者的喜欢。而品牌方最新官宣的升级换代型号AP20相对比于AP10有哪些升级的地冬日幸存者开发日志UI重制与新增视觉效果大幅提升我们深知视觉设计对于游戏的重要性。因此,在这篇开发日志中,我们想要聊一聊最近一段时间里,我们对冬日幸存者UI的一些改动。我们的新UI可以分成两个部分重制与新增。关于重制部分,我们将这些千奇百怪的场馆太适合遛娃了!开飞机学木工做动画片逛公园看大展游泳嬉水,日常遛娃玩来玩去也就这么几个主题,小爱已经给大家推荐过无数遍了,有时也会自己问自己,这么大个北京城,难道就没有其他玩法了吗?能让老母亲心甘情愿带娃去,孩子也能宝妈说带娃抑郁了,监控下却是另一副面孔,宝爸有些懵世界卫生组织研究发现,约6080的女性,会在产后出现不同程度的抑郁情绪。不就是带个孩子吗,有什么好抑郁的,这或许是宝妈最不想听到的一句话了。产后抑郁不是简单地不开心,而且许多女性自暑期出游莫忘做好风险防范近日,在天津湖北两地同时发生景区游客坠落事故,造成一死一伤,其中一名游客为10岁儿童。当下正值暑假旅游旺季,也是汛期灾害易发时期,景区游乐场安全事故时有发生,这给计划出游的家长和孩骑次自行车,才更懂荷兰来源环球时报环球时报特约记者葛莉娜自行车王国荷兰多年来不断建设完善自行车道网络和配套设施打造优美宜人的骑行环境,使人们乐于骑行享受骑行。到了荷兰,游客们喜欢租一辆自行车,在城市乡村奥利教户外徒步篇36户外的不同天气穿衣法则我们要到达的地点和时间在很大程度上决定了我们的户外衣橱的构成在炎热的一天之后,沙漠之夜会变得异常寒冷。我们可能在高山雪原上,在令人惊叹的正午炎热中汗流浃背,然后第二天早上起来发现瓶图文并茂带你一起探秘长江之源沱沱河美景从唐古拉兵站到达唐古拉山镇大概下午四点左右,著名的沱沱河发源于唐古拉山脉格拉丹东雪山之中,是一些冰川融水逐步汇集而成的小溪流,也就是长江发源地的源头沱沱河,河水从唐古拉山镇贯穿而过唐锐公使访问马六甲州8月7日至8日,唐锐公使访问马六甲州,其间会见马六甲州旅游文化及遗产事务行政议员贾拉尼,并赴马六甲科技大学(UTeM)出席一带一路大讲堂活动。唐公使在一带一路大讲堂开幕式上致辞表示哈佛医学院分享的大脑健康饮食方法(全文译自美国CNBC)作为一名营养精神科医生,我一直强调维持均衡的饮食。这在很大程度上与确保我获得所有正确的维生素,特别是因为它对于防止认知能力下降至关重要。鉴于随着年龄的增长,幼儿园将有大调整,有望明年全部落实,家长听后感到安心现在的社会特别重视学历,没有学历寸步难行,将来的发展也很受限,所以为了让自己的孩子将来可以更好地发展,很多的家长都特别重视孩子的教育问题。甚至在孩子上幼儿园时期就要为孩子挑选好的幼