3.0以前,android支持两种动画模式,tween animation,frame animation,在android3.0中又引入了一个新的动画系统:property animation,这三种动画模式在SDK中被称为property animation,view animation,drawable animation。
这篇文章主要使用ObjectAnimator来实现动画的效果。
使用ObjectAnimator这个对象限制性比较多,要满足一定的条件才可以使用,不然动画没有效果。ObjectAnimator继承ValueAnimator,其实就是指定一个对象以及该对象的一个属性,当属性值计算完成自动设置该对象的相关属性,即完成propety Antimation的全部两个操作。
条件为:
1.对象应该有get<属性名> ;set<属性名>方法。
2.ofInt或者ofFloat方法第一个参数是对象名,第二个参数是属性值,后面的参数为可变参数,如果可变参数为1个值,会假定目的值,获取当前值会调用get<属性值>这个方法。
这边用一个简单的例子实现这个动画
首先有3个xml,一个主Activity的main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/l1"
android:baselineAligned="false" >
<FrameLayout
android:id="@+id/fragment1"
android:layout_width="300dp"
android:background="#FF0000"
android:layout_height="fill_parent" />
<FrameLayout
android:id="@+id/fragment2"
android:layout_width="980dp"
android:background="#00FF00"
android:layout_height="fill_parent" />
</LinearLayout>
然后定义一个f1.xml和f2.xml作为fragment1和fragment2的布局,然后替换main.xml中的framelayout1和framgelayout2。fragment的操作,大家在网上一搜一大片,怎么使用就不讲了。
f1.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#30000000"
android:gravity="center"
android:baselineAligned="false" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
android:text="F1" />
</LinearLayout>
f2.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:baselineAligned="false" >
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="go" />
</LinearLayout>
fragment1.java
public class Fragment1 extends Fragment {
public static Fragment1 newInstance() {
return new Fragment1();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.f1, container, false);
return root;
}
}
fragment2.java
public class Fragment2 extends Fragment {
private WeakReference<FragmentResultListener> mFragmentResultListenerRef;
public interface FragmentResultListener {
public void onBtnClick();
}
public static Fragment2 newInstance(FragmentResultListener listener) {
Fragment2 f = new Fragment2();
f.setFragmentResultListener(listener);
return f;
}
private void setFragmentResultListener(FragmentResultListener listener) {
mFragmentResultListenerRef = new WeakReference<FragmentResultListener>(listener);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.f2, container, false);
root.findViewById(R.id.btn).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
FragmentResultListener fragmentResultListener = mFragmentResultListenerRef.get();
if (fragmentResultListener != null) {
fragmentResultListener.onBtnClick();
}
}
});
return root;
}
}
这边实现动画的操作需要点击fragment2中的按钮,所以这边使用了回调,先在fragment2中定义个点击的接口,然后再把接口的方法放在按钮的监听事件里面,然后外边调用的时候实现接口的操作,把接口对象传递过来就ok了。
这边是主要的程序,也是主Acitvity的实现逻辑,动画的定义,都在里面。
public class FragmentAnimationTestActivity extends Activity implements Fragment2.FragmentResultListener {
private static final TimeInterpolator sCollapseInterpolator = new DecelerateInterpolator(2.5F);
private View mPanel1;
private View mPanel2;
private View mLayout;
boolean isCollapsed;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mLayout = findViewById(R.id.l1);
mPanel1 = findViewById(R.id.fragment1);
mPanel2 = findViewById(R.id.fragment2);
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.replace(R.id.fragment1, Fragment1.newInstance(), "f1");
ft.replace(R.id.fragment2, Fragment2.newInstance(this), "f2");
ft.commit();
}
public int getPanelLeft() {
return ((ViewGroup.MarginLayoutParams) mLayout.getLayoutParams()).leftMargin;
}
public void setPanelLeft(int paramInt) {
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mLayout.getLayoutParams();
lp.leftMargin = paramInt;
mLayout.setLayoutParams(lp);
}
public int getPanel2W() {
return ((ViewGroup.MarginLayoutParams) mPanel2.getLayoutParams()).width;
}
public void setPanel2W(int paramInt) {
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mPanel2.getLayoutParams();
lp.width = paramInt;
mPanel2.setLayoutParams(lp);
}
@Override
public void onBtnClick() {
if (isCollapsed) {
PropertyValuesHolder[] arrayOfPropertyValuesHolder = new PropertyValuesHolder[2];
arrayOfPropertyValuesHolder[0] = PropertyValuesHolder.ofInt("PanelLeft", -300, 0);
arrayOfPropertyValuesHolder[1] = PropertyValuesHolder.ofInt("Panel2W", 1280, 980);
ObjectAnimator localObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
arrayOfPropertyValuesHolder).setDuration(400);
localObjectAnimator.setInterpolator(sCollapseInterpolator);
localObjectAnimator.start();
} else {
PropertyValuesHolder[] arrayOfPropertyValuesHolder = new PropertyValuesHolder[2];
arrayOfPropertyValuesHolder[0] = PropertyValuesHolder.ofInt("PanelLeft", 0, -300);
arrayOfPropertyValuesHolder[1] = PropertyValuesHolder.ofInt("Panel2W", 980, 1280);
ObjectAnimator localObjectAnimator = ObjectAnimator.ofPropertyValuesHolder(this,
arrayOfPropertyValuesHolder).setDuration(400);
localObjectAnimator.setInterpolator(sCollapseInterpolator);
localObjectAnimator.start();
}
isCollapsed = !isCollapsed;
}
上面主要使用了ObjectAnimator动画对象,其中ofInt使用了“panelLef'和”panel2W“这2个属性,这2个属性的set和get方法以及ofInt的使用。条件已经满足可以使用ObjectAnimaor对象。
上面还使用一个对象TimeInterplator,这个属相定义了属性值变化的范围,如线性均匀变化,开始慢然后快等等。timeInterplator是propertyAnimation中使用,在这边列举一些简单的实现对象。
- AccelerateInterpolator 加速,开始时慢中间加速
- DecelerateInterpolator 减速,开始时快然后减速
- AccelerateDecelerateInterolator 先加速后减速,开始结束时慢,中间加速
- AnticipateInterpolator 反向 ,先向相反方向改变一段再加速播放
- AnticipateOvershootInterpolator 反向加超越,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值
- BounceInterpolator 跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100
- CycleIinterpolator 循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)
- LinearInterpolator 线性,线性均匀改变
- OvershottInterpolator 超越,最后超出目的值然后缓慢改变到目的值
- TimeInterpolator 一个接口,允许你自定义interpolator,以上几个都是实现了这个接口
后面再把这三种动画对象的区别讲解下吧。
相关知识参考: