参考:
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>
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>
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" />