Android 主题资源风格定制 <1>

无论是定制系统还是自行开发APP的UI,其无论是使用标准UI还是自定义UI,最终都是需要自己熟悉主题风格的各种属性设置,不过属性非常的多,如果需要知道某个UI可以临时查看一下SDK的



D:\liuzhibao\Android\sdk\platforms\android-N\data\res路径下的,但是这个是纯粹的资源文件,没有java文件,所以还是推荐repo下来framework/base代码.

下面先看看自定义View如何添加属性之类的:

新建一个PumpKinCustomeView的android studio工程:

主类程序:

package org.durian.pumpkincustomeview;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class PumpKinMainActivity extends AppCompatActivity {

    private Button mButton;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pump_kin_main);

        mButton=(Button)findViewById(R.id.button);
        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(PumpKinMainActivity.this,ThemeActivity.class);
                PumpKinMainActivity.this.startActivity(intent);
                finish();
            }
        });

    }

}

既然要自定义View,那么就需要新建一个atts.xml文件到res/values下,下面随便举几个:

<?xml version="1.0" encoding="utf-8"?>
<resources>

<declare-styleable name="UIView">
    <attr name="pumpkin_background" format="color"/>
    <attr name="pumpkin_textcolor" format="color" />
    <attr name="pumpkin_textsize" format="integer"/>
    <attr name="pumpkin_view_width" format="dimension"/>
    <attr name="pumpkin_view_height" format="dimension"/>
    <attr name="pumpkin_text" format="string"/>
    <attr name="pumpkin_draw" format="reference"/>
    <attr name="pumpkin_enable" format="boolean"/>
    <attr name="pumpkin_style" format="reference" />
    <attr name="pumpkin_enum" format="enum" />
    <attr name="pumpkin_float" format="float" />
    <attr name="pumpkin_fraction" format="fraction" />
</declare-styleable>

</resources>

上面基本上一看还是非常清楚的,上面只缺少flag位运算format,fraction为百分比,reference为引用,enum可以如下:

<declare-styleable name="pumpkin_enum_style">
<attr name="pumpkin_enum">
    <enum name="enum1">1</enum>
    <enum name="enum2">2</enum>
    <enum name="enum3">3</enum>
</attr>
</declare-styleable>

定义好上面的属性后,新建一个UIView的继承View的类:

package org.durian.pumpkincustomeview.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;

import org.durian.pumpkincustomeview.R;

/**
 * Project name : PumpKinCustomeView
 * Created by zhibao.liu on 2016/4/28.
 * Time : 10:32
 * Email [email protected]
 * Action : durian
 */
public class UIView extends View {

    private Paint mPaint;
    private Paint mTextPaint;

    private int rectWidth;
    private int rectHeight;

    public UIView(Context context) {
        super(context);
    }

    public UIView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
        TypedArray typedArray=context.obtainStyledAttributes(attrs, R.styleable.UIView);

        int textSize=typedArray.getInteger(R.styleable.UIView_pumpkin_textsize,128);
        int textColor=typedArray.getColor(R.styleable.UIView_pumpkin_textcolor, Color.GRAY);

        mTextPaint.setColor(textColor);
        mTextPaint.setStrokeWidth(2);
        mTextPaint.setTextSize(textSize);

        int backgroundColor=typedArray.getColor(R.styleable.UIView_pumpkin_background,Color.GRAY);
        rectWidth=(int)typedArray.getDimension(R.styleable.UIView_pumpkin_view_width,512);
        rectHeight=(int)typedArray.getDimension(R.styleable.UIView_pumpkin_view_height,513);
        rectWidth=Utils.px2dip(context,rectWidth);
        rectHeight=Utils.px2dip(context,rectHeight);
        //rectHeight=Utils.dip2px(context,rectHeight);
        mPaint.setColor(backgroundColor);
        android.util.Log.i("UIVIEW","rectWidth : "+rectWidth+" rectHeight : "+rectHeight);

    }

    public void initView(Context context){
        mPaint=new Paint();
        mTextPaint=new Paint();
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);

        canvas.drawRect(new Rect(10,10,rectWidth,rectHeight),mPaint);

        canvas.drawText("hello view",50,800,mTextPaint);

    }

}

然后在工程主Activity的布局中添加这个自定义View.在添加之前,先为这个View写一个自定义style:

<!-- add by pumpkin custom style -->
    <style name="Pumpkin_style">
        <item name="pumpkin_background">#ffff0000</item>
        <item name="pumpkin_textcolor">#ff00ff00</item>
        <item name="pumpkin_view_width">500dp</item>
        <item name="pumpkin_view_height">500dp</item>

    </style>

