Material Design当中Drawable新特性

参考:

https://developer.android.com/training/material/drawables.html


1、简介

在Material Design主题当中给drawable增加了一些新的功能:

1、图片着色:可以直接为BitmapDrawable和NinePatchDrawable进行着色,并且有多种着色模式可以选择。

2、使用Palette从Bitmap中萃取突出颜色。

3、引入矢量图像VectorDrawable。


2、为drawable进行着色

仅支持API21及以上的版本,通过在xml当中设置android:tint以及android:tintMode来进行着色,如下所示,给ImageView进行着色:


左上角是原始的ImageView,剩下的都是通过对其进行着色得到的ImageView,布局如下所示,关于tintMode,可以参考相关文档:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context="com.easyliu.drawables.MainActivity">

    <ImageView
        android:id="@+id/iv_tint"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:elevation="5dp"
        android:scaleType="fitXY"
        android:src="@mipmap/ic_launcher" />

    <ImageView
        android:id="@+id/iv_tint1"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:elevation="2dp"
        android:scaleType="fitXY"
        android:src="@mipmap/ic_launcher"
        android:tint="@android:color/holo_blue_bright"
        android:tintMode="src_atop" />

    <ImageView
        android:id="@+id/iv_tint2"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_below="@id/iv_tint"
        android:elevation="2dp"
        android:src="@mipmap/ic_launcher"
        android:tint="@android:color/holo_blue_bright"
        android:tintMode="add" />

    <ImageView
        android:id="@+id/iv_tint3"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_alignParentRight="true"
        android:layout_below="@id/iv_tint1"
        android:elevation="2dp"
        android:src="@mipmap/ic_launcher"
        android:tint="@android:color/holo_blue_bright"
        android:tintMode="multiply" />
</RelativeLayout>


3、从Bitmap中萃取突出颜色

Android v7支持库当中包括Palette类,可以从图像中萃取突出颜色,将萃取下列突出颜色:

1、鲜艳
2、鲜艳深色
3、鲜艳浅色
4、低调
5、低调深色
6、低调浅色

如果要萃取这些颜色,需要将Bitmap对象对象传给Palette.generate()方法当中得到Palette对象,注意这个方法需要在一个新的线程中执行,防止阻塞UI线程。当然也可以通过调用Palette.generateAsync()方法,在返回的监听当中获取Palette对象。


在这里,我们的界面使用TabLayout+ViewPager+FragmentPagerAdapter,每个Fragment的背景都设置为一张图片。当滑动到相应的页面的时候,通过获取到相应的Fragment的背景Drawable的资源ID,进一步得到Bitmap对象,然后从这个Bitmap对象当中萃取突出颜色,然后设置状态栏和TabLayout的相关颜色,来达到动态改变主题的目的,效果如下所示。这些图片只是从网上随意找的,真正的UI设计师就知道怎么配色,从而达到更好的交互效果。



布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    tools:context=".PaletteActivity">

    <android.support.design.widget.TabLayout
        android:id="@+id/tal_demo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
    </android.support.design.widget.TabLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager_demo"
        android:layout_below="@id/tal_demo"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </android.support.v4.view.ViewPager>
</RelativeLayout>

Activity代码:

package com.easyliu.drawables;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.graphics.Palette;

import java.lang.ref.WeakReference;

public class PaletteActivity extends AppCompatActivity implements TabFragment.OnFragmentInteractionListener {
    TabLayout tabl_demo;
    ViewPager viewPager_demo;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_palette);
        initViews();
    }

    /**
     * initViews
     */
    private void initViews() {
        tabl_demo = (TabLayout) findViewById(R.id.tal_demo);
        tabl_demo.setTabMode(TabLayout.MODE_SCROLLABLE);
        tabl_demo.setTabTextColors(Color.BLUE, Color.GREEN);
        tabl_demo.setSelectedTabIndicatorColor(Color.GREEN);
        tabl_demo.setSelectedTabIndicatorHeight(16);
        viewPager_demo = (ViewPager) findViewById(R.id.viewPager_demo);
        viewPager_demo.setAdapter(new MyFragmentAdapter(getSupportFragmentManager(), 5));
        tabl_demo.setupWithViewPager(viewPager_demo);
        viewPager_demo.setCurrentItem(0);
        colorChange(viewPager_demo.getCurrentItem());
        viewPager_demo.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }

            @Override
            public void onPageSelected(int position) {
                PaletteActivity.this.colorChange(position);
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
    }

    /**
     * 改变主题的颜色
     *
     * @param position
     */
    private void colorChange(int position) {
        MyFragmentAdapter fragmentAdapter = (MyFragmentAdapter) viewPager_demo.getAdapter();
        WeakReference<Bitmap> bitmapWeakReference= new WeakReference<Bitmap>(BitmapFactory.decodeResource(getResources(), TabFragment.getBackgroundDrawableId(position)));
        Palette.generateAsync(bitmapWeakReference.get(), new Palette.PaletteAsyncListener() {
            @Override
            public void onGenerated(Palette palette) {
                Palette.Swatch swatch=palette.getVibrantSwatch();
                tabl_demo.setBackgroundColor(swatch.getRgb());
                tabl_demo.setTabTextColors(swatch.getTitleTextColor(),swatch.getTitleTextColor());
                tabl_demo.setSelectedTabIndicatorColor(swatch.getTitleTextColor());
                if (Build.VERSION.SDK_INT >= 21) {
                    getWindow().setStatusBarColor(swatch.getRgb());
                    getWindow().setNavigationBarColor(swatch.getRgb());
                }
            }
        });
    }

    @Override
    public void onFragmentInteraction(Uri uri) {

    }
}

