虽然Android 8.0都出了,但是Android 5.X还是需要学习的,这个版本有很多动画还是很好看的,学习了可以提高用户体验的,这也是进阶的一个阶梯
Android 5.X系列开始使用新的设计风格Material Design来统一整个Android系统的界面设计风格。
材料的心态模拟是Material Design中最核心也是改变最大的一个设计,Google通过模拟自然界纸墨的形态变化、光线和阴影、纸与纸之间的控件层级关系,带来一种真实的空间感。
Android 5.X中大量加入了各种新的动画效果,让整个设计风格更加自然、和谐。
Material Design中用大量高饱和度、始终亮度的大色块来突出界面的主次,并一扫Android4.X系列Holo主体的沉重感,让界面更加富有时尚感和视觉冲击力。
此外,Google在其Design网站上,有整个Material Design的设计Spec网站:
https://www.google.com/design/#resources
Material Design现在又三种默认的主题可以设置:
@android:style/Theme.Material (dark version)
@android:style/Theme.Material.Light (light version)
@android:style/Theme.Material.Light.DarkActionBar
同时Android 5.X提出了Color Palette的概念,让开发者可以自己设定系统区域的颜色,使整个App的颜色风格和系统的颜色风格保持一致。
通过如下所示的代码,可以通过使用自定义Style的方式来创建自己的Color Palette颜色主题,从而实现不同的颜色风格
<resources>
<style name="AppTheme" parent="android:Theme.Material">
-- Main theme color-->
-- your app branding color for the app bar-->
<item name="colorPrimary">#BEBEBEitem>
-- derker variant for thr status bar and contextual app bars-->
<item name="colorPrimaryDark">#FF5AEBFFitem>
--theme ui controls like checkBoxs and text fields-->
<item name="colorAccent">#FFFF4130item>
style>
resources>
运行结果:
Android 5.X创新的使用Palette来提取颜色,从而让主题能够动态适应当前页面的色调
Android内置了几种提取色调的种类:
使用Palette需要在Dependencies选项卡中添加以下的依赖:
compile 'com.android.support:palette-v7:21.0.2'
可以通过传递一个Bitmap对象给Palette,并调用它的Palette.generate()静态方法或者Palette.generateAsync()方法来创建一个Palette。
下面演示如何通过加载图片的柔和色调来改变状态栏和Actionbar的色调:
public class PaletteActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_palette);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.test);
// 创建Palette对象
Palette.generateAsync(bitmap,
new Palette.PaletteAsyncListener() {
@Override
public void onGenerated(Palette palette) {
// 通过Palette来获取对应的色调
Palette.Swatch vibrant =
palette.getDarkVibrantSwatch();
// 将颜色设置给相应的组件
getActionBar().setBackgroundDrawable(
new ColorDrawable(vibrant.getRgb()));
Window window = getWindow();
window.setStatusBarColor(vibrant.getRgb());
}
});
}
}
运行结果:
Material Design的一个很重要的特点就是拟扁平化。通过展现生活中的材质效果、恰当地使用阴影和光线,配合完美的动画效果,模拟出一个动感十足又没理大胆的视觉效果。
以往的Android View只有两个属性—X和Y,而在Android 5.X中Google为其增加了一个新的属性—Z,而View中的Z值由两部分组成:
Z = elevation + translationZ;
通常在xml布局中静态设置View 的视图高度:
android:elevation="XXdp"
通过下面的代码演示不同视图高度所显示效果的不同:
<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:orientation="vertical"
tools:context="com.itman.androidfive.elevation.ElevationActivity" >
<TextView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_margin="10dp"
android:background="@drawable/ic_launcher" />
<TextView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_margin="10dp"
android:background="@drawable/ic_launcher"
android:elevation="1dp" />
<TextView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_margin="10dp"
android:background="@drawable/ic_launcher"
android:elevation="20dp" />
LinearLayout>
在程序中,同样可以使用如下代码来动态改变试图高度:
view.setTranslationZ(xxx);
通常也会使用属性动画来为视图高度改变的时候增加一个动画效果:
if(flag){
view.animate().translationZ(100);
flag = false;
}else {
view.animate().translationZ(0);
flag = true;
}
Android 5.X在堆图像的操作上有了更多的功能,下面来看看Android 5.X的两个队操作图像的新功能—Tinting(着色)和Clipping(裁剪)
Tinting的使用非常简单,只要在XML中配置好tint和tintMode就可以了。下面例子设置了几种不同的tint和tintMode来演示Tinting效果:
<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:orientation="vertical"
tools:context="com.itman.androidfive.MainActivity" >
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:elevation="5dp"
android:src="@drawable/ic_launcher" />
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:elevation="5dp"
android:src="@drawable/ic_launcher"
android:tint="@android:color/holo_blue_bright" />
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:elevation="5dp"
android:src="@drawable/ic_launcher"
android:tint="@android:color/holo_blue_bright"
android:tintMode="add" />
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_gravity="center"
android:elevation="5dp"
android:src="@drawable/ic_launcher"
android:tint="@android:color/holo_blue_bright"
android:tintMode="multiply" />
LinearLayout>
Clipping可以让我们改变一个视图的外形。要使用Clipping,首先需要使用ViewOutlineProvider来修改outLine,然后再通过setOutlineProvider将outLine作用给视图。
下面通过例子来理解Clipping的使用思路:
<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:orientation="vertical"
android:gravity="center_horizontal"
tools:context="com.itman.androidfive.MainActivity" >
<TextView
android:id="@+id/tv_rect"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="20dp"
android:elevation="1dp"
android:gravity="center" />
<TextView
android:id="@+id/tv_circle"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="20dp"
android:elevation="1dp"
android:gravity="center" />
LinearLayout>
程序代码中:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View v1 = findViewById(R.id.tv_rect);
View v2 = findViewById(R.id.tv_circle);
//获取Outline
ViewOutlineProvider viewOutlineProvider1 = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
//修改outline为特定形状
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), 30);
}
};
//获取Outline
ViewOutlineProvider viewOutlineProvider2 = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
//修改outline为特定形状
outline.setOval(0, 0, view.getWidth(), view.getHeight());
}
};
//重新设置形状
v1.setOutlineProvider(viewOutlineProvider1);
v2.setOutlineProvider(viewOutlineProvider2);
}
}
RecyclerView就是ListView的升级,使用起来更方便,效率更高。
要使用RecyclerView就需要在Dependencies选项卡中添加以下的依赖,或者下个v7的recyclerview的jar包:
compile 'com.android.support:recyclerview-v7:21.0.2'
准备一个适配器:
public class RecyclerAdapter extends
RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
private List mData;
public RecyclerAdapter(List data) {
mData = data;
}
public OnItemClickListener itemClickListener;
public void setOnItemClickListener(OnItemClickListener itemClickListener) {
this.itemClickListener = itemClickListener;
}
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
public class ViewHolder extends RecyclerView.ViewHolder implements
View.OnClickListener {
public TextView textView;
public ViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView;
textView.setOnClickListener(this);
}
// 通过接口回调来实现RecyclerView的点击事件
@Override
public void onClick(View v) {
if (itemClickListener != null) {
itemClickListener.onItemClick(v, getPosition());
}
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
// 将布局转化为View并传递给RecyclerView封装好的ViewHolder
View v = LayoutInflater.from(viewGroup.getContext()).inflate(
R.layout.rc_item, viewGroup, false);
return new ViewHolder(v);
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i) {
// 建立起ViewHolder中视图与数据的关联
viewHolder.textView.setText(mData.get(i) + i);
}
@Override
public int getItemCount() {
return mData.size();
}
}
item的布局:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:text="111"
android:textSize="40sp"
android:gravity="center"
android:layout_width="match_parent"
android:background="#bebebe"
android:layout_margin="3dp"
android:layout_height="match_parent">
TextView>
布局文件:
<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:orientation="vertical"
tools:context="com.itman.androidfive.recyclerview.RecyclerActivity" >
<android.support.v7.widget.RecyclerView
android:id="@+id/rc_list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="9"
android:scrollbars="vertical" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" >
<Spinner
android:id="@+id/spinner"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:entries="@array/recycler_list" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="addRecycler"
android:text="Add" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:onClick="delRecycler"
android:text="Del" />
LinearLayout>
LinearLayout>
这里需要先添加一个array.xml文件:
<resources>
<string-array name="recycler_list">
<item>Recycler0item>
<item>Recycler1item>
<item>Recycler2item>
string-array>
resources>
最后是activity的代码:
public class RecyclerActivity extends Activity {
private RecyclerView mRcList;
private RecyclerAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private Spinner mSpinner;
private List mData = new ArrayList();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recycler);
mRcList = (RecyclerView) findViewById(R.id.rc_list);
mLayoutManager = new LinearLayoutManager(this);
mRcList.setLayoutManager(mLayoutManager);
mRcList.setHasFixedSize(true);
// 设置显示动画
mRcList.setItemAnimator(new DefaultItemAnimator());
mSpinner = (Spinner) findViewById(R.id.spinner);
mSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView> parent, View view,
int position, long id) {
if (position == 0) {
mRcList.setLayoutManager(
// 设置为线性布局
new LinearLayoutManager(RecyclerActivity.this));
} else if (position == 1) {
mRcList.setLayoutManager(
// 设置为表格布局
new GridLayoutManager(RecyclerActivity.this, 3));
} else if (position == 2) {
}
}
@Override
public void onNothingSelected(AdapterView> parent) {
}
});
// 增加测试数据
mData.add("Recycler");
mData.add("Recycler");
mData.add("Recycler");
mAdapter = new RecyclerAdapter(mData);
mRcList.setAdapter(mAdapter);
mAdapter.setOnItemClickListener(new RecyclerAdapter.OnItemClickListener() {
@Override
public void onItemClick(final View view, int position) {
// 设置点击动画
view.animate().translationZ(15F).setDuration(300)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
view.animate().translationZ(1f)
.setDuration(500).start();
}
}).start();
}
});
}
public void addRecycler(View view) {
mData.add("Recycler");
int position = mData.size();
if (position > 0) {
mAdapter.notifyDataSetChanged();
}
}
public void delRecycler(View view) {
int position = mData.size();
if (position > 0) {
mData.remove(position - 1);
mAdapter.notifyDataSetChanged();
}
}
}
在Android 5.X之后,Google就提供了CardView的控件。其实CardView也是一个容器类布局,只是它提供了卡片这样一种形式。开发者可以定义卡片的大小与视图高度,并设置圆角的角度。
需要在项目中引入依赖:
compile 'com.android.support:cardview-v7:25.+'
主要是设置两个属性:第一个是设置背景颜色;第二个是设置圆角的角度:
app:cardBackgroundColor="#1664a9"
app:cardCornerRadius="10dp"
演示代码:
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="180dp"
android:layout_margin="10dp"
app:cardBackgroundColor="#1664a9"
app:cardCornerRadius="10dp"
app:cardElevation="10dp"
app:contentPadding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="50dp"
android:layout_weight="1"
android:orientation="vertical"
android:padding="8dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="中国工商银行"
android:textColor="#ffffff"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="银联卡"
android:textColor="#ffffff"
android:textSize="16sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="**** **** **** 8888"
android:textColor="#ffffff"
android:textSize="22sp" />
LinearLayout>
LinearLayout>
android.support.v7.widget.CardView>
曾经的Android在Activity进行跳转的时候,即使使用overridePendingtransition(int inId,int outId)这个方法,动画效果也是差强人意的。
但是Android 5.X 提供了三种Transition类型:
其中,进入和退出效果包括:
共享元素包括:
过度动画
要使用三种Activity过度动画非常简单,例如从ActivityA跳转到ActivityB,只需在ActivityA中将基本的startActivity(intent)方法改为:
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this).toBundle());
而在ActivityB中,设置情况如下:
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
或者在样式文件中设置如下代码:
<item name="android:windowContentTransitions">trueitem>
那么接下来就可以设置进入ActivityB的具体的动画效果了:
getWindow().setEnterTransition(new Explode());
getWindow().setEnterTransition(new Slide());
getWindow().setEnterTransition(new Fade());
或者通过如下代码来设置离开ActivityB的动画效果:
getWindow().setExitTransition(new Explode());
getWindow().setExitTransition(new Slide());
getWindow().setExitTransition(new Fade());
共享元素
共享元素的使用,首先要在ActivityA的布局文件中设置共享的元素:
android:transitionName="XXX"
同时在ActivityB的布局文件中,给要实现共享效果的元素也增加相同的属性,需要注意的是一定要保证命名相同:
android:transitionName="XXX"
如果只有一个共享元素,那么在ActivityA中只需使用如下代码。使用的参数就是在前面普通动画的基础上增加了共享的View和前面取的名字:
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this,view,"share").toBundle());
如果有多个共享元素,那么可以通过Pair.create()来创建多个共享元素,代码如下:
startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(this,
Pair.create(view,"share"),Pair.create(fab,"fab")).toBundle());
下面通过一个实例来演示Activity的过渡动画,ActivityA的代码如下:
public class TransitionActivity extends Activity {
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_transition);
}
// 设置不同动画效果
public void explode(View view) {
intent = new Intent(this, TransitionsActivity.class);
intent.putExtra("flag", 0);
startActivity(intent,
ActivityOptions.makeSceneTransitionAnimation(this)
.toBundle());
}
// 设置不同动画效果
public void slide(View view) {
intent = new Intent(this, TransitionsActivity.class);
intent.putExtra("flag", 1);
startActivity(intent,
ActivityOptions.makeSceneTransitionAnimation(this)
.toBundle());
}
// 设置不同动画效果
public void fade(View view) {
intent = new Intent(this, TransitionsActivity.class);
intent.putExtra("flag", 2);
startActivity(intent,
ActivityOptions.makeSceneTransitionAnimation(this)
.toBundle());
}
// 设置不同动画效果
public void share(View view) {
View fab = findViewById(R.id.fab_button);
intent = new Intent(this, TransitionsActivity.class);
intent.putExtra("flag", 3);
// 创建单个共享元素
// startActivity(intent,
// ActivityOptions.makeSceneTransitionAnimation(
// this, view, "share").toBundle());
startActivity(intent,
ActivityOptions.makeSceneTransitionAnimation(
this,
// 创建多个共享元素
Pair.create(view, "share"),
Pair.create(fab, "fab")).toBundle());
}
}
相对应的布局文件:
<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:orientation="vertical"
tools:context="com.itman.androidfive.transition.TransitionActivity" >
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:onClick="explode"
android:text="explode" />
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:onClick="slide"
android:text="slide" />
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:onClick="fade"
android:text="fade" />
<Button
android:layout_width="match_parent"
android:layout_height="100dp"
android:onClick="share"
android:text="share"
android:transitionName="share" />
<Button
android:id="@+id/fab_button"
android:layout_width="56dp"
android:layout_height="56dp"
android:background="@drawable/ripple_round"
android:elevation="5dp"
android:transitionName="fab" />
LinearLayout>
ActivityB代码如下:
public class TransitionsActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
int flag = getIntent().getExtras().getInt("flag");
// 设置不同的动画效果
switch (flag) {
case 0:
getWindow().setEnterTransition(new Explode());
break;
case 1:
getWindow().setEnterTransition(new Slide());
break;
case 2:
getWindow().setEnterTransition(new Fade());
getWindow().setExitTransition(new Fade());
break;
case 3:
break;
}
setContentView(R.layout.activity_transitions);
}
}
相对应的布局代码如下:
<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="com.itman.androidfive.transition.TransitionsActivity" >
<View
android:id="@+id/holder_view"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#2A8AF1"
android:transitionName="share" />
<Button
android:id="@+id/fab_button"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_alignParentEnd="true"
android:layout_below="@+id/holder_view"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:layout_marginTop="-26dp"
android:background="@drawable/ripple_round"
android:elevation="5dp"
android:transitionName="fab" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/holder_view"
android:paddingTop="10dp" >
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_below="@+id/button4"
android:layout_marginTop="10dp" />
<Button
android:id="@+id/button4"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_alignParentStart="true"
android:layout_marginTop="10dp" />
RelativeLayout>
RelativeLayout>
Android 5.X的UI设计Material Design中使用了大量的动画效果,同时Google也在官方设计文档上增加了对动画的设计指导。
Ripple效果其实就是点击后的波纹效果。可以通过下面的代码来设置波纹的背景:
//波纹有边界
android:background="?android:attr/selectableItemBackground"
//波纹无边界
android:background="?android:attr/selectableItemBackgroundBorderless"
下面通过一个实例来演示这两种效果:
<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:background="@android:color/holo_blue_light"
android:gravity="center_horizontal"
android:orientation="vertical"
tools:context="com.itman.androidfive.materialdesign.RippleActivity" >
<Button
android:layout_width="100dp"
android:layout_height="100dp"
android:background="?android:attr/selectableItemBackground"
android:text="有界波纹"
android:textColor="@android:color/white" />
<Button
android:layout_width="100dp"
android:layout_height="100dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:text="无界波纹"
android:textColor="@android:color/white" />
LinearLayout>
运行效果:
同样的也可以在XML中直接来创建一个具有Ripple效果的xml文件:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorPrimary" >
<item>
<shape android:shape="oval" >
<solid android:color="#5EA5F5" />
shape>
item>
ripple>
使用方法:
这个动画具体效果表现为一个View一圆形的形式展开、揭示出来。通过ViewAnimationUtils.createCircularReveal()方法可以创建一个RevealAnimator动画。代码如下:
public static Animator createCircularReveal(View view, int centerX,
int centerY, float startRadius, float endRadius) {
return new RevealAnimator(view,centerX,centerY,startRadius,endRadius);
}
RevealAnimator的使用非常简单,主要是设置几个关键的坐标点:
通过下面的例子,可以非常直观地感受到这种动画效果,xml代码如下:
<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:gravity="center_horizontal"
android:orientation="vertical"
tools:context="com.itman.androidfive.materialdesign.CircularRevealActivity" >
<ImageView
android:id="@+id/oval"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@drawable/oval" />
<ImageView
android:id="@+id/rect"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="@drawable/rect" />
LinearLayout>
这里的圆的xml补上:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight" >
<item>
<shape android:shape="oval" >
<solid android:color="#738ffe" />
shape>
item>
ripple>
方形的xml:
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight" >
<item>
<shape android:shape="rectangle" >
<solid android:color="#738ffe" />
shape>
item>
ripple>
程序代码如下:
public class CircularRevealActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_circular_reveal);
final View oval = findViewById(R.id.oval);
oval.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Animator animator = ViewAnimationUtils.createCircularReveal(
oval, oval.getWidth() / 2, oval.getHeight() / 2,
oval.getWidth(), 0);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(1000);
animator.start();
}
});
final View rect = findViewById(R.id.rect);
rect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Animator animator = ViewAnimationUtils.createCircularReveal(
rect, 0, 0, 0,
(float) Math.hypot(rect.getWidth(), rect.getHeight()));
animator.setInterpolator(new AccelerateInterpolator());
animator.setDuration(1000);
animator.start();
}
});
}
}
运行结果:
在Android 5.X中,系统提供了视图状态改变来设置一个视图的状态切换动画。
StateListAnimator作为视图改变时的动画效果,通常会使用Selector来进行设置,但以前设置Selector的时候,通常是修改背景来达到反馈的效果。现在可以使用动画来作为视图改变的效果。
在XML中定义一个StateListAnimator,并添加到Selector中:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<set>
<objectAnimator android:property="rotationX"
android:duration="@android:integer/config_shortAnimTime"
android:valueTo="360"
android:valuyeType="floatType" />
set>
item>
<item android:state_pressed="false">
<set>
<objectAnimator android:property="rotationX"
android:duration="@android:integer/config_shortAnimTime"
android:valueTo="0"
android:valuyeType="floatType" />
set>
item>
selector>
在布局中直接即可使用:
<Button
android:layout_width="200dp"
android:layout_height="200dp"
android:background="@drawable/anim_change" />
同样,在代码中也可以调用AnimatorInflater.loadStateListAnimator()方法,并且通过View.setStateListAnimator()方法分配动画到视图上。
animated-selector同样是一个状态改变的动画效果Selelctor。
先准备一套状态变换图:
接着在xml中定义这些图片的不同状态:
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/state_on"
android:state_checked="true">
<bitmap android:src="@drawable/ic_done_anim_030" />
item>
<item android:id="@+id/state_off">
<bitmap android:src="@drawable/ic_plus_anim_030" />
item>
<transition
android:fromId="@+id/state_on"
android:toId="@+id/state_off">
<animation-list>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_000" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_001" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_002" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_003" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_004" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_005" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_006" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_007" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_008" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_009" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_010" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_011" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_012" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_013" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_014" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_015" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_016" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_017" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_018" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_019" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_020" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_021" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_022" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_023" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_024" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_025" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_026" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_027" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_028" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_029" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_plus_anim_030" />
item>
animation-list>
transition>
<transition
android:fromId="@+id/state_off"
android:toId="@+id/state_on">
<animation-list>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_000" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_001" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_002" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_003" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_004" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_005" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_006" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_007" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_008" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_009" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_010" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_011" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_012" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_013" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_014" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_015" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_016" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_017" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_018" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_019" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_020" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_021" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_022" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_023" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_024" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_025" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_026" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_027" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_028" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_029" />
item>
<item android:duration="16">
<bitmap android:src="@drawable/ic_done_anim_030" />
item>
animation-list>
transition>
animated-selector>
最后再程序代码中通过setImageState()方法来改变一个背景状态图:
public class AnimatedSelectorActivity extends Activity {
private boolean mIsCheck;
private static final int[] STATE_CHECKED = new int[] { android.R.attr.state_checked };
private static final int[] STATE_UNCHECKED = new int[] {};
private ImageView mImageView;
private Drawable mDrawable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_animated_selector);
mImageView = (ImageView) findViewById(R.id.image);
mDrawable = getResources().getDrawable(R.drawable.fab_anim);
mImageView.setImageDrawable(mDrawable);
}
public void anim(View view) {
if (mIsCheck) {
mImageView.setImageState(STATE_UNCHECKED, true);
mIsCheck = false;
} else {
mImageView.setImageState(STATE_CHECKED, true);
mIsCheck = true;
}
}
}
Toolbar与Actionbar最大的区别就是Toolbar更加自由、可控。要使用Toolbar必须引入appcompat-v7支持,并设置主题为NoActionBar,因此在styles.xml文件中,使用如下代码:
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
-- toolbar颜色-->
<item name="colorPrimary">@color/colorPrimary
- "colorPrimaryDark"
>@color/colorPrimaryDark
- "android:windowBackground">@android:color/white
- "android:searchViewStyle">@style/MySearchView
style>
<style name="MySearchView" parent="Widget.AppCompat.SearchView" />
resources>
用案例实现添加Toolbar显示的标题和图标,再布局中声明Toolbar:
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
在Menu文件夹中创建一个Menu的XML文件:
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity" >
<item
android:id="@+id/ab_search"
android:orderInCategory="80"
android:title="action_search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_share"
android:orderInCategory="90"
android:title="action_share"
app:actionProviderClass="android.support.v7.widget.ShareActionProvider"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="action_settings"
app:showAsAction="never"/>
menu>
activity代码中实现:
public class ToolbarActivity extends AppCompatActivity {
private ShareActionProvider mShareActionProvider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_toolbar);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.setLogo(R.drawable.ic_launcher);
toolbar.setTitle("主标题");
toolbar.setSubtitle("副标题");
setSupportActionBar(toolbar);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return super.onCreateOptionsMenu(menu);
}
}
运行效果:
<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:orientation="vertical"
tools:context="com.itman.androidfive.toolbar.ToolbarActivity" >
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" />
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_blue_light"
android:orientation="vertical">
<Button
android:layout_width="100dp"
android:layout_height="match_parent"
android:text="内容界面" />
LinearLayout>
<LinearLayout
android:id="@+id/drawer_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:orientation="vertical">
<Button
android:layout_width="200dp"
android:layout_height="match_parent"
android:text="菜单界面" />
LinearLayout>
android.support.v4.widget.DrawerLayout>
LinearLayout>
在activity代码中的实现:
public class ToolbarActivity extends ActionBarActivity {
private Toolbar mToolbar;
private ShareActionProvider mShareActionProvider;
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_toolbar);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
mToolbar.setLogo(R.drawable.ic_launcher);
// 标题的文字需在setSupportActionBar之前,不然会无效
mToolbar.setTitle("主标题");
mToolbar.setSubtitle("副标题");
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
mToolbar, R.string.abc_action_bar_home_description,
R.string.abc_action_bar_home_description_format);
mDrawerToggle.syncState();
mDrawerLayout.setDrawerListener(mDrawerToggle);
// 菜单的监听可以在toolbar里设置,
// 也可通过Activity的onOptionsItemSelected回调方法来处理
mToolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_settings:
Toast.makeText(ToolbarActivity.this, "action_settings",
Toast.LENGTH_SHORT).show();
break;
default:
break;
}
return true;
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
/* ShareActionProvider配置 */
mShareActionProvider = (ShareActionProvider) MenuItemCompat
.getActionProvider(menu.findItem(R.id.action_share));
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/*");
mShareActionProvider.setShareIntent(intent);
return super.onCreateOptionsMenu(menu);
}
}
google在Android5.0 上又进一步改进了通知栏,优化了Notification。当我们长按Notification的时候,会显示消息来源;同时,在Android 5.X 设备上,锁屏状态下我们也可以看见Notification的通知。
直接演示案例:
public class NotificationOneActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notification_one);
// 第一步:初始化
Notification.Builder builder = new Notification.Builder(this);
// 第二步:构建点击之后的意图
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("http://www.baidu.com"));
// 构造pendingdintent
PendingIntent pendingIntent = PendingIntent.getActivities(this, 0,
new Intent[] { intent }, 0);
// 第三步:设置通知栏的各种消息
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentIntent(pendingIntent);
builder.setAutoCancel(true);
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher));
builder.setContentText("Title");
builder.setContentText("内容");
builder.setSubText("text");
// 第四步:通过NotificationManager来发出
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(0, builder.build());
}
}
案例演示,先准备两个布局,notification.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:orientation="vertical" >
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#ff43aebe" />
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/robot" />
LinearLayout>
notification_expanded.xml布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="right|top"
android:orientation="horizontal" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="false"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:layout_toLeftOf="@+id/imageView"
android:gravity="center"
android:text="I am now expanded"
android:textColor="#ff43aebe" />
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_gravity="right|top"
android:src="@drawable/robot_expanded" />
RelativeLayout>
LinearLayout>
activity代码:
public class NotificationTwoActivity extends Activity {
private static final int NOTIFICATION_ID_COLLAPSE = 0x01;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notification_two);
Intent intent = new Intent(Intent.ACTION_VIEW,
Uri.parse("http://www.sina.com"));
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
intent, 0);
Notification.Builder builder = new Notification.Builder(this);
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentIntent(pendingIntent);
builder.setAutoCancel(true);
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher));
// 通过RemoteViews来创建自定义的Notification视图
RemoteViews contentView = new RemoteViews(getPackageName(),
R.layout.notification);
contentView.setTextViewText(R.id.textView, "show me when collapsed");
Notification notification = builder.build();
notification.contentView = contentView;
// 通过RemoteViews来创建自定义的Notification视图
RemoteViews expandedView = new RemoteViews(getPackageName(),
R.layout.notification_expanded);
notification.bigContentView = expandedView;
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.notify(NOTIFICATION_ID_COLLAPSE, notification);
}
}
案例演示:
public class NotificationThreeActivity extends Activity {
private static final int NOTIFICATION_ID_HEADSUP = 0x01;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notification_three);
Notification.Builder builder = new Notification.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setPriority(Notification.PRIORITY_DEFAULT)
.setCategory(Notification.CATEGORY_MESSAGE)
.setContentTitle("Headsup Notification")
.setContentText("I am a Headsup notification.");
Intent push = new Intent();
push.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
push.setClass(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, push,
PendingIntent.FLAG_CANCEL_CURRENT);
builder.setContentText("Heads-Up Notification on Android 5.0")
.setFullScreenIntent(pendingIntent, true);
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.notify(NOTIFICATION_ID_HEADSUP, builder.build());
}
}
在Android 5.X 将Notification分成三个等级:
设置Notification等级的方式非常简单,同样是借助builder对象:
builder.setVisibility(Notification.VISIBILITY_PUBLIC);
Notification在Android 5.X中的改动非常多,增加了设置Notification背景颜色的接口:
builder.setColor(Color.RED);
增加了设置Notification的category接口,category用来确定Notification显示的位置,参数就是各种category的类型:
builder.setCategory(Notification.CATEGORY_MESSAGE);
源码下载