然后添加到主Activity的布局中:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:pumpkin="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="org.durian.pumpkincustomeview.PumpKinMainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="theme"/>

    <org.durian.pumpkincustomeview.view.UIView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        pumpkin:pumpkin_textsize="128"
        style="@style/Pumpkin_style"
        />

</LinearLayout>

注意:

<org.durian.pumpkincustomeview.view.UIView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        pumpkin:pumpkin_textsize="128"
        style="@style/Pumpkin_style"
        />

这里故意分开一部分直接写在布局中,有一部分属性赋值封装到PumKin_style,但是直接写到布局中需要注意比如(pumpkin:pumpkin_textsize):

在布局头部需要标记路径:现在android studio可以直接res-auto,以前需要换成res/报名

xmlns:pumpkin=<a target=_blank href="http://schemas.android.com/apk/res-auto">http://schemas.android.com/apk/res-auto</a>

在自定义UIView中注意:

rectWidth=Utils.px2dip(context,rectWidth);
        rectHeight=Utils.px2dip(context,rectHeight);

注意: 我们在风格中明明写着是500,但是如果没有上面两句程序,RectWidth的值将是1500,也就是这个地方设置的500dp(预想这样),但是打印log出来将是1500px,结果整个屏幕的方形将非常的大,也不是我们所需要的,所以获取尺寸以后需要转一下从px转到pd单位,所以这个地方需要特别注意.字体也存在这个转换,但是上面程序没有在给出了,转换一般如下:

package org.durian.pumpkincustomeview.view;

import android.content.Context;

/**
 * Project name : PumpKinCustomeView
 * Created by zhibao.liu on 2016/4/28.
 * Time : 14:42
 * Email [email protected]
 * Action : durian
 */
public class Utils {

    public static int dip2px(Context context, float dipValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }

    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

}

运行结果:

下面来看看如果是系统UI的属性如何修改:下面android5.0来简说,

加入我的Activity有CheckBox和EditText,我希望这个Activity中所有的CheckBox都是一致的,所有的EditText风格也是一致的,如何处理呢?

系统资源设计有几个基本原则和规律:

<1> : 具有继承性:如

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

使用parent关键字,继承parent的所有属性值.

<2> : 子类属性覆盖父类属性值:即在虽然在父类对某个属性赋值了,但是子类希望在这个属性值上面不同于父类,那么就在子类重新对改属性值赋值,如下:

<style name="CustomeAppTheme" parent="@style/AppTheme">

        <item name="colorPrimary">#ffff0000</item>
        <!--<item name="colorAccent">#fff4e80b</item>-->
        <item name="editTextStyle">@style/pumpkin_editTextStyle</item>
        <item name="checkboxStyle">@style/pumpkin_checkboxStyle</item>

    </style>

属性colorPrimary在父类AppTheme中已经赋了值,但还是我希望自己的Activity的titlebar的颜色是红色,那么在这里就重新赋值,达到覆盖父类那个属性值的目的.

<3> : 回答最上面那个问题,如果需要调整一个页面内所以某个UI的风格,那么就需要重新将UI的风格重新写,但是一般推荐继承父类,只调整需要调整的部分,其他的仍然采用父类的属性,这样就不要从零开始写了:

<style name="pumpkin_editTextStyle" parent="@android:style/Widget.Material.EditText">
        <item name="android:textColorPrimary">#ffff0000</item>
        <item name="android:textColor">#ff11e7f3</item>
        <item name="android:textSize">48sp</item>
    </style>

    <style name="pumpkin_checkboxStyle" parent="@android:style/Widget.Material.CompoundButton.CheckBox">
        <item name="android:textColor">#fff107f3</item>
        <item name="android:textSize">32sp</item>
    </style>

将页面的EditText和CheckBox的几个属性重新调整.

在新建一个Activity测试一下:

package org.durian.pumpkincustomeview;

import android.content.Intent;
import android.content.res.Resources;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class ThemeActivity extends AppCompatActivity {

    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_theme);

        button=(Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent=new Intent(ThemeActivity.this,CompareThemeActivity.class);
                ThemeActivity.this.startActivity(intent);
            }
        });

    }

}

manifest.xml添加自定义主题给它:

<activity
            android:name=".ThemeActivity"
            android:theme="@style/CustomeAppTheme"></activity>

对应的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context="org.durian.pumpkincustomeview.ThemeActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="hello textview"/>

    <CheckBox
        android:text="hello checkbox"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/button"
        android:text="button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

运行结果:

发现颜色有54%透明度的黑色变为指定的颜色了.

有读者可能又会问题,如何知道EditText等的属性风格,比如

<item name="editTextStyle">

这个地方记住顺序:

打开android源代码,查看EditText.java源代码:

