{"id":18335173,"url":"https://github.com/esoxjem/androidstylingguide","last_synced_at":"2025-04-06T04:33:57.315Z","repository":{"id":73926382,"uuid":"149623975","full_name":"esoxjem/AndroidStylingGuide","owner":"esoxjem","description":"A simple guide for Styles and Themes","archived":false,"fork":false,"pushed_at":"2019-12-16T14:21:52.000Z","size":7,"stargazers_count":10,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-21T17:08:52.421Z","etag":null,"topics":["android","styles","themes"],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/esoxjem.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-09-20T14:40:06.000Z","updated_at":"2023-07-27T19:49:50.000Z","dependencies_parsed_at":"2023-09-21T14:32:54.846Z","dependency_job_id":null,"html_url":"https://github.com/esoxjem/AndroidStylingGuide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/esoxjem%2FAndroidStylingGuide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/esoxjem%2FAndroidStylingGuide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/esoxjem%2FAndroidStylingGuide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/esoxjem%2FAndroidStylingGuide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/esoxjem","download_url":"https://codeload.github.com/esoxjem/AndroidStylingGuide/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247435043,"owners_count":20938530,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","styles","themes"],"created_at":"2024-11-05T19:54:18.367Z","updated_at":"2025-04-06T04:33:57.308Z","avatar_url":"https://github.com/esoxjem.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Android Styling Guide\nA simple guide for Styles and Themes\n\n\n## Style\nIf you have a `View` with some attributes on it, you can extract them into a *style*.\n \n```xml\n\u003c!--- No Style ---\u003e\n\u003cView android:background=\"...\"/\u003e\n\n\u003c!--- Styled ---\u003e\n\u003cView style=\"@style/MyStyle\"/\u003e\n\n\u003c!--- styles.xml ---\u003e\n\u003cstyle name=\"MyStyle\"\u003e\n\t\u003citem name=\"android:background\"\u003e#ffffff\u003c/item\u003e\n\u003c/style\u003e\n\n```\n\nThis is useful because you can apply the *style* to multiple views.\n\n\n### When To Style\nUse styles when you have multiple **semantically identical view**, i.e, all of the views mean exactly the same thing.\n\n- Buttons on a calculator.\n- Primary and secondary buttons in an app.\n\n### When NOT To Style\n- Single use styles.\n\t- There is no particular advantage to styling these views.\n\t- No reuse and mostly noise.\n\t\t\t\n- Views that use same attributes but are semantically different.\n\n\n```xml\n\u003cTextView \n\tandroid:id=\"@+id/title\"\n\tandroid:textColor=\"@color/blue\"/\u003e\n\t\n\u003cTextView \n\tandroid:id=\"@+id/body\"\n\tandroid:textColor=\"@color/blue\"/\u003e\n```\n\nExtracting a common style to reduce code duplication for title and body would just couples them and doesn't allow us from styling them differently in the future.\n\nAnalogous to using the same constant for two different concepts.\n\n```kotlin\nconst val NUM_THREE = 3\n\nconst val COLUMNS = NUM_THREE\nconst val RETRIES = NUM_THREE\n```\n### Extracting Styles\nUse built in refactoring menu. \n\n```\nRefactor \u003e Extract \u003e Style\n```\n\n### Inheritance\nStyles can have parents and children.\n\n```xml\n\u003c!--- parent ---\u003e\n\u003cstyle name=\"Action\"/\u003e\n\n\u003c!--- explicit parenting ---\u003e\n\u003cstyle name=\"Primary\" parent=\"Action\"/\u003e\n\u003cstyle name=\"Secondary\" parent=\"Action\"/\u003e\n\n\u003c!--- implicit parenting ---\u003e\n\u003cstyle name=\"Action.Primary\"/\u003e\n\u003cstyle name=\"Action.Secondary\"/\u003e\n```\n\n- Don't mix both parenting styles. It's misleading.\n- Prefer Implicit over Explicit parenting. Easier to read.\n\nWhen dealing with the platform, use dotless child for simplicity.\n\n```xml\n\u003cstyle name=\"BorderlessButton\"\n\t\tparent=\"Widget.AppCompat.Button.Borderless\" /\u003e\n\t\t\n\u003cstyle name=\"BorderlessButton.Primary\"/\u003e\n\u003cstyle name=\"BorderlessButton.Secondary\"/\u003e\n```\n\n### Multiple Styles\n- Not possible on Android, unlike CSS. \n- Other than `TextView` using `TextAppearance`.\n\nOverriding priority:\n\n```\nview styling \u003e style \u003e textApprearance\n```\n\n### Organization\nFor starters,\n\n- Attributes `android:layout_****` should be stay in the layout XML\n- Attributes `android:****` should be defined in a style XML.\n\n```xml\n\u003cTextView\n    android:id=\"@+id/name\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_alignParentRight=\"true\"\n    android:text=\"@string/name\"\n    style=\"@style/FancyText\"/\u003e\n```\n\nThe idea is to keep only layout (positioning, margin, sizing) and content attributes in the layout files, while keeping all appearance details (colors, padding, font) in styles files. \n\nThis rule has exceptions, but in general works fine.\n\n- `android:id` should obviously be in the layout files.\n- `android:orientation` for a `LinearLayout` makes more sense in layout files.\n- `android:text` should be in layout files because it defines content.\n\n\n## Themes\n*Styles* are local to a view, *Themes* are applied system-wide.\n\n- Setup defaults. ex: spinnerItemStyle.\n- Activity level theming.\n- Enables theme swapping. Light vs Dark.\n- Different scope than styles\n\n```xml\n\u003c!--- view scope ---\u003e\n\u003cstyle name=\"MyStyle\"\u003e\n\t\u003citem name=\"android:background\"\u003e@color/blue\u003c/item\u003e\n\u003c/style\u003e\n\n\u003c!--- app/activity scope ---\u003e\n\u003cstyle name=\"MyTheme\"\u003e\n\t\u003citem name=\"android:windowBackground\"\u003e@color/white\u003c/item\u003e\n\u003c/style\u003e\n\n```\n\n- Post Lollipop: Use view level theming if you want a portion of your app to look different than the rest of your app. Apply to a `ViewGroup`.\n- Try modifying the theme first, then move to local styling.\n\n## Miscellaneous\n### Naming\nPrefix the type info: `type_foo_bar.xml`.\n\n- `fragment_contact_details.xml`\n- `view_primary_button.xml`\n- `activity_main.xml`\n\n### colors.xml is a color palette\n- `colors.xml` should be a mapping from a color name to an RGBA value. \n- Abstract underlying colors from their usage in the app.\n\n```xml\n\u003c!--- Bad ---\u003e\n\u003cresources\u003e\n    \u003ccolor name=\"button_foreground\"\u003e#FFFFFF\u003c/color\u003e\n    \u003ccolor name=\"button_background\"\u003e#2A91BD\u003c/color\u003e\n\u003c/resources\u003e    \n\n\u003c!--- Good ---\u003e\n\u003cresources\u003e\n    \u003ccolor name=\"white\"\u003e#FFFFFF\u003c/color\u003e\n    \u003ccolor name=\"blue\"\u003e#2A91BD\u003c/color\u003e\n\u003c/resources\u003e\n```\n\n- Further separation between underlying colors and style usage can be achieved by defining an additional color resource file which references the color palette.\n\n```xml\n\u003c!--- color_mapping.xml ---\u003e\n\u003ccolor name=\"button_foreground\"\u003e@color/white\u003c/color\u003e \n\u003ccolor name=\"button_background\"\u003e@color/blue\u003c/color\u003e \n\n\u003c!--- styles.xml ---\u003e\n\u003cstyle name=\"AcceptButton\"\u003e\n    \u003citem name=\"android:foreground\"\u003e@color/button_foreground\u003c/item\u003e\n    \u003citem name=\"android:background\"\u003e@color/button_background\u003c/item\u003e\n\u003c/style\u003e\n```\n\nCost of maintaining another set of color mappings increases.\n\n### Treat dimens.xml like a palette\n- Define a \"palette\" of typical spacing and font sizes.\n\n```xml\n\u003cresources\u003e\n    \u003c!-- font sizes --\u003e\n    \u003cdimen name=\"font_larger\"\u003e22sp\u003c/dimen\u003e\n    \u003cdimen name=\"font_large\"\u003e18sp\u003c/dimen\u003e\n    \u003cdimen name=\"font_normal\"\u003e15sp\u003c/dimen\u003e\n    \u003cdimen name=\"font_small\"\u003e12sp\u003c/dimen\u003e\n\n    \u003c!-- typical spacing between two views --\u003e\n    \u003cdimen name=\"spacing_huge\"\u003e40dp\u003c/dimen\u003e\n    \u003cdimen name=\"spacing_large\"\u003e24dp\u003c/dimen\u003e\n    \u003cdimen name=\"spacing_normal\"\u003e14dp\u003c/dimen\u003e\n    \u003cdimen name=\"spacing_small\"\u003e10dp\u003c/dimen\u003e\n    \u003cdimen name=\"spacing_tiny\"\u003e4dp\u003c/dimen\u003e\n\n    \u003c!-- typical sizes of views --\u003e\n    \u003cdimen name=\"button_height_tall\"\u003e60dp\u003c/dimen\u003e\n    \u003cdimen name=\"button_height_normal\"\u003e40dp\u003c/dimen\u003e\n    \u003cdimen name=\"button_height_short\"\u003e32dp\u003c/dimen\u003e\n\n\u003c/resources\u003e\n```\n\n- Use the `spacing_x` dimensions in margins and paddings.\n\n### strings.xml\n\n- Name your strings with keys that resemble namespaces. \n- Namespaces are necessary to bring context and break ambiguity.\n\n```xml\n\u003c!--- Bad ---\u003e\n\u003cstring name=\"network_error\"\u003eNetwork error\u003c/string\u003e\n\u003cstring name=\"call_failed\"\u003eCall failed\u003c/string\u003e\n\n\u003cstring name=\"enter_email_here\"\u003eEnter email here\u003c/string\u003e\n\u003cstring name=\"enter_name_here\"\u003eEnter name here\u003c/string\u003e\n\n\u003cstring name=\"logout\"\u003eLogout\u003c/string\u003e\n\u003cstring name=\"contact_us\"\u003eContact Us\u003c/string\u003e\n\n\n\u003c!--- Good ---\u003e\n\u003cstring name=\"error_network\"\u003eNetwork error\u003c/string\u003e\n\u003cstring name=\"error_call\"\u003eCall failed\u003c/string\u003e\n\n\u003cstring name=\"registration_email_hint\"\u003eEnter email here\u003c/string\u003e\n\u003cstring name=\"registration_name_hint\"\u003eEnter name here\u003c/string\u003e\n\n\u003cstring name=\"settings_log_out\"\u003eLogout\u003c/string\u003e\n\u003cstring name=\"settings_contact_us\"\u003eContact Us\u003c/string\u003e\n\n```\n\n- Don't write string values in all uppercase. \n- Use attributes for in the view instead. ex: `textAllCaps` for all caps.\n\n```xml\n\u003c!--- Bad ---\u003e\n\u003cstring name=\"error_call\"\u003eCALL FAILED\u003c/string\u003e\n\n\u003c!--- Good ---\u003e\n\u003cstring name=\"error_call\"\u003eCall failed\u003c/string\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fesoxjem%2Fandroidstylingguide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fesoxjem%2Fandroidstylingguide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fesoxjem%2Fandroidstylingguide/lists"}