android实现扑克卡片翻转
今天看见一个Android 扑克卡片翻转效果的帖子,于是手痒想学一学,由于接触过的Animation动画等比较少,所以感觉很新奇。
首先,说一下布局,是FrameLayout,这个布局设置一点点击方法,要设置id,之后会用到。这个布局还包括两个子布局,分别是Poke的正面和反面布局。上代码:
还需额外注意一点:这是刚刚才发现的问题,在主activity中,正反面那个xml文件放在后面就会优先默认显示那个xml文件,所以,如果我需要一打开app就看到正面的话,那么正面xml文件需要放到反面xml文件的下面,就是
<?xml version="1.0" encoding="utf-8"?> <FrameLayout 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" android:onClick="flipCard" android:id="@+id/main_fl_container" tools:context="com.example.chenxuanhe.poketest.MainActivity"> <include layout="@layout/cell_card_back" /> <include layout="@layout/cell_card_front" /> </FrameLayout>
根据代码的逻辑线走,则是接下来的两个layout:
这两个FrameLayout也是需要写id的,之后会用到。
cell_card_back.xml:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/main_fl_card_back" > <ImageView android:src="@drawable/rectangle_back" android:contentDescription="@null" android:padding="16dp" android:layout_width="match_parent" android:layout_height="match_parent" /> <TextView android:textColor="@color/colorAccent" android:text="反面" android:textSize="40dp" android:layout_gravity="center" android:gravity="center" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout>
cell_card_front.xml:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/main_fl_card_front"> <ImageView android:src="@drawable/rectangle_front" android:padding="16dp" android:contentDescription="@null" android:layout_width="match_parent" android:layout_height="match_parent" /> <TextView android:textSize="40dp" android:textColor="@color/colorPrimary" android:text="正面" android:gravity="center" android:layout_gravity="center" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout>
继续顺着上面两个布局的逻辑线来走,就需要用到两个Drawable的文件作为背景图,所以接着看drawable文件:
rectangle_back.xml:
大概是一个黑边红底色带圆角的卡片界面
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="16dp"/> <solid android:color="@color/cardBack"/> <stroke android:width="2dp" android:color="@android:color/black"/> </shape>
rectangle_front.xml:
大概是一个黑边灰底色带圆角的卡片界面
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <corners android:radius="16dp"/> <solid android:color="@color/cardFront"/> <stroke android:width="2dp" android:color="@android:color/black"/> </shape>
走完界面UI的逻辑线之后,就去看Java代码,发现需要两个Animator,于是在res文件下创建一个animator资源文件夹,在下创建两个动画文件:
anim-in.xml:
这是一个从左边进入的动画,一开始是隐藏的,逆向旋转,当旋转到一半时,显示卡片
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <!--消失--> <objectAnimator android:duration="0" android:propertyName="alpha" android:valueFrom="1.0" android:valueTo="0.0"/> <!--旋转--> <objectAnimator android:duration="3000" android:propertyName="rotationY" android:valueFrom="-180" android:valueTo="0"/> <!--出现--> <objectAnimator android:duration="0" android:propertyName="alpha" android:startOffset="1500" android:valueFrom="0.0" android:valueTo="1.0"/> </set>
anim_out.xml:
这是一个右边出去的动画,旋转180度,旋转到一半时,卡片就消失了。
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimator android:duration="3000" android:propertyName="rotationY" android:valueFrom="0" android:valueTo="180"/> <!--消失--> <objectAnimator android:duration="0" android:propertyName="alpha" android:startOffset="1500" android:valueFrom="1.0" android:valueTo="0.0"/> </set>
接着看Java代码:
MainActivity:
public class MainActivity extends AppCompatActivity { @Bind(R.id.main_fl_card_back) FrameLayout mFlCardBack; @Bind(R.id.main_fl_card_front) FrameLayout mFlCardFront; @Bind(R.id.main_fl_container) FrameLayout mFlContainer; private AnimatorSet mLeftInSet; private AnimatorSet mRightOutSet; private boolean mIsShowBack; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); setAnimation();//设置动画 setCameraDistance();//设置镜头距离,在这里不是太懂 } private void setAnimation() { //mLeftInSet是左边进入的动画 mLeftInSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.anim_in); //mRightOutSet是右边出去的动画 mRightOutSet = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.anim_out); //点击事件 //通过ListenerAdapter就不需重写所有方法,只需写需要写的方法 mRightOutSet.addListener(new AnimatorListenerAdapter() { //动画开始时候 @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); mFlContainer.setClickable(false); } }); //动画结束的时候 mLeftInSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); mFlContainer.setClickable(true);//主布局中framelayouy的就允许你去点击了 } }); } //一直不是很懂的设置镜头距离, //帖子上的注释写着:改变视角距离,贴近屏幕 private void setCameraDistance() { int distance = 16000; float scale = getResources().getDisplayMetrics().density*distance; mFlCardFront.setCameraDistance(scale);//设置距离 mFlCardBack.setCameraDistance(scale);//设置距离 } //这是主Framelayout的点击方法 public void flipCard(View view){ //mIsShowBack可以理解为互斥,所以为boolean if(!mIsShowBack){ //右出动画设置在正面卡片界面 mRightOutSet.setTarget(mFlCardFront); //左入动画设置在反面卡片界面 mLeftInSet.setTarget(mFlCardBack); //开始动画 mRightOutSet.start(); mLeftInSet.start(); mIsShowBack = true; }else { //右出动画设置在卡片背面界面 mRightOutSet.setTarget(mFlCardBack); //左入动画设置在卡片正面界面 mLeftInSet.setTarget(mFlCardFront); mRightOutSet.start(); mLeftInSet.start(); mIsShowBack = false; } } //这一点我一直没想到,还可以在onDestroy方法中解绑ButterKnife protected void onDestroy(){ super.onDestroy(); ButterKnife.unbind(this); } }
到这一步,基本就全部完成了。