├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── kevin │ │ └── tech │ │ └── dialogfliptest │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── kevin │ │ │ └── tech │ │ │ └── dialogfliptest │ │ │ ├── DActivity.java │ │ │ ├── ForgetPasswordFragment.java │ │ │ ├── LoginActivity.java │ │ │ ├── LoginFragment.java │ │ │ ├── MainActivity.java │ │ │ ├── MyDialog.java │ │ │ └── Rotate3dAnimation.java │ └── res │ │ ├── animator │ │ ├── card_flip_left_in.xml │ │ ├── card_flip_left_out.xml │ │ ├── card_flip_right_in.xml │ │ └── card_flip_right_out.xml │ │ ├── drawable-xhdpi │ │ ├── bg_2.xml │ │ ├── bg_shape_update_version_dialog.xml │ │ └── ic_avatar.png │ │ ├── drawable │ │ ├── bg_button_login.xml │ │ └── bg_button_register.xml │ │ ├── layout │ │ ├── activity_d.xml │ │ ├── activity_login.xml │ │ ├── activity_main.xml │ │ ├── dialog_my.xml │ │ ├── fragment_forget_password.xml │ │ └── fragment_login.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── integers.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── kevin │ └── tech │ └── dialogfliptest │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img └── dialogFlip.gif └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DialogFlipTest 2 | Android实现dialog的3D翻转效果 3 | 4 | ![pic](https://github.com/student9128/DialogFlipTest/blob/master/img/dialogFlip.gif) 5 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 26 5 | buildToolsVersion "25.0.3" 6 | defaultConfig { 7 | applicationId "com.kevin.tech.dialogfliptest" 8 | minSdkVersion 15 9 | targetSdkVersion 26 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(dir: 'libs', include: ['*.jar']) 24 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 25 | exclude group: 'com.android.support', module: 'support-annotations' 26 | }) 27 | compile 'com.android.support:appcompat-v7:26.+' 28 | compile 'com.android.support.constraint:constraint-layout:1.0.2' 29 | testCompile 'junit:junit:4.12' 30 | compile 'com.jakewharton:butterknife:8.6.0' 31 | annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0' 32 | } 33 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Users\Administrator\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/kevin/tech/dialogfliptest/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.kevin.tech.dialogfliptest; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.kevin.tech.dialogfliptest", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/kevin/tech/dialogfliptest/DActivity.java: -------------------------------------------------------------------------------- 1 | package com.kevin.tech.dialogfliptest; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.view.animation.AccelerateInterpolator; 7 | import android.view.animation.Animation; 8 | import android.view.animation.Animation.AnimationListener; 9 | import android.view.animation.DecelerateInterpolator; 10 | import android.widget.Button; 11 | import android.widget.ImageView; 12 | import android.widget.RelativeLayout; 13 | import android.widget.TextView; 14 | 15 | 16 | /** 17 | * Created by JingPeng on 2017/8/17. 18 | *

19 | *

Description:

20 | *

21 | *

22 | */ 23 | 24 | 25 | public class DActivity extends AppCompatActivity { 26 | private RelativeLayout mContentRl; 27 | private ImageView mLogoIv; 28 | private TextView mDescTv; 29 | private Button mOpenBtn; 30 | 31 | private int centerX; 32 | private int centerY; 33 | private int depthZ = 200; 34 | private int duration = 3000; 35 | private Rotate3dAnimation openAnimation; 36 | private Rotate3dAnimation closeAnimation; 37 | 38 | private boolean isOpen = false; 39 | 40 | @Override 41 | protected void onCreate(Bundle savedInstanceState) { 42 | super.onCreate(savedInstanceState); 43 | setContentView(R.layout.activity_d); 44 | 45 | mContentRl = (RelativeLayout) findViewById(R.id.rl_content); 46 | mLogoIv = (ImageView) findViewById(R.id.iv_logo); 47 | mDescTv = (TextView) findViewById(R.id.tv_desc); 48 | mOpenBtn = (Button) findViewById(R.id.btn_open); 49 | 50 | } 51 | 52 | /** 53 | * 卡牌文本介绍打开效果:注意旋转角度 54 | */ 55 | private void initOpenAnim() { 56 | //从0到90度,顺时针旋转视图,此时reverse参数为true,达到90度时动画结束时视图变得不可见, 57 | openAnimation = new Rotate3dAnimation(0, 90, centerX, centerY, depthZ, true); 58 | openAnimation.setDuration(duration); 59 | openAnimation.setFillAfter(true); 60 | openAnimation.setInterpolator(new AccelerateInterpolator()); 61 | openAnimation.setAnimationListener(new AnimationListener() { 62 | 63 | @Override 64 | public void onAnimationStart(Animation animation) { 65 | 66 | } 67 | 68 | @Override 69 | public void onAnimationRepeat(Animation animation) { 70 | 71 | } 72 | 73 | @Override 74 | public void onAnimationEnd(Animation animation) { 75 | mLogoIv.setVisibility(View.VISIBLE); 76 | mDescTv.setVisibility(View.GONE); 77 | 78 | //从270到360度,顺时针旋转视图,此时reverse参数为false,达到360度动画结束时视图变得可见 79 | Rotate3dAnimation rotateAnimation = new Rotate3dAnimation(270, 360, centerX, centerY, depthZ, false); 80 | rotateAnimation.setDuration(duration); 81 | rotateAnimation.setFillAfter(true); 82 | rotateAnimation.setInterpolator(new DecelerateInterpolator()); 83 | mContentRl.startAnimation(rotateAnimation); 84 | } 85 | }); 86 | } 87 | 88 | /** 89 | * 卡牌文本介绍关闭效果:旋转角度与打开时逆行即可 90 | */ 91 | private void initCloseAnim() { 92 | closeAnimation = new Rotate3dAnimation(360, 270, centerX, centerY, depthZ, true); 93 | closeAnimation.setDuration(duration); 94 | closeAnimation.setFillAfter(true); 95 | closeAnimation.setInterpolator(new AccelerateInterpolator()); 96 | closeAnimation.setAnimationListener(new AnimationListener() { 97 | 98 | @Override 99 | public void onAnimationStart(Animation animation) { 100 | 101 | } 102 | 103 | @Override 104 | public void onAnimationRepeat(Animation animation) { 105 | 106 | } 107 | 108 | @Override 109 | public void onAnimationEnd(Animation animation) { 110 | mLogoIv.setVisibility(View.GONE); 111 | mDescTv.setVisibility(View.VISIBLE); 112 | 113 | Rotate3dAnimation rotateAnimation = new Rotate3dAnimation(90, 0, centerX, centerY, depthZ, false); 114 | rotateAnimation.setDuration(duration); 115 | rotateAnimation.setFillAfter(true); 116 | rotateAnimation.setInterpolator(new DecelerateInterpolator()); 117 | mContentRl.startAnimation(rotateAnimation); 118 | } 119 | }); 120 | } 121 | 122 | public void onClickView(View v) { 123 | //以旋转对象的中心点为旋转中心点,这里主要不要再onCreate方法中获取,因为视图初始绘制时,获取的宽高为0 124 | centerX = mContentRl.getWidth() / 2; 125 | centerY = mContentRl.getHeight() / 2; 126 | if (openAnimation == null) { 127 | initOpenAnim(); 128 | initCloseAnim(); 129 | } 130 | 131 | //用作判断当前点击事件发生时动画是否正在执行 132 | if (openAnimation.hasStarted() && !openAnimation.hasEnded()) { 133 | return; 134 | } 135 | if (closeAnimation.hasStarted() && !closeAnimation.hasEnded()) { 136 | return; 137 | } 138 | 139 | //判断动画执行 140 | if (isOpen) { 141 | mContentRl.startAnimation(openAnimation); 142 | 143 | } else { 144 | mContentRl.startAnimation(closeAnimation); 145 | 146 | } 147 | 148 | isOpen = !isOpen; 149 | mOpenBtn.setText(isOpen ? "关闭" : "打开"); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /app/src/main/java/com/kevin/tech/dialogfliptest/ForgetPasswordFragment.java: -------------------------------------------------------------------------------- 1 | package com.kevin.tech.dialogfliptest; 2 | 3 | import android.app.Activity; 4 | import android.app.Fragment; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.Button; 11 | import android.widget.EditText; 12 | 13 | import butterknife.BindView; 14 | import butterknife.ButterKnife; 15 | import butterknife.Unbinder; 16 | 17 | /** 18 | * Created by Kevin on 2017/8/16. 19 | *

20 | *

Description:

21 | *

22 | *

23 | */ 24 | 25 | 26 | public class ForgetPasswordFragment extends Fragment implements View.OnClickListener { 27 | 28 | Unbinder unbinder; 29 | @BindView(R.id.et_email) 30 | EditText etEmil; 31 | @BindView(R.id.btn_back) 32 | Button btnBack; 33 | 34 | @Override 35 | public void onAttach(Activity activity) { 36 | super.onAttach(activity); 37 | try { 38 | mCallback = (OnBackListener) activity; 39 | } catch (ClassCastException e) { 40 | throw new ClassCastException(activity.toString() + "must implement OnBackListener"); 41 | } 42 | } 43 | 44 | @Nullable 45 | @Override 46 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 47 | View mView = inflater.inflate(R.layout.fragment_forget_password, container, false); 48 | unbinder = ButterKnife.bind(this, mView); 49 | btnBack.setOnClickListener(this); 50 | return mView; 51 | } 52 | 53 | @Override 54 | public void onDestroyView() { 55 | super.onDestroyView(); 56 | unbinder.unbind(); 57 | } 58 | 59 | OnBackListener mCallback; 60 | 61 | @Override 62 | public void onClick(View view) { 63 | mCallback.goBack(); 64 | } 65 | 66 | public interface OnBackListener { 67 | void goBack(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/kevin/tech/dialogfliptest/LoginActivity.java: -------------------------------------------------------------------------------- 1 | package com.kevin.tech.dialogfliptest; 2 | 3 | import android.app.FragmentTransaction; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.widget.FrameLayout; 8 | 9 | import butterknife.BindView; 10 | import butterknife.ButterKnife; 11 | 12 | /** 13 | * Created by Kevin on 2017/8/16. 14 | *

15 | *

Description:

16 | *

17 | *

18 | */ 19 | 20 | 21 | public class LoginActivity extends AppCompatActivity implements LoginFragment.OnForgetListener, ForgetPasswordFragment.OnBackListener { 22 | @BindView(R.id.fl_content) 23 | FrameLayout flContent; 24 | 25 | @Override 26 | protected void onCreate(@Nullable Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | setContentView(R.layout.activity_login); 29 | ButterKnife.bind(this); 30 | // if (savedInstanceState == null) { 31 | FragmentTransaction beginTransaction = getFragmentManager().beginTransaction(); 32 | beginTransaction.add(R.id.fl_content, new LoginFragment()).commit(); 33 | 34 | } 35 | 36 | @Override 37 | public void forgetPassword() { 38 | getFragmentManager().beginTransaction() 39 | .setCustomAnimations(R.animator.card_flip_left_in, R.animator.card_flip_left_out, 40 | R.animator.card_flip_right_in, R.animator.card_flip_right_out) 41 | .replace(R.id.fl_content, new ForgetPasswordFragment()) 42 | .addToBackStack(null).commit(); 43 | } 44 | 45 | @Override 46 | public void goBack() { 47 | getFragmentManager().popBackStack(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/kevin/tech/dialogfliptest/LoginFragment.java: -------------------------------------------------------------------------------- 1 | package com.kevin.tech.dialogfliptest; 2 | 3 | import android.app.Activity; 4 | import android.app.DialogFragment; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.CheckBox; 11 | import android.widget.EditText; 12 | import android.widget.TextView; 13 | 14 | import butterknife.BindView; 15 | import butterknife.ButterKnife; 16 | import butterknife.Unbinder; 17 | 18 | /** 19 | * Created by Kevin on 2017/8/16. 20 | *

21 | *

Description:

22 | *

23 | *

24 | */ 25 | 26 | 27 | public class LoginFragment extends DialogFragment implements View.OnClickListener { 28 | @BindView(R.id.et_user_name) 29 | EditText etUserName; 30 | @BindView(R.id.et_password) 31 | EditText etPassword; 32 | @BindView(R.id.cb_auto_login) 33 | CheckBox cbAutoLogin; 34 | @BindView(R.id.tv_forget_pwd) 35 | TextView tvForgetPwd; 36 | Unbinder unbinder; 37 | 38 | @Override 39 | public void onAttach(Activity context) { 40 | super.onAttach(context); 41 | try { 42 | mCallback = (OnForgetListener) context; 43 | } catch (ClassCastException e) { 44 | throw new ClassCastException(context.toString() + "must implement OnForgetListener"); 45 | } 46 | } 47 | 48 | @Nullable 49 | @Override 50 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 51 | View mView = inflater.inflate(R.layout.fragment_login, container, false); 52 | unbinder = ButterKnife.bind(this, mView); 53 | tvForgetPwd.setOnClickListener(this); 54 | return mView; 55 | } 56 | 57 | @Override 58 | public void onDestroyView() { 59 | super.onDestroyView(); 60 | unbinder.unbind(); 61 | } 62 | 63 | OnForgetListener mCallback; 64 | 65 | @Override 66 | public void onClick(View view) { 67 | mCallback.forgetPassword(); 68 | } 69 | 70 | public interface OnForgetListener { 71 | void forgetPassword(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/kevin/tech/dialogfliptest/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.kevin.tech.dialogfliptest; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | import android.widget.Button; 8 | 9 | import butterknife.BindView; 10 | import butterknife.ButterKnife; 11 | 12 | public class MainActivity extends AppCompatActivity { 13 | 14 | @BindView(R.id.btn_login) 15 | Button btnLogin; 16 | @BindView(R.id.btn_3d) 17 | Button btn3d; 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_main); 23 | ButterKnife.bind(this); 24 | final MyDialog dialog = new MyDialog(this); 25 | btnLogin.setOnClickListener(new View.OnClickListener() { 26 | @Override 27 | public void onClick(View view) { 28 | startActivity(new Intent(MainActivity.this, LoginActivity.class)); 29 | } 30 | }); 31 | btn3d.setOnClickListener(new View.OnClickListener() { 32 | @Override 33 | public void onClick(View view) { 34 | dialog.show(); 35 | // startActivity(new Intent(MainActivity.this, DActivity.class)); 36 | } 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/kevin/tech/dialogfliptest/MyDialog.java: -------------------------------------------------------------------------------- 1 | package com.kevin.tech.dialogfliptest; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.graphics.Typeface; 6 | import android.os.Bundle; 7 | import android.text.method.PasswordTransformationMethod; 8 | import android.util.DisplayMetrics; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.Window; 12 | import android.view.WindowManager; 13 | import android.view.animation.AccelerateInterpolator; 14 | import android.view.animation.Animation; 15 | import android.view.animation.DecelerateInterpolator; 16 | import android.widget.Button; 17 | import android.widget.CheckBox; 18 | import android.widget.EditText; 19 | import android.widget.LinearLayout; 20 | import android.widget.RelativeLayout; 21 | import android.widget.TextView; 22 | 23 | import butterknife.BindView; 24 | import butterknife.ButterKnife; 25 | 26 | 27 | /** 28 | * Created by Kevin on 2017/8/17. 29 | *

30 | *

Description:

31 | *

32 | *

33 | */ 34 | public class MyDialog extends Dialog { 35 | 36 | @BindView(R.id.et_user_name) 37 | EditText etUserName; 38 | @BindView(R.id.et_password) 39 | EditText etPassword; 40 | @BindView(R.id.cb_auto_login) 41 | CheckBox cbAutoLogin; 42 | @BindView(R.id.tv_forget_pwd) 43 | TextView tvForgetPwd; 44 | @BindView(R.id.ll_content) 45 | LinearLayout llContent; 46 | @BindView(R.id.et_email) 47 | EditText etEmail; 48 | @BindView(R.id.btn_back) 49 | Button btnBack; 50 | @BindView(R.id.container) 51 | RelativeLayout container; 52 | private Context context; 53 | 54 | @BindView(R.id.ll_register) 55 | LinearLayout llRegister; 56 | 57 | 58 | //接口回调传递参数 59 | private OnClickListenerInterface mListener; 60 | private View view; 61 | // 62 | private String strContent; 63 | 64 | 65 | private int centerX; 66 | private int centerY; 67 | private int depthZ = 700; 68 | private int duration = 300; 69 | private Rotate3dAnimation openAnimation; 70 | private Rotate3dAnimation closeAnimation; 71 | 72 | private boolean isOpen = false; 73 | 74 | public interface OnClickListenerInterface { 75 | 76 | /** 77 | * 确认, 78 | */ 79 | void doConfirm(); 80 | 81 | /** 82 | * 取消 83 | */ 84 | // public void doCancel(); 85 | } 86 | 87 | public MyDialog(Context context) { 88 | super(context); 89 | this.context = context; 90 | } 91 | 92 | public MyDialog(Context context, String content) { 93 | super(context); 94 | this.context = context; 95 | this.strContent = content; 96 | 97 | } 98 | 99 | @Override 100 | protected void onCreate(Bundle savedInstanceState) { 101 | super.onCreate(savedInstanceState); 102 | //去掉系统的黑色矩形边框 103 | getWindow().setBackgroundDrawableResource(android.R.color.transparent); 104 | requestWindowFeature(Window.FEATURE_NO_TITLE); 105 | 106 | init(); 107 | } 108 | 109 | public void init() { 110 | LayoutInflater inflater = LayoutInflater.from(context); 111 | view = inflater.inflate(R.layout.dialog_my, null); 112 | setContentView(view); 113 | ButterKnife.bind(this); 114 | etPassword.setTypeface(Typeface.DEFAULT); 115 | etPassword.setTransformationMethod(new PasswordTransformationMethod()); 116 | tvForgetPwd.setOnClickListener(new OnWidgetClickListener()); 117 | btnBack.setOnClickListener(new OnWidgetClickListener()); 118 | Window dialogWindow = getWindow(); 119 | WindowManager.LayoutParams lp = dialogWindow.getAttributes(); 120 | DisplayMetrics d = context.getResources().getDisplayMetrics(); // 获取屏幕宽、高用 121 | lp.width = (int) (d.widthPixels * 0.8); // 高度设置为屏幕的0.6 122 | lp.height = (int) (d.heightPixels * 0.6); // 高度设置为屏幕的0.6 123 | dialogWindow.setAttributes(lp); 124 | setCanceledOnTouchOutside(false); 125 | setCancelable(true); 126 | } 127 | 128 | public void setClicklistener(OnClickListenerInterface clickListenerInterface) { 129 | this.mListener = clickListenerInterface; 130 | } 131 | 132 | private class OnWidgetClickListener implements View.OnClickListener { 133 | @Override 134 | public void onClick(View v) { 135 | 136 | int id = v.getId(); 137 | switch (id) { 138 | case R.id.tv_forget_pwd: 139 | startAnimation(); 140 | break; 141 | case R.id.btn_back: 142 | startAnimation(); 143 | break; 144 | } 145 | } 146 | } 147 | 148 | private void startAnimation() { 149 | //接口回调传递参数 150 | // mListener.doConfirm(); 151 | // centerX = mContainer.getWidth() / 2; 152 | // centerY = mContainer.getHeight() / 2; 153 | centerX = container.getWidth() / 2; 154 | centerY = container.getHeight() / 2; 155 | if (openAnimation == null) { 156 | initOpenAnim(); 157 | initCloseAnim(); 158 | } 159 | 160 | //用作判断当前点击事件发生时动画是否正在执行 161 | if (openAnimation.hasStarted() && !openAnimation.hasEnded()) { 162 | return; 163 | } 164 | if (closeAnimation.hasStarted() && !closeAnimation.hasEnded()) { 165 | return; 166 | } 167 | 168 | //判断动画执行 169 | if (isOpen) { 170 | // mContainer.startAnimation(openAnimation); 171 | container.startAnimation(openAnimation); 172 | 173 | } else { 174 | // mContainer.startAnimation(closeAnimation); 175 | container.startAnimation(closeAnimation); 176 | 177 | } 178 | isOpen = !isOpen; 179 | } 180 | 181 | /** 182 | * 卡牌文本介绍打开效果:注意旋转角度 183 | */ 184 | private void initOpenAnim() { 185 | //从0到90度,顺时针旋转视图,此时reverse参数为true,达到90度时动画结束时视图变得不可见, 186 | openAnimation = new Rotate3dAnimation(0, 90, centerX, centerY, depthZ, true); 187 | openAnimation.setDuration(duration); 188 | openAnimation.setFillAfter(true); 189 | openAnimation.setInterpolator(new AccelerateInterpolator()); 190 | openAnimation.setAnimationListener(new Animation.AnimationListener() { 191 | 192 | @Override 193 | public void onAnimationStart(Animation animation) { 194 | 195 | } 196 | 197 | @Override 198 | public void onAnimationRepeat(Animation animation) { 199 | 200 | } 201 | 202 | @Override 203 | public void onAnimationEnd(Animation animation) { 204 | llRegister.setVisibility(View.GONE); 205 | llContent.setVisibility(View.VISIBLE); 206 | //从270到360度,顺时针旋转视图,此时reverse参数为false,达到360度动画结束时视图变得可见 207 | Rotate3dAnimation rotateAnimation = new Rotate3dAnimation(270, 360, centerX, centerY, depthZ, false); 208 | rotateAnimation.setDuration(duration); 209 | rotateAnimation.setFillAfter(true); 210 | rotateAnimation.setInterpolator(new DecelerateInterpolator()); 211 | container.startAnimation(rotateAnimation); 212 | } 213 | }); 214 | } 215 | 216 | /** 217 | * 卡牌文本介绍关闭效果:旋转角度与打开时逆行即可 218 | */ 219 | private void initCloseAnim() { 220 | closeAnimation = new Rotate3dAnimation(360, 270, centerX, centerY, depthZ, true); 221 | closeAnimation.setDuration(duration); 222 | closeAnimation.setFillAfter(true); 223 | closeAnimation.setInterpolator(new AccelerateInterpolator()); 224 | closeAnimation.setAnimationListener(new Animation.AnimationListener() { 225 | 226 | @Override 227 | public void onAnimationStart(Animation animation) { 228 | 229 | } 230 | 231 | @Override 232 | public void onAnimationRepeat(Animation animation) { 233 | 234 | } 235 | 236 | @Override 237 | public void onAnimationEnd(Animation animation) { 238 | llRegister.setVisibility(View.VISIBLE); 239 | llContent.setVisibility(View.GONE); 240 | Rotate3dAnimation rotateAnimation = new Rotate3dAnimation(90, 0, centerX, centerY, depthZ, false); 241 | rotateAnimation.setDuration(duration); 242 | rotateAnimation.setFillAfter(true); 243 | rotateAnimation.setInterpolator(new DecelerateInterpolator()); 244 | container.startAnimation(rotateAnimation); 245 | } 246 | }); 247 | } 248 | } -------------------------------------------------------------------------------- /app/src/main/java/com/kevin/tech/dialogfliptest/Rotate3dAnimation.java: -------------------------------------------------------------------------------- 1 | package com.kevin.tech.dialogfliptest; 2 | 3 | import android.graphics.Camera; 4 | import android.graphics.Matrix; 5 | import android.util.Log; 6 | import android.view.animation.Animation; 7 | import android.view.animation.Transformation; 8 | 9 | /** 10 | * An animation that rotates the view on the Y axis between two specified angles. 11 | * This animation also adds a translation on the Z axis (depth) to improve the effect. 12 | */ 13 | public class Rotate3dAnimation extends Animation { 14 | private final float mFromDegrees; 15 | private final float mToDegrees; 16 | private final float mCenterX; 17 | private final float mCenterY; 18 | private final float mDepthZ; 19 | private final boolean mReverse; 20 | private Camera mCamera; 21 | 22 | /** 23 | * Creates a new 3D rotation on the Y axis. The rotation is defined by its 24 | * start angle and its end angle. Both angles are in degrees. The rotation 25 | * is performed around a center point on the 2D space, definied by a pair 26 | * of X and Y coordinates, called centerX and centerY. When the animation 27 | * starts, a translation on the Z axis (depth) is performed. The length 28 | * of the translation can be specified, as well as whether the translation 29 | * should be reversed in time. 30 | * 31 | * @param fromDegrees the start angle of the 3D rotation //起始角度 32 | * @param toDegrees the end angle of the 3D rotation //结束角度 33 | * @param centerX the X center of the 3D rotation //x中轴线 34 | * @param centerY the Y center of the 3D rotation //y中轴线 35 | * @param reverse true if the translation should be reversed, false otherwise//是否反转 36 | */ 37 | public Rotate3dAnimation(float fromDegrees, float toDegrees, 38 | float centerX, float centerY, float depthZ, boolean reverse) { 39 | mFromDegrees = fromDegrees; 40 | mToDegrees = toDegrees; 41 | mCenterX = centerX; 42 | mCenterY = centerY; 43 | mDepthZ = depthZ;//Z轴移动的距离,这个来影响视觉效果,可以解决flip animation那个给人看似放大的效果 44 | mReverse = reverse; 45 | } 46 | 47 | @Override 48 | public void initialize(int width, int height, int parentWidth, int parentHeight) { 49 | super.initialize(width, height, parentWidth, parentHeight); 50 | mCamera = new Camera(); 51 | } 52 | 53 | @Override 54 | protected void applyTransformation(float interpolatedTime, Transformation t) { 55 | final float fromDegrees = mFromDegrees; 56 | float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime); 57 | 58 | final float centerX = mCenterX; 59 | final float centerY = mCenterY; 60 | final Camera camera = mCamera; 61 | 62 | final Matrix matrix = t.getMatrix(); 63 | 64 | Log.i("interpolatedTime", interpolatedTime+""); 65 | camera.save(); 66 | if (mReverse) { 67 | camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime); 68 | } else { 69 | camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime)); 70 | } 71 | camera.rotateY(degrees); 72 | camera.getMatrix(matrix); 73 | camera.restore(); 74 | 75 | matrix.preTranslate(-centerX, -centerY); 76 | matrix.postTranslate(centerX, centerY); 77 | } 78 | } -------------------------------------------------------------------------------- /app/src/main/res/animator/card_flip_left_in.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 36 | 37 | 38 | 39 | 44 | 45 | 46 | 52 | 53 | 54 | 60 | 61 | -------------------------------------------------------------------------------- /app/src/main/res/animator/card_flip_left_out.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 35 | 36 | 37 | 38 | 44 | 45 | 46 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/animator/card_flip_right_in.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 36 | 37 | 38 | 39 | 44 | 45 | 46 | 52 | 53 | 54 | 60 | 61 | -------------------------------------------------------------------------------- /app/src/main/res/animator/card_flip_right_out.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 35 | 36 | 37 | 38 | 44 | 45 | 46 | 52 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/bg_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/bg_shape_update_version_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/student9128/DialogFlipTest/f7dd0098fe08e41c8daa724e6c089492dbe350ae/app/src/main/res/drawable-xhdpi/ic_avatar.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_button_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/bg_button_register.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_d.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 |