public EditText(Context context, AttributeSet attrs) {
        this(context, attrs, com.android.internal.R.attr.editTextStyle);
    }

看到了吧,这就是为什么前面要自己先写一个自定义的UIView,回顾一下这些主题风格是如何被UI使用的,看到上面的editTextStyle,然后搜索:

        <item name="editTextStyle">@style/Widget.Material.EditText</item>

我的是android5.0的代码,所以带有material.

同时搜索的时候一定要注意,这个搜索的关键字一定要出现在Public.xml中,因为android系统后面的资源需要声明,如果声明在Public.xml中才能够被APP developer使用,即公共的,如果是在symbol.xml,那就算是系统内部自己使用,即私有的.很显然我们这里是需要在APP中使用,所以一定是需要公有的才行.在自己APP程序重新再写这些属性值即可覆盖framework中预设的.

假如自己的UI的一些属性在系统中声明为私有的,怎么办,最粗暴的做法就是直接将系统中的风格和资源文件全部挑选出来放到自己的APP资源下,单个UI的话并不是很难.

假设,这里只是个假设SeekBar 这个ui风格是私有的,那么步骤如下:

<1> : 查看SeekBar.java这个类:

public SeekBar(Context context, AttributeSet attrs) {
        this(context, attrs, com.android.internal.R.attr.seekBarStyle);
    }

继续看seekBarStyle风格:

<item name="seekBarStyle">@style/Widget.Material.SeekBar</item>

找到"定义处":

<style name="Widget.Material.SeekBar">
        <item name="indeterminateOnly">false</item>
        <item name="progressDrawable">@drawable/seekbar_track_material</item>
        <item name="indeterminateDrawable">@drawable/seekbar_track_material</item>
        <item name="thumb">@drawable/seekbar_thumb_material_anim</item>
        <item name="splitTrack">true</item>
        <item name="useDisabledAlpha">false</item>
        <item name="focusable">true</item>
        <item name="paddingStart">16dip</item>
        <item name="paddingEnd">16dip</item>
        <item name="mirrorForRtl">true</item>
        <item name="background">@drawable/control_background_32dp_material</item>
    </style>

其实一般改的并不多,一般是修改SeekBar的进度线的风格(粗细,颜色等)以及游标图案或者颜色,将上面的copy到自己的工程

假如修改背景颜色,那么就还需要提取这个资源:

@drawable/control_background_32dp_material

这个想都不用想,绝对是个xml文件:

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="@color/control_highlight_material"
        android:radius="16dp" />

一看,control_highlight_material还是一个xml:

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true"
          android:state_enabled="true"
          android:alpha="@dimen/highlight_alpha_material_colored"
          android:color="?attr/colorControlActivated" />
    <item android:color="?attr/colorControlHighlight" />
</selector>

也需要提取出来.继续查找颜色:

        <item name="colorControlActivated">?attr/colorAccent</item>

一看colorAccent这个颜色值,这个颜色值很疯狂的,是一个全局的,比如你在自己的APP主题中设置:

<item name="colorAccent">#fff4e80b</item>

你会发现你的所有UI都变色了,而不是一个.

继续查看另外一个颜色colorCotrolHighlight:

<item name="colorControlHighlight">@color/ripple_material_dark</item>

这个颜色值也是一个xml:

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:alpha="@dimen/highlight_alpha_material_dark"
          android:color="@color/foreground_material_dark" />
</selector>

再来看看foreground_material_dark,最终是

<color name="foreground_material_dark">@color/white</color>

即白色前景.

了解上面的流程,如果参考系统的UI就可以拷贝出来自行调整各自的值.

当然上面都是调整APP部分的属性,如果是定制系统,那么就可以在vendor/overlay/framework中自行开发,这样整个系统都有了,但是一般这样的都要拷贝系统原生的,如果希望自己定制的系统中运行的第三方app也跟着调整,也可以直接改原生的主题风格,将原生的代码改掉,当然一般不推荐.

后面一篇可以看看系统基本UI都是谁演化而来:

Button extends TextView 
TextView extends View 
时间: 2024-10-09 08:46:00

Android 主题资源风格定制 <1>的相关文章

Android Metro风格的Launcher开发系列第二篇

前言: 各位小伙伴们请原谅我隔了这么久才开始写这一系列的第二篇博客,没办法忙新产品发布,好了废话不说了,先回顾一下:在我的上一篇博客Android Metro风格的Launcher开发系列第一篇写了如何配置Android开发环境,只是用文字和图片展示了开发Metro风格Launcher的初步设计和产品要求,这一篇文章将会从代码上讲解如何实现对应的UI效果,好了,评书开讲! Launcher主体框架实现: Launcher主体框架我选用的是大家所熟悉的ViewPager控件,因为ViewPager

