虽然6.0早就出了,但是呢,5.0用的都很少。
主要就是更换版本
较高,用户强烈要求才会更换。
http://developer.android.com/training/material/index.html
材质设计,以抽象化的形式展现物理世界的特征。
系统自带的主题
如何自定义主题
参见http://developer.android.com/training/material/theme.html
不同的Theme,不同的属性值。
常用的样式属性
Z = elevation + translationZ
android:elevation //静态Z轴的高度。相对于父控件的高度
android:translationZ //Z轴偏移的高度。
高度决定了View的遮盖关系,遮盖关系决定绘制时机。
android:outlineProvider:
none:不显示阴影
background :按照显示区域来绘制阴影
bounds :在View的边界描绘阴影
paddedBounds: 在View边界描绘阴影,但会忽略paddingTop和paddingLeft
View都是矩形的,阴影默认是沿着背景的边界绘制。如果背景是矩形了自然没有问题。 如果是圆形的,分两种情况:
为了避免圆形的View显示矩形的阴影,,View增加了一个新的描述来指明内容显示的形状,这就是轮廓。
布局设置:
android:outlineProvider="none|background|bounds|paddedBounds"
none 不显示阴影
background :按照显示区域来绘制阴影
bounds :在View的边界描绘阴影
paddedBounds: 在View边界描绘阴影,但会计算paddingTop和paddingLeft
代码设置:
圆形png图片因为无法排除透明通道,无法识别出真实边界,所以可以自定义,代码提供轮廓
View.setOutlineProvider(new ViewOutlineProvide(){
public void getOutline(View view, Outline outline) {
//矩形,圆形,圆角矩形,Path。除了正常的阴影,也可以自定义奇葩的阴影效果
outline.setOval(0, 0, view.getWidth(), view.getHeight());
}
});
由于轮廓可以自定义,当轮廓小于View的大小,View并不会变小。如果希望View大小跟轮廓匹配,可以裁剪View的大小以适应轮廓,这样也可以通过裁剪生成新的形状。
Outline.canClip();//是否可以被裁剪。目前支持矩形,圆形,圆角矩形
View.setClipToOutline(true);//允许裁剪View大小以适应轮廓
如何设置
代码:
Drawable#setTint(int color);//设置渲染色
Drawable#setTintMode(PorterDuff.Mode tintMode);//设置渲染模式
xml文件:
//可以应用xml定义的bitmap或者ImageView或者View的background等涉及到drawable的地方.
android:tint
android:tintMode
渲染模式
PorterDuff.Mode 18种模式,其决定了原图颜色和渲染颜色的取舍和合成规则。
原理:将原图颜色Dst与渲染颜色Src每个像素点的alpha和color值通过算法计算得到新的颜色,以实现不同的混合效果。
效果参见ApiDemos-Graphics-Xfermodes.演示了16种效果
android.support.v7.graphics.Palette
Vibrant 鲜艳的
Vibrant dark鲜艳的暗色
Vibrant light鲜艳的亮色
Muted 柔和的
Muted dark柔和的暗色
Muted light柔和的亮色
//在子线程可以使用同步操作
Palette p = Palette.from(bitmap).generate();
//在主线程使用异步操作
Palette.from(bitmap).generate(new PaletteAsyncListener() {
public void onGenerated(Palette p) {
// Use generated instance
}
});
//gradle 添加依赖
dependencies {
...
compile 'com.android.support:palette-v7:21.0.0'
}
其他
//获取某个像素点的颜色值
int color=Bitmap.getPixel(int x, int y);
Button自带涟漪动画
自定义涟漪背景:
可用于View的隐藏显示的过渡
/**
* @param view 要执行动画的View
* @param centerX 圆心X
* @param centerY 圆心Y
* @param startRadius 开始半径
* @param endRadius 结束半径
*/
ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0, finalRadius);
参见http://developer.android.com/training/material/animations.html#ViewState
- StateListAnimator
- AnimatedStateListDrawable
StateListAnimator 属性动画
//切换到按下状态时执行的动画
-
//同时还可以执行其他的动画
//切换默认状态时执行的动画
-
使用
xml布局:
android:stateListAnimator属性设置
代码:
View#setStateListAnimator(AnimatorInflater.loadStateListAnimator(this,R.drawable.selector_anim_state));
其他
如果设置了Material Theme,Button默认会有Z轴改变的动画效果。如果想屏蔽,可以设置android:stateListAnimator为 @null
AnimatedStateListDrawable 过渡帧动画
定义
//定义每一帧的图片资源
...
...
如何使用
android:background当成普通drawable使用
参见http://developer.android.com/training/material/animations.html#AnimVector
在drawable目录定义一个矢量图
vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="64dp"
android:width="64dp"
android:viewportHeight="600"
android:viewportWidth="600">
在drawable目录定义一个
在anim目录定义要执行的属性动画
//pathData要求参数个数相同,命令也要相同。
使用矢量图动画
animvectordrawable.xml作为background设置给View
//代码中获取到background,因为是特殊的background,播放
Drawable drawable = vector.getBackground();
if (drawable instanceof Animatable) {
((Animatable) drawable).start();
}
参见 http://developer.android.com/training/material/animations.html#CurvedMotion
PathInterpolator
通过Path定义动画插入器的运动轨迹.二阶,三阶贝塞尔曲线和自定义Path
动画插入器:通过运动曲线模型干预动画的执行。
运动曲线模型:一个 1x1 的正方形内指定一个运动曲线,起点位于 (0,0),终点 (1,1),控制点形成运动曲线
//二阶贝塞尔曲线
public PathInterpolator(float controlX, float controlY)
//三阶贝塞尔曲线
public PathInterpolator(float controlX1, float controlY1, float controlX2, float controlY2)
//Path定义运动曲线
public PathInterpolator(Path path)
Path path = new Path();
path.lineTo(0.4f, 0.8f);
path.lineTo(0.6f, 0.0f);
path.lineTo(1f, 1f);//必须从0,0开始,1,1结束
PathInterpolator pathin=new PathInterpolator(path);
ObjectAnimator 属性动画可以通过Path设置View的带X,Y属性
Path path2 = new Path();
path2.lineTo(40, 80);
path2.lineTo(50, 40);
ObjectAnimator.ofFloat(mAnimView,View.TRANSLATION_X,View.TRANSLATION_Y,path2).setDuration(2000).start();
注意:Tween动画跟属性动画做动画,Tween动画不该变View真实的位置及大小,属性动画改变真实位置及大小。
回顾Activity切换动画
新增Activity元素场景转换动画 - 进入、退出、共享元素转换
回顾Activity切换动画
代码:
//Activity切换动画。api 16以后出现了更好的选择--ActivityOption
public void overridePendingTransition(int enterAnim, int exitAnim);//在startActivity之后,finish之前执行,配置进来的和出去的Activity执行的动画
主题:
//主题配置切换动画
Activity元素场景转换动画
分类
进入退出--Visibility
Explode分解 - 从场景中心移入或移出视图。
Slide滑动 - 从场景边缘移入或移出视图。
Fade淡入淡出 - 通过调整透明度从场景增添或移除视图
可实现接口进行自定义
共享元素动画-- Transition
changeBounds - 为目标视图的布局边界的变化添加动画。
changeClipBounds - 为目标视图的裁剪边界的变化添加动画。
changeTransform - 为目标视图的缩放与旋转变化添加动画。
changeScroll - 为目标视图的ScrollTo操作添加动画。
changeImageTransform - 为目标图像的大小与缩放变化添加动画。
如何使用
1. 通过Theme定义
Activity里代码设置:
/ 允许使用transitions
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
// 指定进入、退出、返回、重新进入时的transitions
TransitionSet set = new TransitionSet();//也可设置TransitionSet
set.addTransition(new Explode());
set.addTransition(new Fade());
getWindow().setEnterTransition(new Explode());
getWindow().setExitTransition(new Explode());
getWindow().setEnterTransition(new Explode());
getWindow().setExitTransition(new Explode());
// 指定进入、退出、返回、重新进入时的共享transitions
getWindow().setSharedElementEnterTransition(new ChangeTransform());
getWindow().setSharedElementExitTransition(new ChangeTransform());
getWindow().setSharedElementReturnTransition(new ChangeTransform());
getWindow().setSharedElementReenterTransition(new ChangeTransform());
2. 启动Activity
//没有共享元素
ActivityOptions options=ActivityOptions.makeSceneTransitionAnimation(this);
//1个共享元素
ActivityOptions options = ActivityOptions
.makeSceneTransitionAnimation(this, sharedElementView, "sharedElementName");
//多个共享元素
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
Pair.create(sharedElementView1, "sharedElementName1"),
Pair.create(sharedElementView2, "sharedElementName2"));
// 启动Activity
startActivity(new Intent(getApplicationContext(), XXXActivity.class), options.toBundle());
共享元素:利用 android:transitionName 属性对两个布局中的共享元素指定一个通用名称sharedElementName,以便过渡动画的执行
3. 关闭Activity
调用finishAfterTransition替代finish。返回键默认处理为finishAfterTransition
介绍
基本功能三要素
显示数据集
参见 https://developer.android.com/training/material/lists-cards.html#RecyclerView
1. 在布局文件中使用RecyclerView
2. 在Activity中找到RecyclerView
3. RecyclerView.setLayoutManager(LayoutManager)
4. RecyclerView.setAdapter(Adapter)
5. 定义Adapter
~~~java
public class MyAdapter extends RecyclerView.Adapter {
private final List> data;
public MyAdapter(List> data) {
this.data = data;
}
@Override
public int getItemCount() {
return data == null ? 0 : data.size();
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
SimpleVH svh = new SimpleVH(View.inflate(parent.getContext(), R.layout.item_simple, null));
return svh;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
SimpleVH svh = (SimpleVH) holder;
svh.iv.setImageResource(data.get(position).second);
svh.name.setText(data.get(position).first);
svh.item.setText("position: " + position );
}
public static class SimpleVH extends RecyclerView.ViewHolder {
ImageView iv;
TextView name;
TextView item;
public SimpleVH(View itemView) {
super(itemView);
iv = (ImageView) itemView.findViewById(R.id.iv);
name = (TextView) itemView.findViewById(R.id.name);
item = (TextView) itemView.findViewById(R.id.item);
}
}
}
~~~
实质上就是设置不同的LayoutManager
~~~ java - LinearLayoutManager(Context context, int orientation, // 布局方向 boolean reverseLayout //是否反转 ) - GridLayoutManager(Context context, int spanCount, // 几列 int orientation, // 方向 boolean reverseLayout //是否反转 ) - StaggeredGridLayoutManager( int spanCount, // 几列 int orientation // 方向 ) ~~~
设置点击事件
使用了比较底层的API,较为复杂
使用回调的设计手法
~~~java
/**adapter*/
public static interface OnItemClickListener {
public void onItemClick(RecyclerView.ViewHolder vh);
}
public void setOnItemClickListener(OnItemClickListener oicl) {
this.oicl = oicl;
}
private void onItemClick(RecyclerView.ViewHolder vh) {
if (oicl != null) {
oicl.onItemClick(vh);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
//...
svh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 通知同一个方法,
onItemClick(holder);
}
});
}
/**Activity*/
myAdapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {
@Override
public void onItemClick(RecyclerView.ViewHolder vh) {
Toast.makeText(NewWidgetActivity.this, "position: "+ vh.getAdapterPosition(),Toast.LENGTH_SHORT).show();
}
});
~~~
下拉刷新
使用方法
个性化
//定制SwipeRefreshLayout的样式
//设置箭头的颜色
swipeRefreshLayout.setColorSchemeColors(Color.RED,Color.GREEN, Color.BLUE);
//设置圆圈的背景 v7 22以后
swipeRefreshLayout.setProgressBackgroundColorSchemeColor(Color.GRAY);
使用方法
卡片内容于边距的间隔 cardview:contentPaddingBottom cardview:contentPaddingTop cardview:contentPaddingLeft cardview:contentPaddingRight cardview:contentPaddingStart cardview:contentPaddingEnd
cardview:cardUseCompatPadding 设置内边距,V21+的版本和之前的版本仍旧具有一样的计算方式 cardview:cardPreventConrerOverlap 在V20和之前的版本中添加内边距,这个属性为了防止内容和边角的重叠
~~~
定义不同的布局
将使用了新的API的布局放在res/layout-v21/; 其他的放在res/layout/中
主题定义
小窍门,所有没有见过的,都去掉,aapt会报错,根据aapt的提示添加android的命名空间