ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Android 样式和主题

Android 样式和主题

文章目录

  • Android 样式和主题
    • Style 与 Theme 的区别
    • Style 样式
    • Theme 主题
      • 作用于Activity
      • 作用于Application
    • @ 和 ? 和 @android 和 @attr/ 和 ?android:attr/
      • @
      • ?和?attr/
      • @android
      • ?android:attr/
    • Theme常见写法
    • 常见主题样式设置

Android 样式和主题

Style 与 Theme 的区别

  • 两者本质上是同一种资源 ——<style>。区别只在于作用范围与生效方式:作用于单个 View 时称"样式",作用于 Application / Activity / View 树时称"主题"。
  • 主题不是另一种语法,而是样式在更大作用域上的应用:除控件属性外,还能定义窗口属性(状态栏、导航栏、窗口背景等)以及控件的默认样式。
对比项Style 样式Theme 主题
使用方式style="@style/Xxx"(无android:前缀)android:theme="@style/Xxx"(Manifest 或 View 上)
作用对象单个 ViewApplication / Activity / 单个 View(API 21+)及其子 View
数量限制一个 View 只能指定一个 style一个界面只有一个生效主题,但可逐层覆盖
典型属性宽高、边距、gravity、drawable、字号配色、窗口属性、控件默认样式、textAppearance

主题的作用域可以逐层覆盖:Activity 主题覆盖 Application 主题,View 上的android:theme覆盖 Activity 主题。也就是就近原则。
代码中使用setTheme()必须在setContentView()之前调用才生效。

Style 样式

  • 样式是属性(宽高、颜色、字号、边距等)的集合,主要用于 View。
  • 一个 View 只能通过style属性指定一个样式;样式之间可以用parent继承,文字部分还可以再叠加android:textAppearance。

定义样式

<?xml version="1.0" encoding="utf-8"?><resources><!-- 建议显式继承控件的默认样式,否则 AppCompat / Material 控件会丢失 tint 等默认效果 --><stylename="RadioButtonStyle"parent="Widget.AppCompat.CompoundButton.RadioButton"><!-- LinearLayout 权重均分时宽度必须写 0dp;写 wrap_content 会先按内容分配再分剩余空间,导致宽度不等 --> <item name="android:layout_width">0dp</item> <item name="android:layout_height">match_parent</item> <item name="android:layout_weight">1</item> <item name="android:button">@null</item> <item name="android:drawablePadding">10dp</item> <item name="android:gravity">center</item> <item name="android:textSize">16sp</item></style></resources>

使用样式

<RadioGroupandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><RadioButtonstyle="@style/RadioButtonStyle"android:drawableTop="@drawable/home"android:text="home"/><RadioButtonstyle="@style/RadioButtonStyle"android:drawableTop="@drawable/find"android:text="find"/><RadioButtonstyle="@style/RadioButtonStyle"android:drawableTop="@drawable/message"android:text="message"/></RadioGroup>

Theme 主题

  • 主题是样式在更大作用域上的应用,可以作用于 Application、Activity;API 21 起还可以作用于单个 View / ViewGroup(android:theme)。
  • 主题可以看作是样式的加强版:除控件属性外,还能定义窗口属性和控件默认样式。

作用于Activity

定义主题

<!-- 注意:parent 用 Theme.MaterialComponents.* 时,必须依赖 com.google.android.material:material 库, 否则编译期找不到该主题 --><stylename="ActivityTheme"parent="Theme.MaterialComponents.DayNight.DarkActionBar"><item name="colorPrimary">#FF0000</item> <!-- MDC 主题的状态栏色是 colorPrimaryVariant;colorPrimaryDark 只对 AppCompat 主题生效 --> <item name="colorPrimaryVariant">#00FF00</item> <!-- 强调色:AppCompat 用 colorAccent,MDC 已废弃,改用 colorSecondary --> <item name="colorSecondary">#0000FF</item> <!-- 主题里直接写android:textColor /android:textSize 对普通 TextView 无效(被默认 textAppearance 覆盖), 改默认文字颜色用android:textColorPrimary,字号/字体请写 textAppearance 或 style --> <item name="android:textColorPrimary">#FF0000</item></style>

使用主题

<activityandroid:name=".MainActivity"android:theme="@style/ActivityTheme"/>

作用于Application

将刚才的主题放在<application>标签里

<applicationandroid:theme="@style/ActivityTheme">

@ 和 ? 和 @android 和 @attr/ 和 ?android:attr/

@

@表示引用资源(默认当前应用自己的包),完整形式是@[package:]type/name:

  • @string/app_name:引用本应用的资源
  • @+id/xxx:新建 id
  • @android:drawable/xxx、@com.xxx:type/name:指定包名的资源
<stringname="app_name">hello</string>
<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/app_name"/>

?和?attr/

?表示引用当前主题中的属性值(不是资源值,主题切换时取值随之变化,这是换肤/深色模式的基础)

?attr/等价于?,即?attr/nameColor与?nameColor写法等价,都表示"取当前主题中nameColor这个属性的值"。

以下三个是 AppCompat 主题的属性:

  • colorPrimary:主色,如标题默认颜色
  • colorPrimaryDark:第二颜色,如状态栏颜色
  • colorAccent:强调色,如 FloatingActionButton 背景色
<stylename="AppTheme"parent="Theme.AppCompat.Light.DarkActionBar"><item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item></style>
<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/app_name"android:textColor="?colorPrimary"android:textSize="24sp"/>

@android

@android表示引用 Android 内置的公开系统资源(位于android包)。

<ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@android:drawable/ic_menu_view"/>

?android:attr/

拆成三段理解:?+android:+attr/xxx

片段含义
?取值方式:不是引用资源,而是"去当前主题里查某个属性的值"
android:包名:这个属性由 Android 框架(framework 包)定义
attr/xxx属性名,attr/是固定写法,可省略

所以?android:attr/textColorPrimary= “去当前主题里查 android 包定义的textColorPrimary属性的值”。

两种等价写法:

android:textColor="?android:attr/textColorPrimary"<!-- 完整写法 -->android:textColor="?android:textColorPrimary"<!-- 简写,等价 -->

关键点:值来自"你的主题",不是系统常量

?android:attr/xxx不是"取系统自带的固定值",而是查当前主题给这个属性赋了什么值;框架只是在attrs.xml里声明了这个属性名。

<stylename="AppTheme"parent="Theme.MaterialComponents.DayNight.NoActionBar"><item name="android:textColorPrimary">#333333</item> <!-- 覆写它 --></style>
<TextViewandroid:textColor="?android:attr/textColorPrimary"/><!-- 结果 = #333333 -->

换成DayNight主题的夜间模式,同一个引用会自动取到夜间的值 —— 这才是?的意义(也是换肤/深色模式的基础)。

和@android:的区别

android:background="@android:drawable/dialog_holo_light"<!-- 静态:永远是这一张图 -->android:background="?android:attr/selectableItemBackground"<!-- 动态:随主题变化 -->
  • @android:→ 指向具体资源文件,值固定
  • ?android:attr/→ 查主题中的属性值,换主题就换结果

什么时候加android:前缀

规则只有一条:引用时的名字必须和主题里<item name="...">完全一致。

<!-- 主题里带 android: 前缀 → 引用时也带 --><itemname="android:statusBarColor">#000</item>android:background="?android:attr/statusBarColor"<!-- 主题里不带前缀(AppCompat/MDC 自定义的属性)→ 引用时也不带 --><itemname="colorPrimary">#f00</item>android:textColor="?attr/colorPrimary"

Theme常见写法

注意区分"系统主题"与"库主题":带@android:style/前缀的是系统内置主题,只能在对应 API 及以上使用;
Theme.AppCompat.*、Theme.MaterialComponents.*来自 androidx 库,与系统版本无关,可向下兼容。

Holo 主题(Android 3.0 / 4.0 默认,API 11+)

@android:style/Theme.Holo.Light

Material 主题(Android 5.0 引入,API 21+,不是 4.0)

@android:style/Theme.Material.Light

AppCompat 主题(androidx.appcompat 库,兼容到 API 14+,与 5.0 无关)

Theme.AppCompat.Light.DarkActionBar

MaterialDesign 样式(Material Components 库,需依赖 com.google.android.material:material)

Theme.MaterialComponents.Light.NoActionBar

Material3 样式(Material3 库,属性命名与 MDC 不同)

Theme.Material3.DayNight.NoActionBar

常见主题样式设置

<!--应用的主要颜色--><itemname="colorPrimary">#ff0000</item><!--应用的次要颜色:AppCompat 主题用 colorPrimaryDark;MDC 主题用 colorPrimaryVariant(写 colorPrimaryDark 不会作用于状态栏)--><itemname="colorPrimaryDark">#00ff00</item><!--默认选中颜色:AppCompat 用 colorAccent;MDC 已废弃,改用 colorSecondary--><itemname="colorAccent">@color/colorAccent</item><!--状态栏颜色,API21可用--><itemname="android:statusBarColor">#00000000</item><!-- 状态栏透明化:设为 true 后 android:statusBarColor 失效(内容延伸到状态栏下方),二者二选一 --><itemname="android:windowTranslucentStatus">true</item><!-- 状态栏文字/图标颜色,API23可用,建议放在 values-v23/styles.xml 中 --><itemname="android:windowLightStatusBar">true</item><!-- 全屏显示,隐藏状态栏 --><itemname="android:windowFullscreen">true</item><!-- 隐藏 Title:AppCompat/MDC 主题用无前缀的 windowNoTitle; 系统主题(如 @android:style/Theme.Material.*)要用 android:windowNoTitle。 更简单的方式是直接继承 NoActionBar 系列主题 --><itemname="windowNoTitle">true</item><!-- 底部虚拟导航栏颜色,API21可用 --><itemname="android:navigationBarColor">#E91E63</item><!-- 让底部导航栏半透明并覆盖在 Activity 之上(默认false,activity会居于底部导航栏顶部),如果设为true,navigationBarColor 失效 --><itemname="android:windowTranslucentNavigation">true</item><!--窗口背景(推荐):只作用于 Activity 窗口,不影响子 View --><itemname="android:windowBackground">@drawable/ic_launcher_background</item><!-- 危险:主题中的 android:background 会成为所有 View 的默认背景, 覆盖 Button / EditText 等控件的默认样式。想设窗口背景请用上面的 windowBackground --><!-- <item name="android:background">#a2a3e2</item> --><!-- 注意:android:screenOrientation 不是主题属性,写在主题里完全无效, 必须写在 Manifest 中:<activity android:screenOrientation="landscape" /> -->

控件相关

<!-- button 文字是否全部大写,MaterialComponents 的 Button 默认开启(由 style 决定,可用此属性关闭) --><itemname="android:textAllCaps">false</item><!-- 主题中直接写 android:textColor 对普通 TextView 无效(被控件默认 textAppearance 覆盖), 要改默认文字颜色请用下面的 android:textColorPrimary --><!-- <item name="android:textColor">#B0C4DE</item> --><!-- 默认 EditText 输入框字体的颜色 --><itemname="android:editTextColor">#E6E6FA</item><!-- RadioButton、CheckBox 等控件禁用时的文字颜色 --><itemname="android:textColorPrimaryDisableOnly">#1C71A9</item><!-- 应用的主要文字颜色,ActionBar 标题文字默认使用该颜色 --><itemname="android:textColorPrimary">#FFFFFF</item><!-- 辅助的文字颜色,一般比textColorPrimary的颜色弱一点,用于一些弱化的表示 --><itemname="android:textColorSecondary">#C1C1C1</item><!-- 以下着色属性有"两套前缀",写错前缀不会生效: AppCompat / MaterialComponents 主题使用无前缀版本(AppCompat 自己定义了同名属性); 只有系统主题(@android:style/Theme.Material.*)才使用 android: 前缀 --><!-- 控件选中时的颜色,默认取 colorAccent(AppCompat) / colorSecondary(MDC) --><itemname="colorControlActivated">#FF7F50</item><!-- 控件按压时的色调(水波纹) --><itemname="colorControlHighlight">#FF00FF</item><!-- CheckBox、RadioButton、SwitchCompat 等默认状态的颜色 --><itemname="colorControlNormal">#FFD700</item><!-- 默认按钮的背景颜色 --><itemname="colorButtonNormal">#1C71A9</item>
返回列表