【转载】Android Metro风格的Launcher开发系列第二篇

前言: 各位小伙伴们请原谅我隔了这么久才开始写这一系列的第二篇博客,没办法忙新产品发布,好了废话不说了,先回顾一下:在我的上一篇博客Android Metro风格的Launcher开发系列第一篇写了如何配置Android开发环境,只是用文字和图片展示了开发Metro风格Launcher的初步设计和产品要求,这一篇文章将会从代码上讲解如何实现对应的UI效果,好了,评书开讲! Launcher主体框架实现: Launcher主体框架我选用的是大家所熟悉的ViewPager控件,因为ViewPager

Android系统的定制---定制系统开机动画

4.3定制Android平台系统 通常产品厂商在拿到Android源码后会在Android源码基础上进行定制修改,以匹配适应自己的产品,从本节开始,我们从最原始的Android源码系统里一步一步定制出自己的Android系统.本节主要内容包含:根据Android源码,添加新产品编译项,定制系统启动界面和文字,定制系统启动动画和声音,定制系统桌面. 4.3.1添加新产品编译项 Android系统的源代码是一个逻辑结构非常独立工程,在一套Android源码中可以编译出多个产品映像,在需要编译某一个产

Android Metro风格的Launcher开发系列第三篇

前言: 各位小伙伴,又到了每周更新文章了时候了,本来是周日能发出来呢,这不是赶上清明节吗,女王大人发话了,清明节前两天半陪她玩,只留给我周一下午半天时间写博客,哪里有女王哪里就有压迫呀有木有!好了闲话少说,上一篇博客(Android Metro风格的Launcher开发系列第二篇)说到Launcher主体框架用ViewPager来实现,这一篇博客咱们来说说每一个page的具体实现. PagerAdapter: Launcher主体ViewPager实现就引出了PagerAdapter,Pager

Android Dribbble风格边栏菜单实现(转)

转自:http://blog.csdn.net/t12x3456/article/details/17353049 随着IOS7的推出,大量移动应用也开始进行了重新设计.,开始应用大量的扁平化.可以说现在IOS和Android的风格设计方面确实是在逐渐地靠拢. ReisdeMenu 创意灵感来自于Dribbble(Dribbble是一个面向创作家.艺术工作者.设计师等创意类作品的人群,提供作品在线服务,供网友在线查看已经完成的作品,或者正在创作的作品.). 得益于Dribbble,这种IOS7风

深入浅出 - Android系统移植与平台开发(十)- Android编译系统与定制Android平台系统(瘋耔修改篇二)

第四章.Android编译系统与定制Android平台系统 4.1Android编译系统 Android的源码由几十万个文件构成,这些文件之间有的相互依赖,有的又相互独立,它们按功能或类型又被放到不同目录下,对于这个大的一个工程,Android通过自己的编译系统完成编译过程. 4.1.1 Android编译系统介绍 Android和Linux一样,他们的编译系统都是通过Makefile工具来组织编译源码的.Makefile工具用来解释和执行Makefile文件,在Makefile文件里定义好工程

android shape总结 和控制的风格定制

1:shape总结 1):shape文件是放置在drawable文件下的.res/drawable/filename.xml. 2):shape类型:android:shape. 一共同拥有四种:rectangle.oval,line,ring. 3):corners标签:定义圆角.当且仅当控件类型位rectangle时才有作用. android:radiuse位圆角的半径. 当然也能够单独为每一个圆角进行设置. 4):gradient标签:颜色渐变. android:angle:颜色渐变的方向

Android自定义控件风格的方法

EditText在获取焦点后默认的边框都是黄色的,这可能和我在开发的应用的主题颜色不匹配,那怎么办呢?——用自定义的控件风格,比如说我想让EditText在获取焦点时候边框变成蓝色的,而失去焦点后边框变成灰色的,要实现这个目的方法如下: (一)先在PS中画两张png图片,一张为蓝色边框.白色填充的圆角矩形,另一张为灰色边框.白色填充的圆角矩形,两个矩形形状完全相同.这两种图片分别作为EditText在激活和未激活两个状态的背景图片.一张命名为et_pressed.png,另一张为et_norma

为Android开发人员定制的搜索引擎

我在谷歌上定制了一个专门针对Android开发人员的搜索引擎.载入慢的童鞋考虑FanQiang吧,作为技术人员使用Google才是王道. 在此推荐给大家:Android搜索引擎 搜索内容:Android方面的问答.技术文章.API.开源项目等. 搜索范围:StackOverflow.Github.Google Code.Eoe.开源中国.CSDN.博客园.Android巴士.搜集的各种Android开源小站等. 效果图: