精华内容
下载资源
问答
  • android主题

    2013-09-04 12:49:04
    android:theme="@android:style/Theme.Dialog" 将一个Activity显示为能话框模式 •android:theme="@android:style/Theme.NoTitleBar" 不显示应用程序标题栏 •android:theme="@android:style/Theme....
    •android:theme="@android:style/Theme.Dialog"   将一个Activity显示为能话框模式

    •android:theme="@android:style/Theme.NoTitleBar"  不显示应用程序标题栏

    •android:theme="@android:style/Theme.NoTitleBar.Fullscreen"  不显示应用程序标题栏,并全屏

    •android:theme="Theme.Light"  背景为白色

    •android:theme="Theme.Light.NoTitleBar"  白色背景并无标题栏

    •android:theme="Theme.Light.NoTitleBar.Fullscreen"  白色背景,无标题栏,全屏

    •android:theme="Theme.Black"  背景黑色

    •android:theme="Theme.Black.NoTitleBar"  黑色背景并无标题栏

    •android:theme="Theme.Black.NoTitleBar.Fullscreen"    黑色背景,无标题栏,全屏

    •android:theme="Theme.Wallpaper"  用系统桌面为应用程序背景

    •android:theme="Theme.Wallpaper.NoTitleBar"  用系统桌面为应用程序背景,且无标题栏

    •android:theme="Theme.Wallpaper.NoTitleBar.Fullscreen" 用系统桌面为应用程序背景,无标题栏,全屏

    •android:theme="Translucent"  半透明

    •android:theme="Theme.Translucent.NoTitleBar" 半透明、无标题栏

    •android:theme="Theme.Translucent.NoTitleBar.Fullscreen" 半透明、无标题栏、全屏

    •android:theme="Theme.Panel"

    •android:theme="Theme.Light.Panel"
    展开全文
  • Android主题更换换肤

    千次阅读 2019-06-12 00:04:50
    android主题换肤,通常借助LayoutInflater#setFactory换肤 认识setFactory 获取包外Resource 我们通常通过Context#getSource()获取res目录下的资源,Context#getAssets()获取asset目录下的资源。 参考文章 遇见...

    知识总览

    android主题换肤通常借助LayoutInflater#setFactory实现换肤。

    换肤步骤:

    1. 通过解析外部的apk压缩文件,创建自定义的Resource对象去访问apk压缩文件的资源。
    2. 借助LayoutInfater#setFactoy,将步骤(1)中的资源应用到View的创建过程当中。

    认识setFactory

    平常设置或者获取一个View时,用的较多的是setContentViewLayoutInflater#inflatesetContentView内部也是通过调用LayoutInflater#inflate实现(具体调用在AppCompatViewInflater#setContentView(ind resId)中)。

    通过LayoutInflater#inflate可以将xml布局文件解析为所需要的View,通过分析LayoutInflate#inflate源码,可以看到.xml布局文件在解析的过程中会调用LayoutInflater#rInflate,随后会通过调用LayoutInflater#createViewFromTag来创建View。这里推荐《遇见LayoutInflater&Factory
    下面一起看看View的创建过程LayoutInflate#createViewFormTag:

    View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
                boolean ignoreThemeAttr) {
            if (name.equals("view")) {
                name = attrs.getAttributeValue(null, "class");
            }
    
            // Apply a theme wrapper, if allowed and one is specified.
            if (!ignoreThemeAttr) {
                final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
                final int themeResId = ta.getResourceId(0, 0);
                if (themeResId != 0) {
                    context = new ContextThemeWrapper(context, themeResId);
                }
                ta.recycle();
            }
    
            if (name.equals(TAG_1995)) {
                // Let's party like it's 1995!
                return new BlinkLayout(context, attrs);
            }
    
            try {
                View view;
                if (mFactory2 != null) {
                	//根据attrs信息,通过mFactory2创建View
                    view = mFactory2.onCreateView(parent, name, context, attrs);
                } else if (mFactory != null) {
                	//根据attrs信息,通过mFactory创建View
                    view = mFactory.onCreateView(name, context, attrs);
                } else {
                    view = null;
                }
    
                if (view == null && mPrivateFactory != null) {
                    view = mPrivateFactory.onCreateView(parent, name, context, attrs);
                }
    
                if (view == null) {
                    final Object lastContext = mConstructorArgs[0];
                    mConstructorArgs[0] = context;
                    try {
                        if (-1 == name.indexOf('.')) {
                        	//创建Android原生的View(android.view包下面的view)
                            view = onCreateView(parent, name, attrs);
                        } else {
                        	//创建自定义View或者依赖包中的View(xml中声明的是全路径)
                            view = createView(name, null, attrs);
                        }
                    } finally {
                        mConstructorArgs[0] = lastContext;
                    }
                }
    
                return view;
            } catch (InflateException e) {
                throw e;
    
            } catch (ClassNotFoundException e) {
                final InflateException ie = new InflateException(attrs.getPositionDescription()
                        + ": Error inflating class " + name, e);
                ie.setStackTrace(EMPTY_STACK_TRACE);
                throw ie;
    
            } catch (Exception e) {
                final InflateException ie = new InflateException(attrs.getPositionDescription()
                        + ": Error inflating class " + name, e);
                ie.setStackTrace(EMPTY_STACK_TRACE);
                throw ie;
            }
        }
    

    从上述源码中可以看出View的创建过程中,会首先找Factory2#onCreateViewFactory#onCreateView进行创建,然后走默认的创建流程。所以,我们可以在此处创建自定义的Factory2Factory,并将自定义的Factory2Factory对象添加到LayoutInflater对象当中,来对View的创建进行干预,LayoutInflate也提供了相关的API供我们添加自己的ViewFactory

    例如:下面我们通过设置LayoutInflaterFactory来,将视图中的Button转换为TextView

    @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            LayoutInflater.from(this).setFactory(new LayoutInflater.Factory() {
                @Override
                public View onCreateView(String name, Context context, AttributeSet attrs) {
                    for (int i = 0; i < attrs.getAttributeCount(); i ++){
                        String attrName = attrs.getAttributeName(i);
                        String attrValue = attrs.getAttributeValue(i);
                        Log.i(TAG, String.format("name = %s, attrName = %s, attrValue= %s", name, attrName, attrValue));
                    }
                    TextView textView = null;
                    if (name.equals("Button")){
                         textView = new TextView(context, attrs);
                    }
    
                    return textView;
                }
            });
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_theme_change);
        }
    

    让后启动Activity后,视图中的Button都转化成了TextView,并且能看到输出:

    name = Button, attrName = id, attrValue= @2131230758
    name = Button, attrName = background, attrValue= @2131034152
    name = Button, attrName = layout_width, attrValue= -2
    name = Button, attrName = layout_height, attrValue= -2
    name = Button, attrName = id, attrValue= @2131230757
    name = Button, attrName = background, attrValue= @2131034150
    name = Button, attrName = layout_width, attrValue= -2
    name = Button, attrName = layout_height, attrValue= -2
    

    获取任意一个apk压缩文件的Resource对象

    上述过程已经提供了更改View类型以及属性的方式,下面我们见介绍如何获取一个apk压缩文件中的res资源。

    我们通常通过Context#getSource()获取res目录下的资源,Context#getAssets()(想当于Context#getSource().getAssets())获取asset目录下的资源。所以要获取一个apk压缩文件的资源文件,创建对应该压缩文件的Resource实例,然后通过这个实例获取压缩文件中的资源信息。
    比如,新创建的的Resource实例为mResource,则可以使用mResource.getColor(colorId),来获取实例内colorId所对应的颜色。

    那么接下来的问题分为两步:

    1、如何创建自定义的Resource实例

    Resource的构造函数Resources(AssetManager assets, DisplayMetrics metrics, Configuration config)了解到,需要获取app外部apk文件资源的Resource对象,首先需要创建对应的AssetManager对象。

    public final class AssetManager implements AutoCloseable {
        /**
         * Create a new AssetManager containing only the basic system assets.
         * Applications will not generally use this method, instead retrieving the
         * appropriate asset manager with {@link Resources#getAssets}.    Not for
         * use by applications.
         * {@hide}
         */
        public AssetManager() {
            synchronized (this) {
                if (DEBUG_REFS) {
                    mNumRefs = 0;
                    incRefsLocked(this.hashCode());
                }
                init(false);
                if (localLOGV) Log.v(TAG, "New asset manager: " + this);
                ensureSystemAssets();
            }
        }
         /**
         * Add an additional set of assets to the asset manager.  This can be
         * either a directory or ZIP file.  Not for use by applications.  Returns
         * the cookie of the added asset, or 0 on failure.
         * {@hide}
         */
         //添加额外的asset路径
        public final int addAssetPath(String path) {
            synchronized (this) {
                int res = addAssetPathNative(path);
                if (mStringBlocks != null) {
                    makeStringBlocks(mStringBlocks);
                }
                return res;
            }
        }
    

    所以通过反射可以创建对应的AssertManager,进而创建出对应的Resource实例,代码如下:

    private final static Resources loadTheme(String skinPackageName, Context context){
            String skinPackagePath = Environment.getExternalStorageDirectory() + "/" + skinPackageName;
            File file = new File(skinPackagePath);
            Resources skinResource = null;
            if (!file.exists()) {
                return skinResource;
            }
            try {
                //创建AssetManager实例
                AssetManager assetManager = AssetManager.class.newInstance();
                Method addAssetPath = assetManager.getClass().getMethod("addAssetPath", String.class);
                addAssetPath.invoke(assetManager, skinPackagePath);
                //构建皮肤资源Resource实例
                Resources superRes = context.getResources();
                skinResource = new Resources(assetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());
    
            } catch (Exception e) {
                skinResource = null;
            }
            return skinResource;
        }
    

    2、如何知道当前属性值在所在Resource中的id

    Resource的源码中,可以发现

    public class Resources {
        /**
         * 通过给的资源名称,类型和包名返回一个资源的标识id。
         * @param name 资源的描述名称
         * @param defType 资源的类型名称
         * @param defPackage 包名
         * 
         * @return 返回资源id,0标识未找到该资源
         */
        public int getIdentifier(String name, String defType, String defPackage) {
            if (name == null) {
                throw new NullPointerException("name is null");
            }
            try {
                return Integer.parseInt(name);
            } catch (Exception e) {
                // Ignore
            }
            return mAssets.getResourceIdentifier(name, defType, defPackage);
        }
    }
    
    

    也就是说在任意的apk文件中,只需要知道包名(manifest.xml中指定的包名,用于寻找资源和Java类)、资源类型名称、资源描述名称。
    比如:在包A中有一个defType"color"namecolor_red_1的属性,通过Resource#getIdentifier则可以获取包B中该名称的颜色资源。

    //将skina重View的背景色设置为com.example.skinb中所对应的颜色
    if (attrValue.startsWith("@") && attrName.contains("background")){
    	int resId = Integer.parseInt(attrValue.substring(1));
    	int originColor = mContext.getResources().getColor(resId);
            if (mResource == null){
                return originColor;
            }
            String resName = mContext.getResources().getResourceEntryName(resId);
            int skinRealResId = mResource.getIdentifier(resName, "color", "com.example.skinb");
            int skinColor = 0;
            try{
                skinColor = mResource.getColor(skinRealResId);
            }catch (Exception e){
                Log.e(TAG, "", e);
                skinColor = originColor;
            }
            view.setBackgroundColor(skinColor);
    }
    

    上述方法也是换肤框架Android-Skin-Loader的基本思路。

    参考文章

    1. 遇见LayoutInflater&Factory
    2. Android 探究 LayoutInflater setFactory
    3. Android换肤原理和Android-Skin-Loader框架解析
    4. Android中插件开发篇之----应用换肤原理解析
    展开全文
  • Android 主题切换的一个Demo

    千次下载 热门讨论 2016-04-17 10:54:19
    Android 主题切换的Demo,详细介绍请到:http://www.jianshu.com/users/6725c8e8194f。需要源码请到:https://github.com/burgessjp/MaterialDesignDemo
  • Android 主题背景颜色设置

    Android 主题背景颜色设置

    一.效果图:

    二.快速实现:

    1.添加依赖:

      implementation "com.github.skydoves:multicolorpicker:1.0.8"
        implementation "com.github.skydoves:elasticviews:2.0.0"

    2.主函数代码:调用系统相册,来获取图片上的颜色值

    package com.example.m1571.myapplication.view.activity.color;
    
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.drawable.BitmapDrawable;
    import android.graphics.drawable.Drawable;
    import android.net.Uri;
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v4.content.ContextCompat;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.TextView;
    
    import com.example.m1571.myapplication.R;
    import com.skydoves.elasticviews.ElasticButton;
    import com.skydoves.multicolorpicker.ColorEnvelope;
    import com.skydoves.multicolorpicker.MultiColorPickerView;
    import com.skydoves.multicolorpicker.listeners.ColorListener;
    
    import java.io.FileNotFoundException;
    import java.io.InputStream;
    
    public class MultiColorPickerActivity extends AppCompatActivity {
    
        private int RESULT_LOAD_IMG = 1000;
        private MultiColorPickerView mMultiColorPickerView;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_mc);
            mMultiColorPickerView = findViewById(R.id.multiColorPickerView);
            final TextView tv_bg = findViewById(R.id.tv_bg);
            final TextView tv_add = findViewById(R.id.tv_add);
            final ElasticButton gallery = findViewById(R.id.gallery);
            mMultiColorPickerView.addSelector(ContextCompat.getDrawable(this, R.drawable.wheel), new ColorListener() {
                @Override
                public void onColorSelected(ColorEnvelope envelope) {
                    int color = envelope.getColor();
                    int[] rgb = envelope.getRgb();
                    String htmlCode = envelope.getHtmlCode();
                    String htmlCodes = envelope.getHtmlCode();
                    tv_bg.setText("#"+htmlCodes + "\t,R:" +rgb[0]+",G:"+rgb[1]+",B:"+rgb[2]);
    //                tv_bg.setBackgroundColor(envelope.getColor());
                    tv_add.setBackgroundColor(envelope.getColor());
                    // TODO
                }
            });
            gallery.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
                    photoPickerIntent.setType("image/*");
                    startActivityForResult(photoPickerIntent,RESULT_LOAD_IMG);
                }
            });
            tv_add.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent photoPickerIntent = new Intent(Intent.ACTION_PICK);
                    photoPickerIntent.setType("image/*");
                    startActivityForResult(photoPickerIntent,RESULT_LOAD_IMG);
                }
            });
        }
    
        @SuppressLint("NewApi")
        @Override
        protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
            if (resultCode == Activity.RESULT_OK) {
                try {
                    if(data!=null){
                        Uri imageUri = data.getData();
                        InputStream inputStream = getContentResolver().openInputStream(imageUri);
                        Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
                        Drawable bitmapDrawable = new BitmapDrawable(bitmap);
                        mMultiColorPickerView.setPaletteDrawable(bitmapDrawable);
                    }
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                }
            }
        }
    
    }
    

    3.布局:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/mainLayout"
        android:orientation="vertical">
        <com.skydoves.multicolorpicker.MultiColorPickerView
            android:id="@+id/multiColorPickerView"
            android:layout_width="300dp"
            android:layout_gravity="center"
            android:layout_height="300dp"
            app:palette="@drawable/g"/>
    
        <TextView
            android:id="@+id/tv_bg"
            android:text="KING"
            android:layout_marginTop="15dp"
            android:layout_gravity="center"
            android:gravity="center"
            android:layout_width="150dp"
            android:layout_height="50dp" />
        <TextView
            android:id="@+id/tv_add"
            android:text="添加图片"
            android:layout_marginTop="15dp"
            android:layout_gravity="center"
            android:gravity="center"
            android:layout_width="150dp"
            android:layout_height="50dp" />
        <com.skydoves.elasticviews.ElasticButton
            android:id="@+id/gallery"
            android:textColor="@android:color/white"
            android:layout_width="150dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginTop="15dp"
            app:button_labelText="Gallery"
            app:button_labelStyle="bold"
            app:button_labelSize="17"
            app:button_backgroundColor="@color/btnColor"
            app:button_duration="250"
            app:button_scale="0.8"/>
    </LinearLayout>

    相关源码:

    https://github.com/jbruchanov/AndroidColorPicker

    https://github.com/MummyDing/Leisure

    https://github.com/MummyDing/ColorPickerDialog

    https://github.com/MummyDing/Awesome-Campus

    https://github.com/JorgeCastilloPrz/AndroidColorX

    https://github.com/QuadFlask/colorpicker  一个不错的主题颜色设置

    展开全文
  • Android 主题设计全解析

    千次阅读 2016-06-30 15:57:04
    Android主题设计!有点乱?初学Android的时候对Android的主题设计都是处在一种模糊的认知状态,为啥呢?自定义时候的attr,普通view的style属性,activity以及application的theme属性,theme与style定义的一致性以及...

    Android主题设计!有点乱?

    初学Android的时候对Android的主题设计都是处在一种模糊的认知状态,为啥呢?

    自定义时候的attr,普通view的style属性,activity以及application的theme属性,theme与style定义的一致性以及theme的众多可选性,系统预置的style属性的继承与使用等等……

    OK,先不管这些乱七八糟的,如果你对Android的主题设计依旧存在某些疑问,请看完这篇文章。

    Theme、Style、Attr的基本概念

    Attr:属性,风格样式的最小单元;

    Style:风格,它是一系列Attr的集合用以定义一个View的样式,比如height、width、padding等;

    Theme:主题,它与Style作用一样,不同于Style作用于个一个单独View,而它是作用于Activity上或是整个应用,并具有向下的覆盖特性


    Theme

    Theme的概念验证

    好吧,为了清晰的验证上面的说法,我这里举个例子

    新建一个moudle,在styles.xml中有如下内容

    <resources>
    
        <!-- Base application theme. -->
        <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>
    
    </resources>

    可以看到该style定义了该主题下共享的三个颜色属性,以及继承了一个父主题
    那么来看一下该主题应用的代码

        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>

    此时 ,这个默认主题应用在了Application下,我们启动模拟器观看主题效果
    这里写图片描述

    普普通通没啥特别的,我们为前面的主题添加两个属性

            <item name="windowActionBar">false</item>
            <item name="windowNoTitle">true</item>

    重新启动模拟器,你看到了什么

    这里写图片描述

    Activity的ActionBar被隐藏了,
    是的,正如我前面所说,Theme一般应用于Application和Activity层级,并会继续向下覆盖,这里我们虽然只是设置了Application的theme属性,其下的所有Activity都会使用该主题。

    Theme的定义

    Theme的定义基本是一致的,主要是外部由一个一对style标签,内部通过item指明所定义的各个属性,下面的Theme就是一个标准的样例,

        <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>

    Theme的继承

    1)通过parent属性进行系统主题的继承

        <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>

    2)通过“.”进行自定义主题的继承

        <style name="AppTheme.NoActionbar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
        </style>

    “.”前面是我们自定义的主题name,后面那就随意了,怎么写都可以了

    style的继承与Theme一致,如果你原来不明白别人为何这样写,那么现在你肯定是知道了

    Theme和Style的区别

    • 定义上的区别:无太大区别,主要是属性不同,写法上基本一致
    • 使用上的区别:
      对于单个控件通过style进行引入(此时style不会向下覆盖);
      对于Activity、Application等窗口级向下应用的通过theme进行引入;

    使用系统预置的style

    <!-- 使用系统预制style -->
    <activity android:theme="@android:style/Theme.Dialog">
    
    <!-- 使用系统预制但局部修改的style -->
    <activity android:theme="@style/CustomTheme">
    
    <color name="custom_theme_color">#b0b0ff</color>
    
    <style name="CustomTheme" parent="android:Theme.Light">
        <item name="android:windowBackground">@color/custom_theme_color</item>
        <item name="android:colorBackground">@color/custom_theme_color</item>
    </style>

    使用Android系统内置的style,请务必加上“android:”

    ThemeOverlays

    在所有可用的主题中,我们可以发现一个名字带有 ThemeOverlay 的系列:
    ThemeOverlay
    ThemeOverlay.Light
    ThemeOverlay.ActionBar.Light
    ThemeOverlay.ActionBar.Dark
    这些主题又是做什么的呢?答案是 仅用于为特定的用途定义必要的属性。

    如果你不清楚,请看测试

    我们首先创建两个toolbar的style

        <style name="AppTheme.AppBar1" parent="ThemeOverlay.AppCompat.Light"/>
        <style name="AppTheme.AppBar2" parent="ThemeOverlay.AppCompat.Dark"/>

    添加toolbar进行测试

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:theme="@style/AppTheme.AppBar1"
            android:background="@color/colorPrimary"/>

    这里写图片描述

    修改为第二个

    这里写图片描述

    通过改变主题我们可以很轻松的实现界面的View的样式变换,是不是会很方便。

    Theme的选用

    其是很简单,在MD设计(也就是5.0)被推出之后,google推出了几个material的主题,但你不必去使用这些主题,因为有更好的替代方案
    Theme.AppCompat
    Theme.AppCompat.Light,
    Theme.AppCompat.NoActionBar等等
    这些主题既保证了向下的兼容又兼顾了material的主题设计,并与materiial的各个主题一一对应,你在选择的时候使用以Theme.AppCompat开头的主题准是没错。

    那就有人问了,为毛线这么干,其他乱七八糟的主题又是啥呢?

    这里我强烈推荐你看一篇文章(译文):android-themes-an-in-depth-guide


    Attr

    首先以layout_width为例分析自定义属性

    <declare-styleable name="ViewGroup_Layout">
        <attr name="layout_width" format="dimension">
            <enum name="fill_parent" value="-1" />
            <enum name="match_parent" value="-1" />
            <enum name="wrap_content" value="-2" />
        </attr>
    </declare-styleable>

    declare-styleable代表自定属性组,attr则是代表属性,name是属性的标识,format是该属性的值类型,内部为enum表示值是唯一的,只可选其一。

    再来看一下text的style

    <attr name="textStyle">
        <flag name="normal" value="0" />
        <flag name="bold" value="1" />
        <flag name="italic" value="2" />
    </attr>

    此时attr的内部是flag,代指属性值是可叠加使用的,比如textStyle = bold|italic则是加粗和斜体的叠加。

    format属性的可选值如下
    这里写图片描述
    其中,reference代表引用,我们常用的@drawable/myImage、@color/myColor等都是这么干的。

    ok,attr内部也只有enum和flag两种类型的属性,看完这个相信你可以自行定义属性了。

    特别注意,当你的format选择错误的时候,填入对应的值AS并不会报错,所以具体实践时请留心

    Attr的获得方法

    有些情况下,我们可能需要使用theme中的属性值,比如下面我们想让一个TextView直接显示dogName这个属性的内容,并且使用系统字体的颜色,则可以如下做:

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="?android:textColorSecondary"
        android:text="?attr/dogName"/>

    获得一个Attr的方法,不同于普通资源使用@符号获得的方式,而是需要使用?符号来获得属性,整体的表达方式如下:

    ?[:][/]
    如果是本应用中的attr使用,则可以省去<package_name>部分。

    此处的textColor使用当前主题的android:textColorSecondary属性内容。因为资源工具知道此处是一个属性,所以省去了attr (完整写法:?android:attr/textColorSecondary)。

    Attr的使用优先级:View的Style>Activity的Theme>Application的Theme,所以说你可以定义整个应用的总体风格,但局部风格你也可以做出自己的调整。


    最近做了下反思,与其制造网络垃圾不如不去写文章,所以准备大幅度降低写作速度并致力于提升文章的质量,未来计划在自己进步的同时分享进步的干货并不断去删除原文,以保证整个博客的文章质量和可用性。

    如果你对本文有什么问题和看法请及时告知,送人玫瑰手有余香,谢谢支持。

    参考文章:
    Attr、Style和Theme详解
    Android开发之Theme、Style探索及源码浅析
    ThemeOverlay
    Android Themes — An in-depth guide

    展开全文
  • Android 主题与style概述

    2016-05-04 21:27:17
    前言: 很多Android应用都提供不同的主题供用户选择。切换主题后,应用的背景,字体等会相应发生改变。...一、Android主题(Theme)和样式(Style)简介在Android应用资源目录下,res/values/目录有style
  • Android主题Theme

    2018-08-03 10:35:29
    主题Theme就是用来设置界面UI风格,可以设置整个应用或者某个活动Activity的界面风格。在Android SDK中内置了下面的Theme,可以按标题栏Title Bar和状态栏Status Bar是否可见来分类: android:theme="@...
  • Android主题theme和样式style总结

    千次阅读 2017-03-24 15:27:19
    Android主题theme和样式style总结 Android中的theme和style对页面的效果影响还是很大的,有的程序启动后页面的背景颜色为白色,字体为黑色,但是有的程序又是相反的,这是因为Android默认的主题显示不一样,各个...
  • Android 主题切换

    千次阅读 2017-06-07 11:49:39
    想实现Android多套主题的切换,网络上方案已经很多了,也看了许多大神的实现方式,但心里总想着自己去实现一遍,就这么借鉴GitHub的开源实现了一个简单的android换肤框架。 实现的思路 通过...
  • Android主题与样式

    千次阅读 2010-11-16 09:04:00
    Android主题与样式 转自 http://blog.sina.com.cn/s/blog_4e5143100100jrwi.html?retcode=0<br />  Android 风格和主题 <br /> Android xml风格和主题文件的编写,是涉及到整个程序...
  • android主题跟样式

    2012-10-21 16:30:10
    android主题跟样式 样式主要用于很多界面用于相同的风格 1.在values下建立一个样式,名称可以任意, 2.在Resources点击add添加一个name跟parent,在添加item就是我们显示的具体内容 3,在布局xml中引用style="@style...
  • android 主题颜色:colorPrimary、colorPrimaryDark、colorAccent等 ...
  • Android主题与Toolbar样式之间的关系

    万次阅读 热门讨论 2016-07-02 15:07:50
    最近这几天被Android主题与Toolbar样式搞晕了,因为本来自己的Android根基就浅,对这方面又一直没有深入了解过;后来在Google上搜索到一篇文章:Android: Changing the Toolbar's text color and overflow icon ...
  • 本开源库是基于我之前的一篇博文《Android主题换肤 无缝切换》,不知道原理的可以先看看。 出于易于集成的目的,我将其抽取出来,作为一个模块。提供简洁的 API,方便使用。 目前暂时没有发现兼容性问题,...
  • Android主题定制及修改

    千次阅读 2012-11-09 09:40:00
    Android主题定制及修改 简介:在写Android的App时,我们在Layout中的xml文件中都会引用到大量的布局组件及风格,有时Android提供的原生组件并不能满足我们的需求,这时我们就要考虑对style及theme进行定制及修改...
  • Android主题定制

    2016-01-05 09:56:56
    Android开发过程中,有个新的需求,需要给APP定制一套可手动变换的应用主题。 1.创建不同控件的样式 style.xml @color/colorPrimary @color/colorPrimaryDark @color/colorAccent false tr
  • Android主题换肤

    2018-01-05 10:29:02
    前几天在研究主题换肤功能,然后在自己的一个App框架Demo中尝试了主题换肤,功能是实现了,就是效果还没有那么完善。1.引入:首先在自己的build.gradle中引入该第三方框架,第一项是必选的,后面三项可以根据自己的...
  • Android主题应用

    2015-07-01 11:12:54
    在很多软件中都有设置主题这个功能,最简单比如网页上的hao123都有换肤功能。那么,如何在Android实现它呢?
  • Android主题设置

    千次阅读 2013-06-05 16:56:25
    设置一个对话框样式的Activity: android:theme="@android:style/Theme.Dialog"> 设置Activity透明背景: android:theme="@android:...在 /res/values/styles.xml中写CutomTheme,设置Activity主题为自定义主题
  • Android 主题 application theme

    千次阅读 2017-04-13 14:56:05
    Android自带的主题样式,黑,白,风格
  • Android 主题及自定义窗口

    千次阅读 2015-10-26 09:55:27
    使用Android系统主题: R.styles.xml中包含了系统的一些主题; 我们常见的系统主题有: Theme.Light : 该主题的背景和用户元素使用一个相反的颜色主题. 为Android3.0以前的默认推荐基础主题; true @drawable/...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 13,875
精华内容 5,550
关键字:

android主题