主要是上面的这个colorChange方法,在这个方法里面获取到Fragment的背景Drawable的资源ID,然后转换成Bitmap对象,然后再调用Palette.generateAsync方法,在回调监听里面获取到Palette对象,然后再调用其相关的方法。关于Palette的详细的API,请查看相应文档。


自定义的FragmentAdapter:

package com.easyliu.drawables;

import android.graphics.Color;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.util.ArrayMap;
import android.support.v4.view.PagerAdapter;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * Created by EasyLiu on 2016/8/27.
 */
public class MyFragmentAdapter extends FragmentPagerAdapter {
    int mTabNumbers;
    ArrayMap<Integer, TabFragment> arrayMap = new ArrayMap<>();

    public MyFragmentAdapter(FragmentManager fm, int tabNumbers) {
        super(fm);
        this.mTabNumbers = tabNumbers;
    }

    @Override
    public int getCount() {
        return mTabNumbers;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return "Tab" + position;
    }

    @Override
    public Fragment getItem(int position) {
        TabFragment tabFragment = arrayMap.get(position);
        if (tabFragment == null) {
            tabFragment = TabFragment.newInstance(position);
            arrayMap.put(position, tabFragment);
        }
        return tabFragment;
    }
}

TabFragment:

package com.easyliu.drawables;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class TabFragment extends Fragment {
    private static final String ARG_POSITION = "param1";
    private int mPosition;
    private TextView tv_display;
    private OnFragmentInteractionListener mListener;
    private static final int[] drawables = new int[]{R.drawable.back1, R.drawable.back2, R.drawable.back3, R.drawable.back4, R.drawable.back5};

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param param1 Parameter 1.
     * @return A new instance of fragment TabFragment.
     */
    public static TabFragment newInstance(int param1) {
        TabFragment fragment = new TabFragment();
        Bundle args = new Bundle();
        args.putInt(ARG_POSITION, param1);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mPosition = getArguments().getInt(ARG_POSITION);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_tab, container, false);
        tv_display = (TextView) view.findViewById(R.id.tv_display);
        tv_display.setText("tab" + mPosition);
        view.setBackgroundResource(drawables[mPosition]);
        return view;
    }

    public void onButtonPressed(Uri uri) {
        if (mListener != null) {
            mListener.onFragmentInteraction(uri);
        }
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof OnFragmentInteractionListener) {
            mListener = (OnFragmentInteractionListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }


    public interface OnFragmentInteractionListener {
        void onFragmentInteraction(Uri uri);
    }

    /**
     * 返回fragment的背景drawableId给Palette
     * @param position
     * @return
     */
    public static  int getBackgroundDrawableId(int position) {
        return drawables[position];
    }
}


记住,需要加入依赖:

 compile 'com.android.support:appcompat-v7:24.1.1'
 compile 'com.android.support:design:24.1.1'
 compile 'com.android.support:support-v4:24.1.1'
 compile 'com.android.support:palette-v7:24.1.1'


4、VectorDrawable

在API21及更高版本当中引入了矢量图像VectorDrawable,VectorDrawable可以在不损失清晰度的情况下进行缩放。只需要在一个文件提供一个VectorDrawable,而不需要再像以前一样提供多个屏幕密度的图像。下列实例创建了一个VectorDrawable,在<vector>XML元素中定义形状的详情,这里定义的是一个心形图像:

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="256dp"
    android:height="256dp"
    android:viewportHeight="32"
    android:viewportWidth="32">
    <!-- draw a path -->
    <path
        android:fillColor="#8fffff"
        android:pathData="M20.5,9.5
                        c-1.955,0,-3.83,1.268,-4.5,3
                        c-0.67,-1.732,-2.547,-3,-4.5,-3
                        C8.957,9.5,7,11.432,7,14
                        c0,3.53,3.793,6.257,9,11.5
                        c5.207,-5.242,9,-7.97,9,-11.5
                        C25,11.432,23.043,9.5,20.5,9.5z" />
</vector>


关于<path>标签当中的pathData语法,请参考:

https://www.w3.org/TR/SVG11/paths.html#PathData


效果如下所示,还带有阴影效果,然后我们只需要在使用的地方引用这个VectorDrawable即可。



在ImageView当中引用这个VectorDrawable:

  <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:src="@drawable/heart" />




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值