前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >无需自定义View,彻底解放shape,selector吧

无需自定义View,彻底解放shape,selector吧

作者头像
我就是马云飞
发布2018-10-25 10:45:24
6610
发布2018-10-25 10:45:24
举报
文章被收录于专栏:我就是马云飞我就是马云飞

前言

作为一个android程序员,对于shape、selector这两个标签一定不陌生。每当UI设计师给我们设计出一个个button背景的时候,我们就需要去drawable文件夹下去新建一个bg_xxx.xml,然后很多时候区别仅仅是一个边框的颜色或者填充的颜色。这就导致了很多非常相似的.xml文件产生。 网上之前也有了一种通过自定义View,在xml中通过设置属性达到shape效果的控件。但是这种自定义的控件不太灵活,归根到底是一个自定义的button,如果我想改造项目的话就得去替换原有的button或者textView。接下来就给大家提供一种更加简单的方式: 无需自定义View,直接添加属性便可以实现shape、selector效果。

具体内容

效果展示

话不多说,直接上代码。

使用方法:

1、在BaseActiviy的super.onCreate()之前调用一行代码,仅仅是一个方法

2、没有其他操作了,直接layout里开始写控件吧!

布局代码

我们来添加一些实例属性:

有没有觉得很熟悉,就是原生标签的tag名+_+属性名,很容易记住,而且不管是Button还是TextView,只要是View都可以。

效果

我们来看一下实际效果:

修改背景

现在UI设计师告诉我们要改一下背景,没事,我们只需要在xml添加或者修改属性就行。 我们来把圆形改成正方形,加个边框。5秒ok!

简单的原理解析
app:xxx

app:xxx属性就不用多说了,这些就是一些自定义属性而已。在这里我把shape、selector的部分属性转换成自定义的属性,这样就方便添加到已有原生控件中。

BackgroundLibrary.inject(this)

这个方法是这个框架唯一需要加入的代码。 inject中实际上是给LayoutInflater添加了一个LayoutInflater.Factory类。而Android的Activity在创建过程(也就是setContentView)中实际上是通过把xml转换成View的对象。而LayoutInflater.Factory相当于这中间的一个后门,它是xml解析创建成View的必经方法,google中的v7support包里很多内容就是通过LayoutInflater.Factory来实现向下兼容的。 在这里,我通过低入侵的方式,加入一个自定义的LayoutInflater.Factory,去解析添加的自定义属性,接下来就简单了。生成系统提供的GradientDrawable、RippleDrawable、StateListDrawable即可。 同时由于AppcompatActivity是已经实现了LayoutInflater.Factory,而Activity又设定一个Activity只能加入一个factory类,因此这里需要在super.onCreate之前调用该方法,利用AppcompatActivity的factory去创建View。 具体原理解释可以参考我的这篇文章:Android 常用换肤方式以及原理分析

具体使用方法:

添加依赖:

代码语言:javascript
复制
implementation "com.android.support:appcompat-v7:$supportVersion"
implementation 'com.noober.backgorund:core:1.0.5'

BaseActivity的super.onCreate之前添加代码:

代码语言:javascript
复制
BackgroundLibrary.inject(context);

支持属性,命名规则就是标签名_标签属性名,支持shape所有属性:

代码语言:javascript
复制
   <attr name="shape" format="enum">
       <enum name="rectangle" value="0" />
       <enum name="oval" value="1" />
       <enum name="line" value="2" />
       <enum name="ring" value="3" />
   </attr>

   <attr name="solid_color" format="color"/>

   <attr name="corners_radius" format="dimension"/>
   <attr name="corners_bottomLeftRadius" format="dimension"/>
   <attr name="corners_bottomRightRadius" format="dimension"/>
   <attr name="corners_topLeftRadius" format="dimension"/>
   <attr name="corners_topRightRadius" format="dimension"/>

   <attr name="gradient_angle" format="integer"/>
   <attr name="gradient_centerX" format="float"/>
   <attr name="gradient_centerY" format="float"/>
   <attr name="gradient_centerColor" format="color"/>
   <attr name="gradient_endColor" format="color"/>
   <attr name="gradient_startColor" format="color"/>
   <attr name="gradient_gradientRadius" format="dimension"/>
   <attr name="gradient_type" format="enum">
       <enum name="linear" value="0" />
       <enum name="radial" value="1" />
       <enum name="sweep" value="2" />
   </attr>
   <attr name="gradient_useLevel" format="boolean"/>

   <attr name="padding_left" format="dimension"/>
   <attr name="padding_top" format="dimension"/>
   <attr name="padding_right" format="dimension"/>
   <attr name="padding_bottom" format="dimension"/>

   <attr name="size_width" format="dimension">
       <enum name="wrap_content" value="-2" />
       <enum name="match_parent" value="-1" />
   </attr>
   <attr name="size_height" format="dimension">
       <enum name="wrap_content" value="-2" />
       <enum name="match_parent" value="-1" />
   </attr>

   <attr name="stroke_width" format="dimension"/>
   <attr name="stroke_color" format="color"/>
   <attr name="stroke_dashWidth" format="dimension"/>
   <attr name="stroke_dashGap" format="dimension"/>

   <!--以下是selector事件-->
   <attr name="ripple_enable" format="boolean"/>
   <attr name="ripple_color" format="color"/>
   <attr name="unpressed_color" format="color"/>
   <attr name="pressed_color" format="color"/>

例如加一个边框背景,如下即可:

代码语言:javascript
复制
<TextView
    android:layout_width="130dp"
    android:layout_height="36dp"
    android:gravity="center"
    android:text="TextView"
    android:textColor="#8c6822"
    android:textSize="20sp"
    app:corners_radius="4dp"
    app:solid_color="#E3B666"
    app:stroke_color="#8c6822"
    app:stroke_width="2dp" />

如果需要selector效果,需要同时添加

代码语言:javascript
复制
app:unpressed_color
app:pressed_color

如果需要水波纹效果,5.0以上才支持:

代码语言:javascript
复制
app:ripple_enable="true"//打开水波纹开关
app:solid_color="xxx"//设置默认填充颜色
app:ripple_color="xxx"//设置水波纹颜色

注意: 1、如果直接给原生控件添加属性,在xml中会如下报红色异常,这时候不用理会即可。

但是红色多了,显示总归难受,可以在根节点添加

代码语言:javascript
复制
tools:ignore="MissingPrefix" 

2、如果Button设置背景的时候文字显示不全,需要设置padding为0,这是button的系统默认风格导致的。 3、当前为了快速使用selector只支持press事件,后续会把所有selector事件加上。 4、Fragment因为依附在Activity上,所以无需特殊处理即可使用

作者:JavaNoober 链接:https://juejin.im/post/5b9682ebe51d450e543e3495


本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-10-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 我就是马云飞 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 具体内容
    • 效果展示
      • 使用方法:
        • 布局代码
          • 效果
            • 修改背景
              • 简单的原理解析
                • app:xxx
                • BackgroundLibrary.inject(this)
              • 具体使用方法:
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档