Android一點 仿淘寶購物車動畫
阿新 • • 發佈:2019-01-22
首先看看ios上的淘寶購物車的動畫效果ios淘寶購物車動畫
我們實現的效果
看特效是分為兩個介面,一個是主view,一個是彈出層。彈出層是用dialog實現的,只是加入了彈出的動畫,這裡就不分析了,我們主要看主view的動畫是怎麼實現的,初看好像只是縮放了一點,但是又帶著點其它炫耀的動畫,其實也是通過旋轉、偏移等動畫組合的效果。看看動畫具體的實現,
1、進入的動畫
/**
* 縮放xy,但是y縮放的比例比較小
*/
ObjectAnimator fViewScaleXAnim=ObjectAnimator.ofFloat(this ,"scaleX",1.0f,0.8f);
fViewScaleXAnim.setDuration(350);
ObjectAnimator fViewScaleYAnim=ObjectAnimator.ofFloat(this,"scaleY",1.0f,0.9f);
fViewScaleYAnim.setDuration(350);
/**
* 重點特效
* 通過x的雙重旋轉
*/
ObjectAnimator fViewRotationXAnim = ObjectAnimator.ofFloat(this , "rotationX", 0f, 10f);
fViewRotationXAnim.setDuration(200);
ObjectAnimator fViewResumeAnim = ObjectAnimator.ofFloat(this, "rotationX", 10f, 0f);
fViewResumeAnim.setDuration(150);
fViewResumeAnim.setStartDelay(200);
/**
* y需要的偏移量
*/
ObjectAnimator fViewTransYAnim=ObjectAnimator.ofFloat(this ,"translationY",0,-0.01f* height);
fViewTransYAnim.setDuration(350);
2、退出的動畫(退出動畫是和進入動畫相反的)
ObjectAnimator fViewScaleXAnim=ObjectAnimator.ofFloat(this,"scaleX",0.8f,1.0f);
fViewScaleXAnim.setDuration(350);
ObjectAnimator fViewScaleYAnim=ObjectAnimator.ofFloat(this,"scaleY",0.9f,1.0f);
fViewScaleYAnim.setDuration(350);
ObjectAnimator fViewRotationXAnim = ObjectAnimator.ofFloat(this, "rotationX", 0f, 10f);
fViewRotationXAnim.setDuration(200);
ObjectAnimator fViewResumeAnim = ObjectAnimator.ofFloat(this, "rotationX", 10f, 0f);
fViewResumeAnim.setDuration(150);
fViewResumeAnim.setStartDelay(200);
ObjectAnimator fViewTransYAnim=ObjectAnimator.ofFloat(this,"translationY",-0.01f* height,0);
fViewTransYAnim.setDuration(350);
2、下面開始封裝開發我們的ShopAnimatorView(仿淘寶購物車動畫View)
ShopAnimatorView.java
package com.flyjun.shopanimator.view;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.WindowManager;
import android.widget.RelativeLayout;
public class ShopAnimatorView extends RelativeLayout{
private int width;
private int height;
private AnimatorSet showAnim;
private AnimatorSet hiddenAnim;
private onShopAnimatorListener shopAnimatorListener;
public ShopAnimatorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
this.init();
}
public ShopAnimatorView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
this.init();
}
public ShopAnimatorView(Context context) {
super(context);
// TODO Auto-generated constructor stub
this.init();
}
/**
* 初始化操作
*/
private void init(){
WindowManager wm = (WindowManager) getContext()
.getSystemService(Context.WINDOW_SERVICE);
width = wm.getDefaultDisplay().getWidth();
height = wm.getDefaultDisplay().getHeight();
initShowAnim();
initHiddenAnim();
}
/**
* 進場動畫
*/
private void initShowAnim(){
/**
* 縮放xy,但是y縮放的比例比較小
*/
ObjectAnimator fViewScaleXAnim=ObjectAnimator.ofFloat(this,"scaleX",1.0f,0.8f);
fViewScaleXAnim.setDuration(350);
ObjectAnimator fViewScaleYAnim=ObjectAnimator.ofFloat(this,"scaleY",1.0f,0.9f);
fViewScaleYAnim.setDuration(350);
/**
* 重點特效
* 通過x的雙重旋轉
*/
ObjectAnimator fViewRotationXAnim = ObjectAnimator.ofFloat(this, "rotationX", 0f, 10f);
fViewRotationXAnim.setDuration(200);
ObjectAnimator fViewResumeAnim = ObjectAnimator.ofFloat(this, "rotationX", 10f, 0f);
fViewResumeAnim.setDuration(150);
fViewResumeAnim.setStartDelay(200);
/**
* y需要的偏移量
*/
ObjectAnimator fViewTransYAnim=ObjectAnimator.ofFloat(this,"translationY",0,-0.01f* height);
fViewTransYAnim.setDuration(350);
showAnim=new AnimatorSet();
showAnim.playTogether(fViewScaleXAnim,fViewRotationXAnim,fViewResumeAnim,fViewTransYAnim,fViewScaleYAnim);
/**
* 動畫開始時可以 顯示彈出層
*/
showAnim.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// TODO Auto-generated method stub
if(shopAnimatorListener != null){
shopAnimatorListener.onShowView();
}
}
@Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationCancel(Animator animation) {
// TODO Auto-generated method stub
}
});
}
/**
* 退出動畫
*/
private void initHiddenAnim(){
ObjectAnimator fViewScaleXAnim=ObjectAnimator.ofFloat(this,"scaleX",0.8f,1.0f);
fViewScaleXAnim.setDuration(350);
ObjectAnimator fViewScaleYAnim=ObjectAnimator.ofFloat(this,"scaleY",0.9f,1.0f);
fViewScaleYAnim.setDuration(350);
ObjectAnimator fViewRotationXAnim = ObjectAnimator.ofFloat(this, "rotationX", 0f, 10f);
fViewRotationXAnim.setDuration(200);
ObjectAnimator fViewResumeAnim = ObjectAnimator.ofFloat(this, "rotationX", 10f, 0f);
fViewResumeAnim.setDuration(150);
fViewResumeAnim.setStartDelay(200);
ObjectAnimator fViewTransYAnim=ObjectAnimator.ofFloat(this,"translationY",-0.01f* height,0);
fViewTransYAnim.setDuration(350);
hiddenAnim=new AnimatorSet();
hiddenAnim.playTogether(fViewScaleXAnim,fViewRotationXAnim,fViewResumeAnim,fViewTransYAnim,fViewScaleYAnim);
/**
* 動畫開始時可以 關閉彈出層
*/
hiddenAnim.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// TODO Auto-generated method stub
if(shopAnimatorListener != null){
shopAnimatorListener.onCancelView();
}
}
@Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationCancel(Animator animation) {
// TODO Auto-generated method stub
}
});
}
/**
* 開始進入動畫
*/
public void startShowAnim(){
showAnim.start();
}
/**
* 開始退出動畫
*/
public void startHiddenAnim(){
hiddenAnim.start();
}
/**
* 設定什麼顯示彈出層和關閉彈出層的監聽器
*/
public void setOnShopAnimatorListener(onShopAnimatorListener shopAnimatorListener){
this.shopAnimatorListener=shopAnimatorListener;
}
public interface onShopAnimatorListener{
public void onShowView();
public void onCancelView();
}
}
3、彈出層的封裝(實現用的是dialog)
ShopAnimatorDialog.java
package com.flyjun.shopanimator.view;
import com.flyjun.shopanimator.R;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
public abstract class ShopAnimatorDialog extends Dialog{
private Context context;
private ShopAnimatorView shopAnimatorView;
public ShopAnimatorDialog(Context context,ShopAnimatorView shopAnimatorView) {
super(context);
// TODO Auto-generated constructor stub
this.context=context;
this.shopAnimatorView=shopAnimatorView;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
init();
}
private void init(){
/**
* 彈出的動畫
*/
getWindow().setWindowAnimations(R.style.MyDialogAnimation);
setCanceledOnTouchOutside(false);
/**
* 設定在dialog關閉時恢復動畫
*/
this.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
// TODO Auto-generated method stub
shopAnimatorView.startHiddenAnim();
}
});
setContentView(getContentView());
android.view.WindowManager.LayoutParams ll=getWindow().getAttributes();
ll.width=WindowManager.LayoutParams.MATCH_PARENT;
ll.gravity=Gravity.BOTTOM;
getWindow().setAttributes(ll);
}
/**
* 返回ContentView(檢視view)
* @return
*/
public abstract View getContentView();
public void showDialog(){
if(!isShowing()){
show();
}
}
public void cancelDialog(){
if(isShowing()){
cancel();
}
}
}
彈出層動畫
<style name="MyDialogAnimation">
<!--進入 -->
<item name="android:windowEnterAnimation">@anim/dialog_enter_anim</item>
<!--退出-->
<item name="android:windowExitAnimation">@anim/dialog_exit_anim</item>
</style>
dialog_enter_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromYDelta="100%"
android:toYDelta="0"
android:duration="300"></translate>
</set>
dialog_exit_anim.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromYDelta="0"
android:toYDelta="100%"
android:duration="300"/>
</set>
4、demo程式碼,測試的程式碼就變得簡單了
主view的佈局
<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"
android:background="@android:color/background_dark"
>
<com.flyjun.shopanimator.view.ShopAnimatorView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/shopLayout"
android:background="@android:color/white">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello"
android:textSize="20sp"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="加入購物車"
android:id="@+id/add"
android:layout_alignParentBottom="true"
android:layout_marginBottom="10dp"/>
</com.flyjun.shopanimator.view.ShopAnimatorView>
</RelativeLayout>
MainActivity.java
package com.flyjun.shopanimator;
import com.flyjun.shopanimator.view.ShopAnimatorView;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends Activity {
private ShopAnimatorView shopAnimatorView;
private TestDialog testDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 隱藏標題欄
requestWindowFeature(Window.FEATURE_NO_TITLE);
// 隱藏狀態列
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_main);
this.shopAnimatorView=(ShopAnimatorView) findViewById(R.id.shopLayout);
this.testDialog=new TestDialog(this, shopAnimatorView);
findViewById(R.id.add).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
shopAnimatorView.startShowAnim();
testDialog.showDialog();
}
});
}
@Override
public void onBackPressed() {
// TODO Auto-generated method stub
// super.onBackPressed();
// shopAnimatorView.startHiddenAnim();
testDialog.cancelDialog();
}
}
測試的彈出層
TestDialog.java
package com.flyjun.shopanimator;
import com.flyjun.shopanimator.view.ShopAnimatorDialog;
import com.flyjun.shopanimator.view.ShopAnimatorView;
import android.content.Context;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
public class TestDialog extends ShopAnimatorDialog{
public TestDialog(Context context, ShopAnimatorView shopAnimatorView) {
super(context, shopAnimatorView);
// TODO Auto-generated constructor stub
}
@Override
public View getContentView() {
// TODO Auto-generated method stub
return View.inflate(getContext(), R.layout.test_dialog, null);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
findViewById(R.id.close).setOnClickListener(new android.view.View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
cancelDialog();
}
});
}
}
仿淘寶購物車動畫完成,厲害了Flyjun哥!!!
通過ShopAnimatorView的封裝和ShopAnimatorDialog彈出層的封裝,對於不同的業務和介面都可以輕鬆的實現了