Android自定义view教程04-------------自定义属性动画
不太会美工,所以随便写了个菜单打开关闭的动画,主要是教会大家如何使用属性动画,可以这么说
学会属性动画 前面的fream动画和tween动画可以不用看了,因为他们2能做的,属性动画也能做,
他们2不能做的,属性动画也能做。
直接上代码吧,注释写的还算详细。
主activity代码 实际上没啥好看的,主要就是使用了dialogfragment,没有用dialog,因为谷歌后来推荐
我们使用这个dialogfragment,而且这个确实比dialog要优秀方便很多。
package com.example.dialogfragmenttest; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTransaction; import android.view.View; import android.widget.TextView; public class MainActivity extends FragmentActivity { private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv = (TextView) this.findViewById(R.id.tv); tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub MyDialogFragment fragment = new MyDialogFragment(); FragmentTransaction ft = getSupportFragmentManager() .beginTransaction(); ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); fragment.show(ft, "df"); } }); } }
然后主要看一下我们这个dialogfragment的代码,这边代码写的比较乱,不过还算详细,我并没有怎么优化他,主要目的是让大家看懂。有兴趣的同学可以继续优化这边代码
1 package com.example.dialogfragmenttest; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import android.animation.Animator; 7 import android.animation.AnimatorSet; 8 import android.animation.ObjectAnimator; 9 import android.os.Bundle; 10 import android.os.Handler; 11 import android.support.v4.app.DialogFragment; 12 import android.view.LayoutInflater; 13 import android.view.View; 14 import android.view.ViewGroup; 15 import android.view.WindowManager; 16 import android.view.animation.LinearInterpolator; 17 import android.widget.ImageView; 18 import android.widget.TextView; 19 20 import com.nineoldandroids.view.ViewHelper; 21 22 public class MyDialogFragment extends DialogFragment { 23 24 // 显示菜单的动画 集 25 private AnimatorSet mAnimatorSetShowMenu; 26 27 // 关闭菜单的动画 集 28 private AnimatorSet mAnimatorSetCloseMenu; 29 30 // 那个叉叉按钮 实际上就是关闭菜单用的 31 private ImageView cancelImageView; 32 // 这个是叉叉按钮旁边的文字 但是在xml文件里设置了不可见 33 // 这么做的原因是 动画要配对,如果是6个图片对应着5个文字的话,动画就不配对了 34 // 这个地方放这个不可见的tv 只是为了配对,不信大家把这个tv删掉就知道 动画效果很奇怪了 35 private TextView icncancel_tv; 36 37 // 这边定义的就是四个菜单 每个菜单分别有文字部分和图片部分 38 private TextView oneTv, twoTv, threeTv, fourTv; 39 private ImageView oneIv, twoIv, threeIv, fourIv; 40 41 private Handler mHandler = new Handler() { 42 public void handleMessage(android.os.Message msg) { 43 44 switch (msg.what) { 45 // 关闭菜单 46 case 0: 47 mAnimatorSetCloseMenu.start(); 48 break; 49 // 打开菜单 50 case 1: 51 mAnimatorSetShowMenu.start(); 52 break; 53 default: 54 break; 55 } 56 }; 57 }; 58 59 @Override 60 public View onCreateView(LayoutInflater inflater, ViewGroup container, 61 Bundle savedInstanceState) { 62 View v = inflater.inflate(R.layout.fragment_menu, container, false); 63 initViews(v); 64 // 初始化打开菜单和关闭菜单的动画set 65 initMenuOpenAnimatorSet(); 66 initMenuCloseAnimatorSet(); 67 // 设置一些属性 68 getDialog().getWindow().clearFlags( 69 WindowManager.LayoutParams.FLAG_DIM_BEHIND); 70 // 这个函数调用实际上很重要,因为我们这个对话框刚成立的时候 一定要把我们的view 71 // 设置成不可见的,实际上反过来说就是一定要把我们的控件设置成关闭后的属性。 72 // 不然效果就变成了一开始这些view 就直接刷出来了,然后刷出来以后再执行动画, 73 // 那样效果很糟糕,可以尝试把这个代码删掉就知道是什么效果 74 initStartStatus(); 75 // 打开菜单 76 mHandler.sendEmptyMessage(1); 77 return v; 78 } 79 80 @Override 81 public void onCreate(Bundle savedInstanceState) { 82 // TODO Auto-generated method stub 83 super.onCreate(savedInstanceState); 84 // 设置对话框属性 85 setStyle(STYLE_NO_FRAME, R.style.MenuFragmentStyle); 86 87 } 88 89 private void initViews(View view) { 90 cancelImageView = (ImageView) view.findViewById(R.id.cancel_icon); 91 cancelImageView.setOnClickListener(new View.OnClickListener() { 92 93 @Override 94 public void onClick(View v) { 95 // TODO Auto-generated method stub 96 mHandler.sendEmptyMessage(0); 97 } 98 }); 99 icncancel_tv = (TextView) view.findViewById(R.id.icncancel_tv); 100 oneIv = (ImageView) view.findViewById(R.id.icn1); 101 oneTv = (TextView) view.findViewById(R.id.icn1_tv); 102 103 twoIv = (ImageView) view.findViewById(R.id.icn2); 104 twoTv = (TextView) view.findViewById(R.id.icn2_tv); 105 106 threeIv = (ImageView) view.findViewById(R.id.icn3); 107 threeTv = (TextView) view.findViewById(R.id.icn3_tv); 108 109 fourIv = (ImageView) view.findViewById(R.id.icn4); 110 fourTv = (TextView) view.findViewById(R.id.icn4_tv); 111 } 112 113 /** 114 * 初始化一开始的状态 其实也就是关闭菜单以后的状态 这里我们偷懒引用了nineoldandroids 这个库里面的函数 115 * 有兴趣的同学可以谷歌一下nineoldandroids这个库的用法和介绍 116 * 117 */ 118 private void initStartStatus() { 119 ViewHelper.setAlpha(oneTv, 0); 120 ViewHelper.setAlpha(twoTv, 0); 121 ViewHelper.setAlpha(threeTv, 0); 122 ViewHelper.setAlpha(fourTv, 0); 123 124 ViewHelper.setRotation(cancelImageView, 0); 125 ViewHelper.setRotationY(cancelImageView, -90); 126 ViewHelper.setRotationX(cancelImageView, 0); 127 128 ViewHelper.setRotation(oneIv, 0); 129 ViewHelper.setRotationY(oneIv, 0); 130 ViewHelper.setRotationX(oneIv, -90); 131 ViewHelper.setRotation(twoIv, 0); 132 ViewHelper.setRotationY(twoIv, 0); 133 ViewHelper.setRotationX(twoIv, -90); 134 ViewHelper.setRotation(threeIv, 0); 135 ViewHelper.setRotationY(threeIv, 0); 136 ViewHelper.setRotationX(threeIv, -90); 137 ViewHelper.setRotation(fourIv, 0); 138 ViewHelper.setRotationY(fourIv, 0); 139 ViewHelper.setRotationX(fourIv, -90); 140 } 141 142 /** 143 * 获取关闭菜单的动画集合 144 */ 145 private void initMenuCloseAnimatorSet() { 146 147 // 文本部分的动画--关闭 148 List<Animator> textAnimations = new ArrayList<Animator>(); 149 // 图片部分的动画--关闭 150 List<Animator> imageAnimations = new ArrayList<Animator>(); 151 152 // 下面开始弄 文本部分消失的时候的动画 实际上这里就是和打开菜单的动画是相反的 153 // 与打开动画相同的是 我们的icncancel_tv 这个控件依然是不可见的,只不过起到一个填充的顺序 154 // 保证动画一起执行时的顺序 155 AnimatorSet textAnimatorSetXX = new AnimatorSet(); 156 textAnimatorSetXX.playTogether( 157 ObjectAnimator.ofFloat(icncancel_tv, "alpha", 1, 0), 158 ObjectAnimator.ofFloat(icncancel_tv, "translationX", 0, 8)); 159 AnimatorSet textAnimatorSetOne = new AnimatorSet(); 160 textAnimatorSetOne.playTogether( 161 ObjectAnimator.ofFloat(oneTv, "alpha", 1, 0), 162 ObjectAnimator.ofFloat(oneTv, "translationX", 0, 8)); 163 164 AnimatorSet textAnimatorSetTwo = new AnimatorSet(); 165 textAnimatorSetTwo.playTogether( 166 ObjectAnimator.ofFloat(twoTv, "alpha", 1, 0), 167 ObjectAnimator.ofFloat(twoTv, "translationX", 0, 8)); 168 169 AnimatorSet textAnimatorSeThree = new AnimatorSet(); 170 textAnimatorSeThree.playTogether( 171 ObjectAnimator.ofFloat(threeTv, "alpha", 1, 0), 172 ObjectAnimator.ofFloat(threeTv, "translationX", 0, 8)); 173 174 AnimatorSet textAnimatorSetFour = new AnimatorSet(); 175 textAnimatorSetFour.playTogether( 176 ObjectAnimator.ofFloat(fourTv, "alpha", 1, 0), 177 ObjectAnimator.ofFloat(fourTv, "translationX", 0, 8)); 178 // 把文字动画放在一起 注意顺序 注意这次是关闭的动画 看一下这个add的顺序 179 // 从下往上关闭菜单 所以add的顺序要注意 180 textAnimations.add(textAnimatorSetFour); 181 textAnimations.add(textAnimatorSeThree); 182 textAnimations.add(textAnimatorSetTwo); 183 textAnimations.add(textAnimatorSetOne); 184 textAnimations.add(textAnimatorSetXX); 185 186 // 图片动画也是一样 从下往上关闭 所以要注意add的顺序 187 imageAnimations 188 .add(ObjectAnimator.ofFloat(fourIv, "rotationX", 0, -90)); 189 imageAnimations.add(ObjectAnimator 190 .ofFloat(threeIv, "rotationX", 0, -90)); 191 imageAnimations.add(ObjectAnimator.ofFloat(twoIv, "rotationX", 0, -90)); 192 imageAnimations.add(ObjectAnimator.ofFloat(oneIv, "rotationX", 0, -90)); 193 // 第一个叉叉出现时的动画 放入集合 注意他是从右往左出现的 194 imageAnimations.add(ObjectAnimator.ofFloat(cancelImageView, 195 "rotationY", 0, -90)); 196 197 // 现在我们来获取动画的集合 198 // 先获取文字的动画集合 199 AnimatorSet textCloseAnimatorSet = new AnimatorSet(); 200 textCloseAnimatorSet.playSequentially(textAnimations); 201 // 再获取图片的动画集合 202 AnimatorSet imageCloseAnimatorSet = new AnimatorSet(); 203 imageCloseAnimatorSet.playSequentially(imageAnimations); 204 205 // 最后把文字和图片的属性动画 放在一起 206 // 所以在这要保证 一定是6个图片动画和6个文字动画 不然就不是配对执行了,执行起来会比较难看 207 mAnimatorSetCloseMenu = new AnimatorSet(); 208 mAnimatorSetCloseMenu.playTogether(imageCloseAnimatorSet, 209 textCloseAnimatorSet); 210 mAnimatorSetCloseMenu.setDuration(300); 211 mAnimatorSetCloseMenu.setStartDelay(0); 212 // 插值器 213 mAnimatorSetCloseMenu.setInterpolator(new LinearInterpolator()); 214 215 } 216 217 /** 218 * 获取打开菜单的动画集合 219 */ 220 private void initMenuOpenAnimatorSet() { 221 // 文本部分的动画 注意这是一个list 这里面的元素每一个都是 单独的属性动画 222 List<Animator> textAnimations = new ArrayList<Animator>(); 223 // 图片部分的动画 224 List<Animator> imageAnimations = new ArrayList<Animator>(); 225 // 第一个叉叉出现时的动画 放入集合 注意他是从右往左出现的 226 imageAnimations.add(ObjectAnimator.ofFloat(cancelImageView, 227 "rotationY", -90, 0)); 228 229 // 注意其他菜单元素出现的时候imageview 都是 从上往下出现的和第一个xx出现的时候不一样 230 imageAnimations.add(ObjectAnimator.ofFloat(oneIv, "rotationX", 90, 0)); 231 imageAnimations.add(ObjectAnimator.ofFloat(twoIv, "rotationX", 90, 0)); 232 imageAnimations.add(ObjectAnimator 233 .ofFloat(threeIv, "rotationX", -90, 0)); 234 imageAnimations 235 .add(ObjectAnimator.ofFloat(fourIv, "rotationX", -90, 0)); 236 237 // 下面开始弄 文本部分出现的时候的动画 238 AnimatorSet textAnimatorSetXX = new AnimatorSet(); 239 textAnimatorSetXX.playTogether( 240 ObjectAnimator.ofFloat(icncancel_tv, "alpha", 0, 1), 241 ObjectAnimator.ofFloat(icncancel_tv, "translationX", 8, 0)); 242 // 文本动画其实比较简单 一个是透明度的变化 另外带着一点位移动画 243 AnimatorSet textAnimatorSetOne = new AnimatorSet(); 244 // 前面是透明度变化 后面是位移变化 245 textAnimatorSetOne.playTogether( 246 ObjectAnimator.ofFloat(oneTv, "alpha", 0, 1), 247 ObjectAnimator.ofFloat(oneTv, "translationX", 8, 0)); 248 249 AnimatorSet textAnimatorSetTwo = new AnimatorSet(); 250 // 前面是透明度变化 后面是位移变化 251 textAnimatorSetTwo.playTogether( 252 ObjectAnimator.ofFloat(twoTv, "alpha", 0, 1), 253 ObjectAnimator.ofFloat(twoTv, "translationX", 8, 0)); 254 255 AnimatorSet textAnimatorSeThree = new AnimatorSet(); 256 // 前面是透明度变化 后面是位移变化 257 textAnimatorSeThree.playTogether( 258 ObjectAnimator.ofFloat(threeTv, "alpha", 0, 1), 259 ObjectAnimator.ofFloat(threeTv, "translationX", 8, 0)); 260 261 AnimatorSet textAnimatorSetFour = new AnimatorSet(); 262 // 前面是透明度变化 后面是位移变化 263 textAnimatorSetFour.playTogether( 264 ObjectAnimator.ofFloat(fourTv, "alpha", 0, 1), 265 ObjectAnimator.ofFloat(fourTv, "translationX", 8, 0)); 266 // 把文字动画放在一起 注意顺序 267 textAnimations.add(textAnimatorSetXX); 268 textAnimations.add(textAnimatorSetOne); 269 textAnimations.add(textAnimatorSetTwo); 270 textAnimations.add(textAnimatorSeThree); 271 textAnimations.add(textAnimatorSetFour); 272 273 // 现在我们来获取动画的集合 274 // 先获取文字的动画集合 275 AnimatorSet textOpenAnimatorSet = new AnimatorSet(); 276 textOpenAnimatorSet.playSequentially(textAnimations); 277 // 再获取图片的动画集合 278 AnimatorSet imageOpenAnimatorSet = new AnimatorSet(); 279 imageOpenAnimatorSet.playSequentially(imageAnimations); 280 281 // 最后把文字和图片的属性动画 放在一起 282 mAnimatorSetShowMenu = new AnimatorSet(); 283 mAnimatorSetShowMenu.playTogether(imageOpenAnimatorSet, 284 textOpenAnimatorSet); 285 mAnimatorSetShowMenu.setDuration(300); 286 mAnimatorSetShowMenu.setStartDelay(0); 287 // 插值器 288 mAnimatorSetShowMenu.setInterpolator(new LinearInterpolator()); 289 } 290 }
然后把这个dialog的布局文件看一下,
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/menu_fragment_background" android:orientation="vertical" > <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="40dp" > <ImageView android:id="@+id/cancel_icon" android:layout_width="40dp" android:layout_height="40dp" android:layout_alignParentRight="true" android:background="#ffffff" android:src="@drawable/icn_close" > </ImageView> <TextView android:id="@+id/icncancel_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginRight="8dp" android:layout_toLeftOf="@id/cancel_icon" android:gravity="center" android:text="发送短信" android:textColor="#ffffffff" android:textSize="14sp" android:visibility="invisible" > </TextView> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/icn1" android:layout_width="40dp" android:layout_height="40dp" android:layout_alignParentRight="true" android:background="#ffffff" android:src="@drawable/icn_1" > </ImageView> <TextView android:id="@+id/icn1_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginRight="8dp" android:layout_toLeftOf="@id/icn1" android:gravity="center" android:text="发送短信" android:textColor="#ffffffff" android:textSize="14sp" > </TextView> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/icn2" android:layout_width="40dp" android:layout_height="40dp" android:layout_alignParentRight="true" android:background="#ffffff" android:src="@drawable/icn_2" > </ImageView> <TextView android:id="@+id/icn2_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginRight="8dp" android:layout_toLeftOf="@id/icn2" android:gravity="center" android:text="点赞" android:textColor="#ffffffff" android:textSize="14sp" > </TextView> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/icn3" android:layout_width="40dp" android:layout_height="40dp" android:layout_alignParentRight="true" android:background="#ffffff" android:src="@drawable/icn_3" > </ImageView> <TextView android:id="@+id/icn3_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginRight="8dp" android:layout_toLeftOf="@id/icn3" android:gravity="center" android:text="添加联系人" android:textColor="#ffffffff" android:textSize="14sp" > </TextView> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <ImageView android:id="@+id/icn4" android:layout_width="40dp" android:layout_height="40dp" android:layout_alignParentRight="true" android:background="#ffffff" android:src="@drawable/icn_4" > </ImageView> <TextView android:id="@+id/icn4_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginRight="8dp" android:layout_toLeftOf="@id/icn4" android:gravity="center" android:text="爱他就点他" android:textColor="#ffffffff" android:textSize="14sp" > </TextView> </RelativeLayout> </LinearLayout>
基本就是这样了,有看不懂的可以私信问我,或者留言问。
这边偷懒了,没有继续设置PivotX PivotY这2个属性的 变化,否则应该动画效果更美丽一些,有兴趣的可以自行拓展。
关于Android动画的教程差不多就到这里结束了,下面应该会讲一下 自定义view的一些原理和技巧,然后讲一下滑动触摸事件,
最后3者结合起来带大家分析1-2个牛逼的开源控件,这个系列的教程就要结束了,争取4月份能结束他!
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。