我不确定在Android中开发界面的最佳方式是什么。 通过将内联属性移动到样式文件来清理布局文件是否更好?据我所知,在HTML中最好在HTML中使用类和ID,并在style.css文件中使用它们。安卓怎么样?
答案 0 :(得分:8)
我发现了这个,也许它可以帮助别人。
我们必须解决的第一个问题很简单:何时应该使用样式而不是内联属性?
规则#1:当多个视图在语义上相同时使用样式。
最好通过几个例子来说明这条规则:
所有这些示例中的共同点是,这些Views
不只是使用相同的属性 - 它们在整个应用中扮演相同的角色。现在,当您想要调整这些Views
中的任何一个的外观时,您只需编辑样式并立即更改它们。它可以节省您的时间和精力,并使Views
保持一致。
想要节省更多工作?使用资源引用!
规则#2:在适当的时候使用样式中的引用。
您可以通过这种方式定义样式:
<style name="MyButton">
<item name="android:minWidth">88dp</item>
<item name="android:minHeight">48dp</item>
</style>
如果您希望minWidth
根据屏幕尺寸变化,该怎么办?您可以在每个屏幕尺寸上复制一次样式(例如,sw600dp
和sw900dp
),但您也必须复制minHeight
属性。如果您希望两个属性发生变化,该怎么办?突然间,你到处都有大量的MyButtons
被定义,每个都重复了所有其他属性。这是灾难的秘诀;很容易忘记在多个副本之一中更改一个属性。
样式只是一系列属性的别名。定义这样的风格要容易得多:
<style name="MyButton">
<item name="android:minWidth">@dimen/button_min_width</item>
<item name="android:minHeight">@dimen/button_min_height</item>
</style>
现在,您只需修改每个资源限定符的单个属性即可。考虑重复布局只是为了改变肖像与景观中View
的宽度,这是荒谬的。您可以使用维度。这同样适用于款式。
我不是故意暗示你总是在样式中使用资源引用;如果您需要在资源限定符上切换多个值,那么您应该使用它。
这并不是说有时您不需要跨资源限定符复制样式,但您可以将其保持在最低限度。通常,这样做的唯一原因是平台更改(例如,从paddingLeft
和paddingRight
更改为paddingStart
和paddingEnd
)。
如果您可以将多种样式应用于单个View
,如CSS。
你不能。遗憾。
但在某些情况下,你可以得到多种风格的近似值。
规则#3:使用主题调整默认样式。
主题提供了定义许多标准小部件的默认样式的方法。例如,如果要为应用程序定义默认按钮,则可以执行以下操作:
<style name="MyTheme">
<item name="android:buttonStyle">@style/MyButton</item>
</style>
如果你只是调整默认风格,唯一棘手的部分就是找出你风格的父母;您希望它与设备的相应主题相匹配,但这会因操作系统版本而异。
如果您正在使用AppCompat主题,则应将其样式用作父级,因为它们也可以处理不同平台之间的差异。例如,它们具有Spinner
样式:
<style name="MySpinner" parent="Widget.AppCompat.Spinner" />
如果AppCompat中没有样式(或者你没有使用它),问题就会变得有点棘手,因为你需要父母根据主题进行切换。以下是正常使用Holo的自定义Button
样式示例,但适当时使用材质。
您将其放在/values/values.xml
:
<style name="ButtonParent" parent="android:Widget.Holo.Button />
<style name="ButtonParent.Mine">
<item name="android:background">@drawable/my_bg</item>
</style>
然后,在/values-v21/values.xml
:
<style name="ButtonParent" parent="android:Widget.Material.Button />
设置正确的父级将确保您的应用和平台的一致性。
如果你真的想要定义所有必要的属性(而不仅仅是调整默认值),你可以完全跳过育儿。
规则#4:尽可能使用文字外观。
TextAppearance
允许您为一些最常修改的文本属性合并两个样式。看看你的所有风格:其中有多少仅修改文字的外观?在这些情况下,您只需修改TextAppearance
。
首先,您需要定义TextAppearance
:
<style name="MyTextAppearance" parent="TextAppearance.AppCompat">
<item name="android:textColor">#0F0</item>
<item name="android:textStyle">italic</item>
</style>
请注意我如何设置父级 - 文本外观不会合并,因此您需要确保定义所有属性。您可以使用任何适当的TextAppearance
作为父级。
现在您可以在TextView
:
<TextView
style="@style/MyStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/MyTextAppearance" />
请注意,我仍然可以为这个TextView
应用一种样式,让我为一个视图获得惊人的两种风格!不如真正的多种风格,但我会采取我能得到的。
您可以在任何扩展TextAppearance
的类中使用TextView
。这意味着EditText
,Button
等都支持文字样式。
我在使用样式时一直都在解释。不幸的是,从长远来看,很容易滥用款式会对你造成伤害。这里有一些要避免的反模式。
规则#5:如果只使用一次,请不要创建样式。
样式是一个额外的抽象层。它增加了复杂性。您必须查找样式才能查看它们应用的属性。因此,除非您在多个地方使用该风格,否则我认为没有理由使用它们。
打开布局时,您更愿意看到这个:这个?
<TextView style="HelloWorldTextView" />
还是这个?
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
如果您需要,如此简单可以创建样式。不要过早计划。
规则#6:不要因为多个视图使用相同的属性而创建样式。
使用样式的主要原因是减少重复属性的数量,对吧?为什么不在多个视图使用相同属性时使用样式?
这种态度的问题在于,那些Views
,如果它们不在相同的上下文中使用,最终可能希望在它们的外观上有所不同。此时,您的基本样式变得难以编辑而没有意外的副作用。
想想这个场景:你有一些TextViews
相同的文字外观和背景。你想,&#34;嘿,我会创造一种风格,减少代码重复。&#34;一开始一切都很笨拙,但最终你想要调整一些TextViews
看起来如何。问题是,到目前为止,所有地方都使用了该样式,因此您无法在没有附带损害的情况下对其进行编辑。
好吧,你说 - 我只是直接在布局XML中覆盖样式。问题解决了。然后又发生了。然后再次。最终这种风格毫无意义,因为你不得不在任何地方覆盖它。它最终会增加额外的工作,而不是让生活更轻松。
这就是我在规则#1中指定当Views
语义相同时应使用样式的原因。这样可以确保在更改样式时,您确实 希望每个View
使用样式进行更改。
样式支持父级,其中子样式采用父样式的所有属性。如果他们不这样做,那将是相当有限的。
假设我希望应用中的每个Button
看起来都一样,所以我制作了ButtonStyle
。后来,我决定Buttons
的一半应该看起来略有不同 - 通过育儿,我可以创建ButtonStyle.Different
,获得基本风格+调整。
事实证明,有两种方式可以隐式和明确地定义父母:
<!-- Our parent style -->
<style name="Parent" />
<!-- Implicit parenting, using dot notation -->
<style name="Parent.Child" />
<!-- Explicit parenting, using the parent attribute -->
<style name="Child" parent="Parent" />
够简单吧?但是,当我们用两种方法定义父母时,你认为在这里发生了什么?
<style name="Parent.Child" parent="AnotherParent" />
如果您回答说这个风格有两个父母,那么错误。事实证明它只有一个父:AnotherParent
。
每种样式只能有一个父项,即使有两种方法可以定义它。显式父项(使用属性)优先。这引出了我的下一条规则:
规则#7:不要混合隐式和显式育儿。
混合这两者是混淆的一个秘诀。假设我有这个布局:
<Button
style="@style/MyWidgets.Button.Awesome"
android:layout_width="match_parent"
android:layout_height="match_parent" />
但事实证明我的风格是这样定义的:
<style name="MyWidgets.Button.Awesome" parent="SomethingElse" />
即使看起来,我的Button
也基于MyWidgets.Button
,但事实并非如此!样式名称具有误导性,发现它的唯一方法是做额外的工作并深入挖掘你的样式文件。
常见的诱惑是继续使用带有明确父级的点符号,以便您的样式看起来与层次结构相关:
<style name="MyButton" parent="android:Widget.Holo.Button" />
<style name="MyButton.Borderless" parent="android:Widget.Holo.Button.Borderless" />
面向对象的风格!它们看起来很漂亮,对吧?但看起来就是你所得到的 - 一种错觉,即当风格不是时风格是相关的。欺骗是MyButton.Borderless
与MyButton
有关,但它们没有任何共同之处!让我们通过删除名称中的点来消除混淆:
<style name="MyButton" parent="android:Widget.Holo.Button" />
<style name="MyBorderlessButton" parent="android:Widget.Holo.Button.Borderless" />
我在层次结构上看起来很漂亮,但我在代码中获得了很多实用工具。
样式和主题是两个不同的概念。虽然样式适用于单个View
,但主题会应用于一组Views
(或整个Activity
)。
例如,假设您正在使用AppCompat,并且您想要为屏幕设置主要颜色。为此,您必须以整个Activity
:
<style name="MyTheme">
<style name="colorPrimary">@color/my_primary_color</style>
</style>
主题使用与样式相同的数据结构 - 即使使用style
标记 - 但实际上它们在完全不同的情况下使用!他们不会使用相同的属性进行操作 - 例如,您可以在视图上定义textColor
,但主题没有textColor
属性。同样,主题中存在colorPrimary
,但在样式中它们未被使用。因此:
规则#8:不要混合样式和主题。
我见过的两个常见错误:
从Lollipop开始,您可以将主题应用于View
及其所有子项 2 。即使在这种情况下,你也不应该混淆两者,尽管你可以同时使用它们:
<View
style="@style/MyView"
android:theme="@style/MyTheme" />
AppCompat对View
有一个Toolbar
主题的模拟,但是你会得到一段时间,直到Lollipop成为你应用的最低支持版本。换句话说 - 您可以在几年内享受此功能。 :P
使用样式时,这些规则的统一元素是小心和考虑周全。他们可以节省您的时间,但前提是您知道何时使用它们。
字体:this article