├── README.md ├── app ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── gplibs │ │ └── magic_surface_view_sample │ │ ├── App.java │ │ ├── LightSampleActivity.java │ │ ├── MacWindowAnimActivity.java │ │ ├── MainActivity.java │ │ ├── MatrixAnimSampleActivity.java │ │ ├── MultiScrapAnimActivity.java │ │ ├── MultiSlideAnimActivity.java │ │ ├── VortexAnimActivity.java │ │ ├── WaveAnimActivity.java │ │ ├── common │ │ ├── AnimHelper.java │ │ ├── Direction.java │ │ ├── FloatValueAnimator.java │ │ ├── MagicActivity.java │ │ └── RandomNumber.java │ │ ├── launch │ │ ├── LaunchActivity.java │ │ ├── LaunchBackgroundUpdater.java │ │ ├── LaunchButtonMatrixUpdater.java │ │ ├── LaunchButtonModelUpdater.java │ │ ├── LaunchSceneUpdater.java │ │ └── LaunchTextModelUpdater.java │ │ └── updater │ │ ├── MacWindowAnimUpdater.java │ │ ├── MultiScrapUpdater.java │ │ ├── MultiSlideUpdater.java │ │ ├── VortexAnimUpdater.java │ │ └── WaveAnimUpdater.java │ └── res │ ├── drawable │ ├── btn_bg.xml │ ├── dark_bg.xml │ └── surface_bg.xml │ ├── layout │ ├── activity_launch.xml │ ├── activity_light_sample.xml │ ├── activity_mac_window_anim.xml │ ├── activity_magic.xml │ ├── activity_main.xml │ ├── activity_matrix_anim_sample.xml │ ├── activity_multi_fold_anim.xml │ ├── activity_multi_scrap_anim.xml │ ├── activity_multi_slide_anim.xml │ ├── activity_vortex_anim.xml │ ├── activity_wave_anim.xml │ └── item_activity.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-v19 │ └── styles.xml │ ├── values-v21 │ └── styles.xml │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── gradle.properties ├── gradlew ├── gradlew.bat ├── local.properties └── settings.gradle /README.md: -------------------------------------------------------------------------------- 1 | # android-magic-surface-view-sample 2 | 3 | 这是基于MagicSurfaceView库的示例项目 ([下载此示例项目apk](https://github.com/gplibs/resources/raw/master/android/magic-surface-view/apk/magic-surface-view-sample-release.apk))。
4 | MagicSurfaceView库地址:
5 | 6 | 此项目只有几个简陋的示例,只为抛砖引玉。 7 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | Properties properties = new Properties() 4 | properties.load(project.rootProject.file('local.properties').newDataInputStream()) 5 | 6 | android { 7 | compileSdkVersion 25 8 | buildToolsVersion "25.0.2" 9 | 10 | defaultConfig { 11 | applicationId "com.gplibs.magic_surface_view_sample" 12 | minSdkVersion 11 13 | targetSdkVersion 25 14 | versionCode 111 15 | versionName "1.1.1" 16 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 17 | } 18 | buildTypes { 19 | release { 20 | minifyEnabled false 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | } 24 | } 25 | 26 | dependencies { 27 | compile fileTree(dir: 'libs', include: ['*.jar']) 28 | compile 'com.gplibs:magic-surface-view:1.1.1' 29 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 30 | exclude group: 'com.android.support', module: 'support-annotations' 31 | }) 32 | compile 'com.android.support:appcompat-v7:25.3.1' 33 | compile 'com.android.support.constraint:constraint-layout:1.0.1' 34 | testCompile 'junit:junit:4.12' 35 | } 36 | -------------------------------------------------------------------------------- /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 /Users/guoping/Software/dev/IDEA/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/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/App.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample; 2 | 3 | import android.app.Application; 4 | 5 | public class App extends Application { 6 | 7 | @Override 8 | public void onCreate() { 9 | super.onCreate(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/LightSampleActivity.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.IdRes; 5 | import android.view.MotionEvent; 6 | import android.view.View; 7 | import android.widget.CompoundButton; 8 | import android.widget.RadioGroup; 9 | import android.widget.SeekBar; 10 | import android.widget.TextView; 11 | import android.widget.ToggleButton; 12 | 13 | import com.gplibs.magic_surface_view_sample.common.MagicActivity; 14 | import com.gplibs.magicsurfaceview.MagicScene; 15 | import com.gplibs.magicsurfaceview.MagicSceneBuilder; 16 | import com.gplibs.magicsurfaceview.MagicSurface; 17 | import com.gplibs.magicsurfaceview.MagicSurfaceView; 18 | import com.gplibs.magicsurfaceview.PointLight; 19 | import com.gplibs.magicsurfaceview.ReusableVec; 20 | import com.gplibs.magicsurfaceview.Vec; 21 | import com.gplibs.magicsurfaceview.VecPool; 22 | 23 | public class LightSampleActivity extends MagicActivity { 24 | 25 | private View mViewContainer; 26 | private MagicSurfaceView mSurfaceView; 27 | private TextView mTvContent; 28 | 29 | private TextView mTvPos; 30 | private TextView mTvShininess; 31 | private SeekBar mSbZ; 32 | private SeekBar mSbShininess; 33 | private RadioGroup mRadioGroup; 34 | private ToggleButton mToggleButton; 35 | 36 | private MagicScene mScene; // 场景对象 37 | private MagicSurface mSurface; // 渲染对象 38 | private PointLight mPointLight; // 点光源对象 39 | private Vec mLightPos = new Vec(3); // 光源位置 40 | 41 | private boolean mIsFirstResume = true; 42 | private float mX, mY; 43 | 44 | @Override 45 | protected void onCreate(Bundle savedInstanceState) { 46 | super.onCreate(savedInstanceState); 47 | setContentView(R.layout.activity_light_sample); 48 | setTitle("LightSample"); 49 | 50 | initViews(); 51 | } 52 | 53 | private void initViews() { 54 | mSurfaceView = (MagicSurfaceView) findViewById(R.id.surface_view); 55 | mTvContent = (TextView) findViewById(R.id.tv_content); 56 | 57 | mViewContainer = findViewById(R.id.view_container); 58 | mViewContainer.setOnTouchListener(new View.OnTouchListener() { 59 | @Override 60 | public boolean onTouch(View v, MotionEvent event) { 61 | moveLight(event.getX(), event.getY()); 62 | return true; 63 | } 64 | }); 65 | 66 | mTvPos = (TextView) findViewById(R.id.tv_pos); 67 | mTvShininess = (TextView) findViewById(R.id.tv_shininess); 68 | 69 | mSbZ = (SeekBar) findViewById(R.id.sb_z); 70 | mSbShininess = (SeekBar) findViewById(R.id.sb_shininess); 71 | SeekBar.OnSeekBarChangeListener onSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() { 72 | @Override 73 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 74 | if (seekBar == mSbZ) { 75 | moveLightZ(0.2f + 0.8f * progress / 100.f); 76 | mTvPos.setText("z:" + mLightPos.z()); 77 | } else { 78 | mSurface.setShininess(progress); 79 | mTvShininess.setText("shininess:" + progress); 80 | } 81 | } 82 | 83 | @Override 84 | public void onStartTrackingTouch(SeekBar seekBar) { 85 | 86 | } 87 | 88 | @Override 89 | public void onStopTrackingTouch(SeekBar seekBar) { 90 | 91 | } 92 | }; 93 | mSbZ.setOnSeekBarChangeListener(onSeekBarChangeListener); 94 | mSbShininess.setOnSeekBarChangeListener(onSeekBarChangeListener); 95 | 96 | mRadioGroup = (RadioGroup) findViewById(R.id.radio_group); 97 | mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { 98 | @Override 99 | public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) { 100 | int color; 101 | switch (checkedId) { 102 | case R.id.rb_red: 103 | color = 0XFF800000; 104 | break; 105 | case R.id.rb_green: 106 | color = 0XFF008000; 107 | break; 108 | case R.id.rb_blue: 109 | color = 0XFF000080; 110 | break; 111 | default: 112 | color = 0XFF808080; 113 | break; 114 | } 115 | updateColor(color); 116 | } 117 | }); 118 | 119 | mToggleButton = (ToggleButton) findViewById(R.id.toggle_button); 120 | mToggleButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 121 | @Override 122 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 123 | mPointLight.setEnable(isChecked); 124 | } 125 | }); 126 | } 127 | 128 | private void render() { 129 | // 光源默认位置 (0.f, 0.f, 0.2f): MagicSurfaceView 正中, Z轴向屏幕外0.2 130 | mLightPos.setXYZ(mX, mY, 0.2f + 0.8f * mSbZ.getProgress() / 100.f); 131 | mPointLight = new PointLight(0XFF808080, mLightPos); 132 | mSurface = new MagicSurface(mTvContent); 133 | mSurface.setShininess(mSbShininess.getProgress()); 134 | mSurface.setGrid(50, 50); 135 | mScene = new MagicSceneBuilder(mSurfaceView) 136 | .addSurfaces(mSurface) 137 | .ambientColor(0XFF333333) // 环境光,设置暗些灯光效果才明显 138 | .addLights(mPointLight) 139 | .build(); 140 | mSurfaceView.render(mScene); 141 | } 142 | 143 | public void moveLight(float x, float y) { 144 | ReusableVec sceneTopLeft = VecPool.get(3); 145 | mScene.getPosition(0, 0, sceneTopLeft); 146 | mX = sceneTopLeft.x() + mScene.getWidth() * x / mViewContainer.getWidth(); 147 | mY = sceneTopLeft.y() - mScene.getHeight() * y / mViewContainer.getHeight(); // 场景Y轴向上所以要减 148 | sceneTopLeft.free(); 149 | mLightPos.setXY(mX, mY); 150 | updatePosition(); 151 | } 152 | 153 | // 修改灯光位置Z坐标 154 | private void moveLightZ(float z) { 155 | mLightPos.z(z); 156 | updatePosition(); 157 | } 158 | 159 | // 修改灯光颜色 160 | private void updateColor(int color) { 161 | mPointLight.setColor(color); 162 | } 163 | 164 | // 修改灯光水平位置 165 | private void updatePosition() { 166 | mPointLight.setPosition(mLightPos); 167 | } 168 | 169 | @Override 170 | protected void onPageAnimEnd() { 171 | render(); 172 | } 173 | 174 | @Override 175 | protected void onPause() { 176 | super.onPause(); 177 | mSurfaceView.onPause(); 178 | } 179 | 180 | @Override 181 | protected void onResume() { 182 | super.onResume(); 183 | getWindow().getDecorView().post(new Runnable() { 184 | @Override 185 | public void run() { 186 | if (!mIsFirstResume) { 187 | render(); 188 | } else { 189 | mIsFirstResume = false; 190 | } 191 | mSurfaceView.onResume(); 192 | } 193 | }); 194 | } 195 | 196 | @Override 197 | protected void onDestroy() { 198 | super.onDestroy(); 199 | // 释放资源 200 | mSurfaceView.onDestroy(); 201 | } 202 | 203 | @Override 204 | public void onBackPressed() { 205 | mSurfaceView.setVisibility(View.INVISIBLE); 206 | mViewContainer.postDelayed(new Runnable() { 207 | @Override 208 | public void run() { 209 | LightSampleActivity.super.onBackPressed(); 210 | } 211 | }, 50); 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/MacWindowAnimActivity.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample; 2 | 3 | import android.os.Bundle; 4 | import android.view.Gravity; 5 | import android.view.MotionEvent; 6 | import android.view.View; 7 | import android.widget.Button; 8 | import android.widget.FrameLayout; 9 | import android.widget.TextView; 10 | 11 | import com.gplibs.magic_surface_view_sample.common.Direction; 12 | import com.gplibs.magic_surface_view_sample.common.MagicActivity; 13 | import com.gplibs.magic_surface_view_sample.updater.MacWindowAnimUpdater; 14 | import com.gplibs.magicsurfaceview.MagicScene; 15 | import com.gplibs.magicsurfaceview.MagicSceneBuilder; 16 | import com.gplibs.magicsurfaceview.MagicSurface; 17 | import com.gplibs.magicsurfaceview.MagicSurfaceView; 18 | import com.gplibs.magicsurfaceview.MagicUpdater; 19 | import com.gplibs.magicsurfaceview.MagicUpdaterListener; 20 | 21 | public class MacWindowAnimActivity extends MagicActivity implements View.OnTouchListener, View.OnClickListener { 22 | 23 | private MagicSurfaceView mSurfaceView; 24 | private TextView mTvContent; 25 | 26 | private Button mBtnLeft; 27 | private Button mBtnTop; 28 | private Button mBtnRight; 29 | private Button mBtnBottom; 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.activity_mac_window_anim); 35 | setTitle("MacWindowAnim"); 36 | 37 | mSurfaceView = (MagicSurfaceView) findViewById(R.id.surface_view); 38 | mTvContent = (TextView) findViewById(R.id.tv_content); 39 | 40 | mBtnLeft = (Button) findViewById(R.id.btn_left); 41 | mBtnTop = (Button) findViewById(R.id.btn_top); 42 | mBtnRight = (Button) findViewById(R.id.btn_right); 43 | mBtnBottom = (Button) findViewById(R.id.btn_bottom); 44 | 45 | mBtnLeft.setOnClickListener(this); 46 | mBtnTop.setOnClickListener(this); 47 | mBtnRight.setOnClickListener(this); 48 | mBtnBottom.setOnClickListener(this); 49 | 50 | findViewById(R.id.view_left_container).setOnTouchListener(this); 51 | findViewById(R.id.view_top_container).setOnTouchListener(this); 52 | findViewById(R.id.view_right_container).setOnTouchListener(this); 53 | findViewById(R.id.view_bottom_container).setOnTouchListener(this); 54 | } 55 | 56 | @Override 57 | public boolean onTouch(View v, MotionEvent event) { 58 | boolean isVertical = false; 59 | Button btn = null; 60 | switch (v.getId()) { 61 | case R.id.view_left_container: 62 | btn = mBtnLeft; 63 | break; 64 | case R.id.view_top_container: 65 | btn = mBtnTop; 66 | isVertical = true; 67 | break; 68 | case R.id.view_right_container: 69 | btn = mBtnRight; 70 | break; 71 | case R.id.view_bottom_container: 72 | btn = mBtnBottom; 73 | isVertical = true; 74 | break; 75 | } 76 | updateBtnPosition(btn, isVertical, isVertical ? event.getX() : event.getY()); 77 | return true; 78 | } 79 | 80 | @Override 81 | public void onClick(View v) { 82 | float center = 0.5f; 83 | int direction = Direction.BOTTOM; 84 | switch (v.getId()) { 85 | case R.id.btn_left: 86 | direction = Direction.LEFT; 87 | center = (v.getTop() + v.getHeight() / 2.f) / ((View)v.getParent()).getHeight(); 88 | break; 89 | case R.id.btn_right: 90 | direction = Direction.RIGHT; 91 | center = (v.getTop() + v.getHeight() / 2.f) / ((View)v.getParent()).getHeight(); 92 | break; 93 | case R.id.btn_top: 94 | direction = Direction.TOP; 95 | center = (v.getLeft() + v.getWidth() / 2.f) / ((View)v.getParent()).getWidth(); 96 | break; 97 | case R.id.btn_bottom: 98 | direction = Direction.BOTTOM; 99 | center = (v.getLeft() + v.getWidth() / 2.f) / ((View)v.getParent()).getWidth(); 100 | break; 101 | } 102 | if (isHide()) { 103 | show(center, direction); 104 | } else { 105 | hide(center, direction); 106 | } 107 | } 108 | 109 | private void hide(float center, int direction) { 110 | MacWindowAnimUpdater updater = new MacWindowAnimUpdater(true, direction, center, false); 111 | updater.addListener(new MagicUpdaterListener() { 112 | @Override 113 | public void onStart() { 114 | mTvContent.setVisibility(View.INVISIBLE); 115 | } 116 | 117 | @Override 118 | public void onStop() { 119 | mSurfaceView.setVisibility(View.GONE); 120 | // 释放资源 121 | mSurfaceView.release(); 122 | } 123 | }); 124 | MagicSurface s = new MagicSurface(mTvContent) 125 | .setGrid(getRowLineCount(direction), getColLineCount(direction)) 126 | .setModelUpdater(updater); 127 | MagicScene scene = new MagicSceneBuilder(mSurfaceView) 128 | .addSurfaces(s) 129 | .build(); 130 | mSurfaceView.setVisibility(View.VISIBLE); 131 | mSurfaceView.render(scene); 132 | } 133 | 134 | private void show(float center, int direction) { 135 | MacWindowAnimUpdater updater = new MacWindowAnimUpdater(false, direction, center, false); 136 | updater.addListener(new MagicUpdaterListener() { 137 | @Override 138 | public void onStart() { 139 | mTvContent.setVisibility(View.INVISIBLE); 140 | } 141 | @Override 142 | public void onStop() { 143 | mTvContent.setVisibility(View.VISIBLE); 144 | mSurfaceView.setVisibility(View.GONE); 145 | // 释放资源 146 | mSurfaceView.release(); 147 | } 148 | }); 149 | MagicSurface s = new MagicSurface(mTvContent) 150 | .setGrid(getRowLineCount(direction), getColLineCount(direction)) 151 | .setModelUpdater(updater); 152 | mSurfaceView.setVisibility(View.VISIBLE); 153 | mSurfaceView.render(s); 154 | } 155 | 156 | private int getRowLineCount(int direction) { 157 | return Direction.isVertical(direction) ? 20 : 8; 158 | } 159 | 160 | private int getColLineCount(int direction) { 161 | return Direction.isVertical(direction) ? 8 : 20; 162 | } 163 | 164 | private boolean isHide() { 165 | return mTvContent.getVisibility() != View.VISIBLE; 166 | } 167 | 168 | private void updateBtnPosition(Button btn, boolean isVertical, float value) { 169 | if (value < 0) { 170 | value = 0; 171 | } 172 | View parent = (View) btn.getParent(); 173 | float max = isVertical ? parent.getWidth() : parent.getHeight(); 174 | if (value > max) { 175 | value = max; 176 | } 177 | FrameLayout.LayoutParams p = (FrameLayout.LayoutParams) btn.getLayoutParams(); 178 | if (isVertical) { 179 | p.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL; 180 | p.leftMargin = (int) (value - btn.getWidth() / 2.0); 181 | } else { 182 | p.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; 183 | p.topMargin = (int) (value - btn.getHeight() / 2.0); 184 | } 185 | btn.setLayoutParams(p); 186 | } 187 | 188 | 189 | // 设置Page转场动画 190 | @Override 191 | protected MagicUpdater getPageUpdater(boolean isHide) { 192 | return new MacWindowAnimUpdater(isHide, Direction.RIGHT, 0.184f, false); 193 | } 194 | 195 | } 196 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | import android.os.Bundle; 8 | import android.support.annotation.LayoutRes; 9 | import android.support.annotation.NonNull; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.AdapterView; 13 | import android.widget.ArrayAdapter; 14 | import android.widget.Button; 15 | import android.widget.ListView; 16 | 17 | import com.gplibs.magic_surface_view_sample.common.Direction; 18 | import com.gplibs.magic_surface_view_sample.common.MagicActivity; 19 | import com.gplibs.magic_surface_view_sample.updater.VortexAnimUpdater; 20 | import com.gplibs.magic_surface_view_sample.updater.WaveAnimUpdater; 21 | import com.gplibs.magicsurfaceview.MagicSurfaceModelUpdater; 22 | 23 | import java.util.HashMap; 24 | import java.util.LinkedHashMap; 25 | import java.util.Map; 26 | import java.util.TreeMap; 27 | 28 | public class MainActivity extends MagicActivity { 29 | 30 | private Map.Entry>[] mArray; 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.activity_main); 36 | setTitle("MagicSurfaceViewSample"); 37 | initData(); 38 | initView(); 39 | } 40 | 41 | private void initData() { 42 | Map> items = new LinkedHashMap<>(); 43 | items.put("ScrapAnim", MultiScrapAnimActivity.class); 44 | items.put("MultiSlideAnim", MultiSlideAnimActivity.class); 45 | items.put("MacWindowAnim", MacWindowAnimActivity.class); 46 | items.put("WaveAnim", WaveAnimActivity.class); 47 | items.put("VortexAnim", VortexAnimActivity.class); 48 | items.put("MatrixAnimSample", MatrixAnimSampleActivity.class); 49 | items.put("LightSample", LightSampleActivity.class); 50 | mArray = new Map.Entry[items.size()]; 51 | items.entrySet().toArray(mArray); 52 | } 53 | 54 | private void initView() { 55 | ((ListView) findViewById(R.id.list_view)).setAdapter(new Adapter(this, R.layout.item_activity)); 56 | findViewById(R.id.tv_address).setOnClickListener(new View.OnClickListener() { 57 | @Override 58 | public void onClick(View v) { 59 | openGitHub(); 60 | } 61 | }); 62 | } 63 | 64 | @Override 65 | protected MagicSurfaceModelUpdater getPageUpdater(boolean isHide) { 66 | if (isHide) { 67 | return new VortexAnimUpdater(true); 68 | } else { 69 | return new WaveAnimUpdater(false, Direction.RIGHT, false); 70 | } 71 | } 72 | 73 | @Override 74 | protected int pageAnimRowCount() { 75 | return 60; 76 | } 77 | 78 | @Override 79 | protected int pageAnimColCount() { 80 | return 60; 81 | } 82 | 83 | private void start(Class activityClass) { 84 | startActivity(new Intent(this, activityClass)); 85 | } 86 | 87 | private void openGitHub() { 88 | Intent intent = new Intent(); 89 | intent.setAction("android.intent.action.VIEW"); 90 | intent.setData(Uri.parse("http://github.com/gplibs")); 91 | startActivity(intent); 92 | } 93 | 94 | class Adapter extends ArrayAdapter>> { 95 | private int mResourceId; 96 | 97 | public Adapter(@NonNull Context context,@LayoutRes int resource) { 98 | super(context, resource); 99 | this.mResourceId = resource; 100 | } 101 | 102 | @Override 103 | public int getCount() { 104 | return mArray.length; 105 | } 106 | 107 | @Override 108 | public View getView(int position, View convertView, ViewGroup parent) { 109 | if (convertView == null){ 110 | convertView = getLayoutInflater().inflate(mResourceId, null); 111 | } 112 | final Map.Entry> entry = mArray[position]; 113 | ((Button) convertView).setText(entry.getKey()); 114 | convertView.setOnClickListener(new View.OnClickListener() { 115 | @Override 116 | public void onClick(View v) { 117 | start(entry.getValue()); 118 | } 119 | }); 120 | return convertView; 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/MatrixAnimSampleActivity.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample; 2 | 3 | import android.os.Bundle; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.gplibs.magic_surface_view_sample.common.FloatValueAnimator; 8 | import com.gplibs.magic_surface_view_sample.common.MagicActivity; 9 | import com.gplibs.magicsurfaceview.MagicScene; 10 | import com.gplibs.magicsurfaceview.MagicSurface; 11 | import com.gplibs.magicsurfaceview.MagicSurfaceMatrixUpdater; 12 | import com.gplibs.magicsurfaceview.MagicSurfaceView; 13 | import com.gplibs.magicsurfaceview.MagicUpdaterListener; 14 | import com.gplibs.magicsurfaceview.Vec; 15 | 16 | /** 17 | * 矩形变换示例 18 | */ 19 | public class MatrixAnimSampleActivity extends MagicActivity { 20 | 21 | private MagicSurfaceView mSurfaceView; 22 | private TextView mTvContent; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_matrix_anim_sample); 28 | setTitle("MatrixAnimSample"); 29 | 30 | mSurfaceView = (MagicSurfaceView) findViewById(R.id.surface_view); 31 | mTvContent = (TextView) findViewById(R.id.tv_content); 32 | findViewById(R.id.view_container).setOnClickListener(new View.OnClickListener() { 33 | @Override 34 | public void onClick(View v) { 35 | start(); 36 | } 37 | }); 38 | } 39 | 40 | @Override 41 | protected void onDestroy() { 42 | super.onDestroy(); 43 | mSurfaceView.onDestroy(); 44 | } 45 | 46 | private void start() { 47 | MatrixUpdater updater = new MatrixUpdater(); 48 | updater.addListener(new MagicUpdaterListener() { 49 | @Override 50 | public void onStart() { 51 | mTvContent.setVisibility(View.INVISIBLE); 52 | } 53 | @Override 54 | public void onStop() { 55 | mTvContent.setVisibility(View.VISIBLE); 56 | mSurfaceView.setVisibility(View.GONE); 57 | // 释放资源 58 | mSurfaceView.release(); 59 | } 60 | }); 61 | MagicSurface s = new MagicSurface(mTvContent) 62 | .setGrid(2, 2) 63 | .drawGrid(false) 64 | .setMatrixUpdater(updater); 65 | mSurfaceView.setVisibility(View.VISIBLE); 66 | mSurfaceView.render(s); 67 | } 68 | 69 | /** 70 | * 矩阵变换示例 71 | */ 72 | private static class MatrixUpdater extends MagicSurfaceMatrixUpdater { 73 | 74 | private FloatValueAnimator mAnimator; 75 | private float mAnimValue = 0; 76 | 77 | // y轴 78 | private Vec mAxis = new Vec(0, 1, 0); 79 | // 缩放量 80 | private Vec mScale = new Vec(1, 1, 1); 81 | // 位移量 82 | private Vec mTranslate = new Vec(0, 0, 0); 83 | 84 | public MatrixUpdater() { 85 | mAnimator = new FloatValueAnimator(1000); 86 | mAnimator.addListener(new FloatValueAnimator.FloatValueAnimatorListener() { 87 | @Override 88 | public void onAnimationUpdate(float value) { 89 | mAnimValue = value; 90 | // 通知框架,数据改变,可以调用 update 方法进行更新 91 | notifyChanged(); 92 | } 93 | 94 | @Override 95 | public void onStop() { 96 | // 通知框架,数据改变,可以调用 update 方法进行更新 97 | notifyChanged(); 98 | } 99 | }); 100 | } 101 | 102 | // 在绘制第一帧之前调用 (可以在此方法里进行一些初始化操作) 103 | @Override 104 | protected void willStart(MagicSurface surface) { 105 | mAnimValue = 0; 106 | mAnimator.reset(); 107 | } 108 | 109 | // 在开始绘制后调用(绘制第一帧后调用,一般动画可以在此开始) 110 | @Override 111 | protected void didStart(MagicSurface surface) { 112 | mAnimator.start(false); 113 | } 114 | 115 | // 当调用Updater 的 stop() 方法之后,真正停止后会回调此方法 116 | @Override 117 | protected void didStop(MagicSurface surface) { 118 | mAnimator.stop(); 119 | } 120 | 121 | /** 122 | * 在此方法里进行矩阵变换 123 | * 124 | * @param offset 为 model 相对场景中心的坐标偏移量, 如果不进行 offset 位移, model 就会显示在场景中心; 125 | * 126 | * 当使用 View 构造 MagicSurface 时, 127 | * View中心位置 相对 MagicSurfaceView中心位置 的坐标偏移量 在场景坐标系中的表现就是 offset。 128 | * 129 | * @param matrix model 矩阵 130 | */ 131 | @Override 132 | protected void updateMatrix(MagicSurface surface, Vec offset, float[] matrix) { 133 | 134 | // 旋转角度 135 | float angle = 360.f * 2 * mAnimValue; 136 | float scale; 137 | float translateY; 138 | 139 | if (mAnimValue < 0.5f) { // 前一半时间 140 | // 从 1倍 缩小到 0.5倍 141 | scale = 0.5f + 0.5f * (0.5f - mAnimValue) / 0.5f; 142 | // 从 offset 处移到其y轴上方 0.8 位置处 143 | translateY = 0.8f * mAnimValue / 0.5f; 144 | } else { // 后一半时间 145 | // 从 0.5倍 放大到 1倍 146 | scale = 0.5f + 0.5f * (mAnimValue - 0.5f) / 0.5f; 147 | // 从 offset 上方 0.8 位置移到 offset 处 148 | translateY = 0.8f * (1 - mAnimValue) / 0.5f; 149 | } 150 | 151 | mScale.setXYZ(scale, scale, 1); 152 | 153 | mTranslate.copy(offset); 154 | mTranslate.add(0, translateY, 0); 155 | 156 | // 重置matrix 157 | reset(matrix); 158 | // 缩放 159 | scale(matrix, mScale); 160 | // 位移 161 | translate(matrix, mTranslate); 162 | // 绕 mAxis 旋转 angle 度。 163 | rotate(matrix, mAxis, angle); 164 | 165 | if (mAnimator.isStopped()) { 166 | stop(); 167 | } 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/MultiScrapAnimActivity.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample; 2 | 3 | import android.os.Bundle; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.gplibs.magic_surface_view_sample.common.Direction; 8 | import com.gplibs.magic_surface_view_sample.common.MagicActivity; 9 | import com.gplibs.magic_surface_view_sample.updater.MultiScrapUpdater; 10 | import com.gplibs.magicsurfaceview.MagicMultiSurface; 11 | import com.gplibs.magicsurfaceview.MagicMultiSurfaceUpdater; 12 | import com.gplibs.magicsurfaceview.MagicSurfaceView; 13 | import com.gplibs.magicsurfaceview.MagicUpdater; 14 | import com.gplibs.magicsurfaceview.MagicUpdaterListener; 15 | 16 | public class MultiScrapAnimActivity extends MagicActivity { 17 | 18 | private MagicSurfaceView mSurfaceView; 19 | private TextView mTvTest; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_multi_scrap_anim); 25 | setTitle("ScrapAnim"); 26 | mSurfaceView = (MagicSurfaceView) findViewById(R.id.magic_surface_view); 27 | mTvTest = (TextView) findViewById(R.id.tv_test); 28 | 29 | findViewById(R.id.view_container).setOnClickListener(new View.OnClickListener() { 30 | @Override 31 | public void onClick(View v) { 32 | if (mTvTest.getVisibility() == View.VISIBLE) { 33 | hide(); 34 | } else { 35 | show(); 36 | } 37 | } 38 | }); 39 | } 40 | 41 | @Override 42 | protected void onDestroy() { 43 | super.onDestroy(); 44 | mSurfaceView.onDestroy(); 45 | } 46 | 47 | private void show() { 48 | MultiScrapUpdater mMultiUpdater = new MultiScrapUpdater(false, Direction.RIGHT); 49 | mMultiUpdater.addListener(new MagicUpdaterListener() { 50 | @Override 51 | public void onStart() { 52 | mTvTest.setVisibility(View.INVISIBLE); 53 | } 54 | 55 | @Override 56 | public void onStop() { 57 | mTvTest.setVisibility(View.VISIBLE); 58 | mSurfaceView.setVisibility(View.GONE); 59 | mSurfaceView.release(); 60 | } 61 | }); 62 | mSurfaceView.render(new MagicMultiSurface(mTvTest, 20, 10).setUpdater(mMultiUpdater)); 63 | } 64 | 65 | private void hide() { 66 | MultiScrapUpdater mMultiUpdater = new MultiScrapUpdater(true, Direction.RIGHT); 67 | mMultiUpdater.addListener(new MagicUpdaterListener() { 68 | @Override 69 | public void onStart() { 70 | mTvTest.setVisibility(View.INVISIBLE); 71 | } 72 | 73 | @Override 74 | public void onStop() { 75 | mTvTest.setVisibility(View.INVISIBLE); 76 | mSurfaceView.setVisibility(View.GONE); 77 | mSurfaceView.release(); 78 | } 79 | }); 80 | mSurfaceView.render(new MagicMultiSurface(mTvTest, 20, 10).setUpdater(mMultiUpdater)); 81 | } 82 | 83 | // 返回null禁用 单Surface转场动画 84 | @Override 85 | protected MagicUpdater getPageUpdater(boolean isHide) { 86 | return null; 87 | } 88 | 89 | // 启用多Surface转场动画 90 | @Override 91 | protected MagicMultiSurfaceUpdater getPageMultiUpdater(boolean isHide) { 92 | return new MultiScrapUpdater(isHide, Direction.BOTTOM); 93 | } 94 | 95 | // 纵向surface数量 96 | @Override 97 | protected int pageAnimRowCount() { 98 | return 20; 99 | } 100 | 101 | // 横向surface数量 102 | @Override 103 | protected int pageAnimColCount() { 104 | return 10; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/MultiSlideAnimActivity.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample; 2 | 3 | import android.os.Bundle; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.gplibs.magic_surface_view_sample.common.Direction; 8 | import com.gplibs.magic_surface_view_sample.common.MagicActivity; 9 | import com.gplibs.magic_surface_view_sample.updater.MultiSlideUpdater; 10 | import com.gplibs.magicsurfaceview.MagicMultiSurface; 11 | import com.gplibs.magicsurfaceview.MagicMultiSurfaceUpdater; 12 | import com.gplibs.magicsurfaceview.MagicSurfaceView; 13 | import com.gplibs.magicsurfaceview.MagicUpdater; 14 | import com.gplibs.magicsurfaceview.MagicUpdaterListener; 15 | 16 | public class MultiSlideAnimActivity extends MagicActivity { 17 | 18 | private MagicSurfaceView mSurfaceView; 19 | private TextView mTvTest; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_multi_slide_anim); 25 | setTitle("MultiSlideAnim"); 26 | 27 | mSurfaceView = (MagicSurfaceView) findViewById(R.id.magic_surface_view); 28 | mTvTest = (TextView) findViewById(R.id.tv_test); 29 | findViewById(R.id.view_container).setOnClickListener(new View.OnClickListener() { 30 | @Override 31 | public void onClick(View v) { 32 | if (mTvTest.getVisibility() == View.VISIBLE) { 33 | hide(); 34 | } else { 35 | show(); 36 | } 37 | } 38 | }); 39 | } 40 | 41 | @Override 42 | protected void onDestroy() { 43 | super.onDestroy(); 44 | mSurfaceView.onDestroy(); 45 | } 46 | 47 | private void show() { 48 | MultiSlideUpdater updater = new MultiSlideUpdater(false, Direction.BOTTOM); 49 | updater.addListener(new MagicUpdaterListener() { 50 | @Override 51 | public void onStart() { 52 | mTvTest.setVisibility(View.INVISIBLE); 53 | } 54 | 55 | @Override 56 | public void onStop() { 57 | mSurfaceView.setVisibility(View.GONE); 58 | mTvTest.setVisibility(View.VISIBLE); 59 | mSurfaceView.release(); 60 | } 61 | }); 62 | mSurfaceView.render(new MagicMultiSurface(mTvTest, 150, 1).setUpdater(updater)); 63 | } 64 | 65 | private void hide() { 66 | MultiSlideUpdater updater = new MultiSlideUpdater(true, Direction.BOTTOM); 67 | updater.addListener(new MagicUpdaterListener() { 68 | @Override 69 | public void onStart() { 70 | mTvTest.setVisibility(View.INVISIBLE); 71 | } 72 | 73 | @Override 74 | public void onStop() { 75 | mSurfaceView.setVisibility(View.GONE); 76 | mTvTest.setVisibility(View.INVISIBLE); 77 | mSurfaceView.release(); 78 | } 79 | }); 80 | mSurfaceView.render(new MagicMultiSurface(mTvTest, 150, 1).setUpdater(updater)); 81 | } 82 | 83 | // 返回null禁用 单Surface转场动画 84 | @Override 85 | protected MagicUpdater getPageUpdater(boolean isHide) { 86 | return null; 87 | } 88 | 89 | // 启用多Surface转场动画 90 | @Override 91 | protected MagicMultiSurfaceUpdater getPageMultiUpdater(boolean isHide) { 92 | return new MultiSlideUpdater(isHide, Direction.TOP); 93 | } 94 | 95 | // 纵向surface数量 96 | @Override 97 | protected int pageAnimRowCount() { 98 | return 150; 99 | } 100 | 101 | // 横向surface数量 102 | @Override 103 | protected int pageAnimColCount() { 104 | return 1; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/VortexAnimActivity.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample; 2 | 3 | import android.os.Bundle; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.gplibs.magic_surface_view_sample.common.Direction; 8 | import com.gplibs.magic_surface_view_sample.common.MagicActivity; 9 | import com.gplibs.magic_surface_view_sample.updater.MacWindowAnimUpdater; 10 | import com.gplibs.magic_surface_view_sample.updater.VortexAnimUpdater; 11 | import com.gplibs.magicsurfaceview.MagicScene; 12 | import com.gplibs.magicsurfaceview.MagicSurface; 13 | import com.gplibs.magicsurfaceview.MagicUpdater; 14 | import com.gplibs.magicsurfaceview.MagicUpdaterListener; 15 | import com.gplibs.magicsurfaceview.MagicSurfaceView; 16 | 17 | public class VortexAnimActivity extends MagicActivity { 18 | 19 | private MagicSurfaceView mSurfaceView; 20 | private TextView mTvContent; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_vortex_anim); 26 | setTitle("VortexAnim"); 27 | 28 | mSurfaceView = (MagicSurfaceView) findViewById(R.id.surface_view); 29 | mTvContent = (TextView) findViewById(R.id.tv_content); 30 | findViewById(R.id.view_container).setOnClickListener(new View.OnClickListener() { 31 | @Override 32 | public void onClick(View v) { 33 | if (mTvContent.getVisibility() == View.VISIBLE) { 34 | hide(); 35 | } else { 36 | show(); 37 | } 38 | } 39 | }); 40 | } 41 | 42 | @Override 43 | protected void onDestroy() { 44 | super.onDestroy(); 45 | mSurfaceView.onDestroy(); 46 | } 47 | 48 | private void show() { 49 | VortexAnimUpdater updater = new VortexAnimUpdater(false); 50 | updater.addListener(new MagicUpdaterListener() { 51 | @Override 52 | public void onStart() { 53 | mTvContent.setVisibility(View.INVISIBLE); 54 | } 55 | @Override 56 | public void onStop() { 57 | mTvContent.setVisibility(View.VISIBLE); 58 | mSurfaceView.setVisibility(View.GONE); 59 | // 释放资源 60 | mSurfaceView.release(); 61 | } 62 | }); 63 | MagicSurface s = new MagicSurface(mTvContent) 64 | .setGrid(60, 60) 65 | .drawGrid(false) 66 | .setModelUpdater(updater); 67 | mSurfaceView.setVisibility(View.VISIBLE); 68 | mSurfaceView.render(s); 69 | } 70 | 71 | private void hide() { 72 | VortexAnimUpdater updater = new VortexAnimUpdater(true); 73 | updater.addListener(new MagicUpdaterListener() { 74 | @Override 75 | public void onStart() { 76 | mTvContent.setVisibility(View.INVISIBLE); 77 | } 78 | @Override 79 | public void onStop() { 80 | mSurfaceView.setVisibility(View.GONE); 81 | // 释放场景资源 82 | mSurfaceView.release(); 83 | } 84 | }); 85 | MagicSurface s = new MagicSurface(mTvContent) 86 | .setGrid(60, 60) 87 | .drawGrid(false) 88 | .setModelUpdater(updater); 89 | mSurfaceView.setVisibility(View.VISIBLE); 90 | mSurfaceView.render(s); 91 | } 92 | 93 | // 设置Page转场动画 94 | @Override 95 | protected MagicUpdater getPageUpdater(boolean isHide) { 96 | return new VortexAnimUpdater(isHide); 97 | } 98 | 99 | @Override 100 | protected int pageAnimRowCount() { 101 | return 60; 102 | } 103 | 104 | @Override 105 | protected int pageAnimColCount() { 106 | return 60; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/WaveAnimActivity.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample; 2 | 3 | import android.os.Bundle; 4 | import android.view.View; 5 | import android.widget.TextView; 6 | 7 | import com.gplibs.magic_surface_view_sample.common.Direction; 8 | import com.gplibs.magic_surface_view_sample.common.MagicActivity; 9 | import com.gplibs.magic_surface_view_sample.updater.WaveAnimUpdater; 10 | import com.gplibs.magicsurfaceview.MagicScene; 11 | import com.gplibs.magicsurfaceview.MagicSurface; 12 | import com.gplibs.magicsurfaceview.MagicUpdaterListener; 13 | import com.gplibs.magicsurfaceview.MagicSurfaceView; 14 | 15 | public class WaveAnimActivity extends MagicActivity { 16 | 17 | private MagicSurfaceView mSurfaceView; 18 | private TextView mTvContent; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_wave_anim); 24 | setTitle("WaveAnim"); 25 | 26 | mSurfaceView = (MagicSurfaceView) findViewById(R.id.surface_view); 27 | mTvContent = (TextView) findViewById(R.id.tv_content); 28 | findViewById(R.id.view_container).setOnClickListener(new View.OnClickListener() { 29 | @Override 30 | public void onClick(View v) { 31 | if (mTvContent.getVisibility() == View.VISIBLE) { 32 | hide(Direction.RIGHT); 33 | } else { 34 | show(Direction.RIGHT); 35 | } 36 | } 37 | }); 38 | } 39 | 40 | @Override 41 | protected void onDestroy() { 42 | super.onDestroy(); 43 | mSurfaceView.onDestroy(); 44 | } 45 | 46 | private void show(int direction) { 47 | WaveAnimUpdater updater = new WaveAnimUpdater(false, direction, false); 48 | updater.addListener(new MagicUpdaterListener() { 49 | @Override 50 | public void onStart() { 51 | mTvContent.setVisibility(View.INVISIBLE); 52 | } 53 | @Override 54 | public void onStop() { 55 | mTvContent.setVisibility(View.VISIBLE); 56 | mSurfaceView.setVisibility(View.GONE); 57 | // 释放资源 58 | mSurfaceView.release(); 59 | } 60 | }); 61 | MagicSurface s = new MagicSurface(mTvContent) 62 | .setGrid(getRowLineCount(direction), getColLineCount(direction)) 63 | .drawGrid(false) 64 | .setModelUpdater(updater); 65 | mSurfaceView.setVisibility(View.VISIBLE); 66 | mSurfaceView.render(s); 67 | } 68 | 69 | private void hide(int direction) { 70 | WaveAnimUpdater updater = new WaveAnimUpdater(true, direction, false); 71 | updater.addListener(new MagicUpdaterListener() { 72 | @Override 73 | public void onStart() { 74 | mTvContent.setVisibility(View.INVISIBLE); 75 | } 76 | @Override 77 | public void onStop() { 78 | mSurfaceView.setVisibility(View.GONE); 79 | // 释放资源 80 | mSurfaceView.release(); 81 | } 82 | }); 83 | MagicSurface s = new MagicSurface(mTvContent) 84 | .setGrid(getRowLineCount(direction), getColLineCount(direction)) 85 | .drawGrid(false) 86 | .setModelUpdater(updater); 87 | mSurfaceView.setVisibility(View.VISIBLE); 88 | mSurfaceView.render(s); 89 | } 90 | 91 | private int getRowLineCount(int direction) { 92 | return Direction.isVertical(direction) ? 50 : 8; 93 | } 94 | 95 | private int getColLineCount(int direction) { 96 | return Direction.isVertical(direction) ? 8 : 50; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/common/AnimHelper.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.common; 2 | 3 | import com.gplibs.magicsurfaceview.MagicBaseSurface; 4 | import com.gplibs.magicsurfaceview.ReusableVec; 5 | import com.gplibs.magicsurfaceview.Vec; 6 | import com.gplibs.magicsurfaceview.VecPool; 7 | 8 | public class AnimHelper { 9 | 10 | public static final int MOVE_TYPE_SCENE = 0; 11 | public static final int MOVE_TYPE_SELF = 1; 12 | 13 | private float mAnimValue; 14 | private int mDirection; 15 | private MagicBaseSurface mSurface; 16 | private float mTotalDistanceScene; 17 | private float mTotalDistanceSelf; 18 | private float mBeginPos = 0, mReverseBeginPos = 0, mSurfaceSize = 1; 19 | 20 | public AnimHelper(MagicBaseSurface surface, int direction, boolean isHide) { 21 | mSurface = surface; 22 | mDirection = direction; 23 | mAnimValue = isHide ? 0 : 1; 24 | init(); 25 | } 26 | 27 | public void update(float animValue) { 28 | mAnimValue = animValue; 29 | } 30 | 31 | public float getStartAnimTime(Vec pos, boolean reverse, float totalStartingTime) { 32 | float p = (mDirection == Direction.TOP || mDirection == Direction.BOTTOM) ? pos.y() : pos.x(); 33 | float begin = reverse ? mReverseBeginPos : mBeginPos; 34 | return Math.abs(p - begin) / mSurfaceSize * totalStartingTime; 35 | } 36 | 37 | public float getStartAnimTime(int index, int count, boolean reverse, float totalStartingTime) { 38 | float start = 0; 39 | float end = count - 1; 40 | switch (mDirection) { 41 | case Direction.TOP: 42 | case Direction.LEFT: 43 | start = reverse ? count - 1 : 0; 44 | end = reverse ? 0 : count - 1; 45 | break; 46 | case Direction.RIGHT: 47 | case Direction.BOTTOM: 48 | start = reverse ? 0 : count - 1; 49 | end = reverse ? count - 1 : 0; 50 | break; 51 | } 52 | return Math.abs((index - start) / (end - start)) * totalStartingTime; 53 | } 54 | 55 | public float getAnimProgress(float startTime, float animTime) { 56 | float endTime = startTime + animTime; 57 | if (endTime > 1) { 58 | endTime = 1; 59 | } 60 | if (mAnimValue < startTime ) { 61 | return 0; 62 | } else if (mAnimValue >= startTime && mAnimValue < endTime) { 63 | float r = (mAnimValue - startTime) / (endTime - startTime); 64 | return r * r; 65 | } else { 66 | return 1; 67 | } 68 | } 69 | 70 | public float getMoveDistance(int moveType, float beginTime, float movingTime) { 71 | return getMoveDistance(moveType == MOVE_TYPE_SELF ? mTotalDistanceSelf : mTotalDistanceScene, beginTime, movingTime); 72 | } 73 | 74 | public float getMoveDistance(float totalDistance, float beginTime, float movingTime) { 75 | float r = getAnimProgress(beginTime, movingTime); 76 | if (mDirection == Direction.TOP || mDirection == Direction.RIGHT) { 77 | return totalDistance * r; 78 | } else { 79 | return -totalDistance * r; 80 | } 81 | } 82 | 83 | private void init() { 84 | ReusableVec surfacePos = VecPool.get(3); 85 | ReusableVec scenePos = VecPool.get(3); 86 | ReusableVec surfacePos1 = VecPool.get(3); 87 | boolean isVertical = false; 88 | 89 | if (mDirection == Direction.TOP) { 90 | mSurface.getPosition(0, 1, surfacePos); 91 | mSurface.getScene().getPosition(0, 0, scenePos); 92 | mSurface.getPosition(0, 0, surfacePos1); 93 | isVertical = true; 94 | } else if (mDirection == Direction.BOTTOM) { 95 | mSurface.getPosition(0, 0, surfacePos); 96 | mSurface.getScene().getPosition(0, 1, scenePos); 97 | mSurface.getPosition(0, 1, surfacePos1); 98 | isVertical = true; 99 | } else if (mDirection == Direction.LEFT) { 100 | mSurface.getPosition(1, 0, surfacePos); 101 | mSurface.getScene().getPosition(0, 0, scenePos); 102 | mSurface.getPosition(0, 0, surfacePos1); 103 | isVertical = false; 104 | } else if (mDirection == Direction.RIGHT) { 105 | mSurface.getPosition(0, 0, surfacePos); 106 | mSurface.getScene().getPosition(1, 0, scenePos); 107 | mSurface.getPosition(1, 0, surfacePos1); 108 | isVertical = false; 109 | } 110 | 111 | if (isVertical) { 112 | mReverseBeginPos = surfacePos.y(); 113 | mBeginPos = surfacePos1.y(); 114 | mSurfaceSize = mSurface.getHeight(); 115 | mTotalDistanceScene = Math.abs(scenePos.y() - surfacePos.y()); 116 | mTotalDistanceSelf = Math.abs(surfacePos1.y() - surfacePos.y()); 117 | } else { 118 | mReverseBeginPos = surfacePos.x(); 119 | mBeginPos = surfacePos1.x(); 120 | mSurfaceSize = mSurface.getWidth(); 121 | mTotalDistanceScene = Math.abs(scenePos.x() - surfacePos.x()); 122 | mTotalDistanceSelf = Math.abs(surfacePos1.x() - surfacePos.x()); 123 | } 124 | 125 | scenePos.free(); 126 | surfacePos1.free(); 127 | surfacePos.free(); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/common/Direction.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.common; 2 | 3 | public class Direction { 4 | public final static int LEFT = 0; 5 | public final static int TOP = 1; 6 | public final static int RIGHT = 2; 7 | public final static int BOTTOM = 3; 8 | 9 | public static boolean isVertical(int direction) { 10 | return direction == TOP || direction == BOTTOM; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/common/FloatValueAnimator.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.common; 2 | 3 | import android.animation.Animator; 4 | import android.animation.TimeInterpolator; 5 | import android.animation.ValueAnimator; 6 | import android.os.Handler; 7 | import android.os.Looper; 8 | import android.view.animation.BounceInterpolator; 9 | import android.view.animation.LinearInterpolator; 10 | 11 | import java.util.ArrayList; 12 | import java.util.List; 13 | 14 | /** 15 | * 0~1 或者 1~0 的ValueAnimator 16 | */ 17 | public class FloatValueAnimator implements ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener { 18 | 19 | public interface FloatValueAnimatorListener { 20 | void onAnimationUpdate(float value); 21 | void onStop(); 22 | } 23 | 24 | private final int STATE_NONE = 0; 25 | private final int STATE_RUNNING = 1; 26 | private final int STATE_STOPPED = 2; 27 | 28 | private int mState = STATE_NONE; 29 | private boolean mStopping = false; 30 | private ValueAnimator mAnimator; 31 | private int mDuration = 600; 32 | private TimeInterpolator mInterpolator; 33 | private List mListeners = new ArrayList<>(2); 34 | 35 | public FloatValueAnimator(int duration) { 36 | mDuration = duration; 37 | } 38 | 39 | public void addListener(FloatValueAnimatorListener listener) { 40 | if (!mListeners.contains(listener)) { 41 | mListeners.add(listener); 42 | } 43 | } 44 | 45 | public void removeListener(FloatValueAnimatorListener listener) { 46 | if (mListeners.contains(listener)) { 47 | mListeners.remove(listener); 48 | } 49 | } 50 | 51 | public void setDuration(int duration) { 52 | mDuration = duration; 53 | } 54 | 55 | public void setInterpolator(TimeInterpolator interpolator) { 56 | this.mInterpolator = interpolator; 57 | } 58 | 59 | @Override 60 | public void onAnimationUpdate(ValueAnimator animation) { 61 | onAnimValueChanged((float) animation.getAnimatedValue()); 62 | } 63 | 64 | @Override 65 | public void onAnimationStart(Animator animation) { 66 | } 67 | 68 | @Override 69 | public void onAnimationEnd(Animator animation) { 70 | mState = STATE_STOPPED; 71 | mAnimator = null; 72 | onStop(); 73 | } 74 | 75 | @Override 76 | public void onAnimationCancel(Animator animation) { 77 | mState = STATE_STOPPED; 78 | mAnimator = null; 79 | onStop(); 80 | } 81 | 82 | @Override 83 | public void onAnimationRepeat(Animator animation) { 84 | } 85 | 86 | public void reset() { 87 | mState = STATE_NONE; 88 | } 89 | 90 | public boolean isStopped() { 91 | return mState == STATE_STOPPED; 92 | } 93 | 94 | public boolean isRunning() { 95 | return mState == STATE_RUNNING; 96 | } 97 | 98 | public synchronized void start(final boolean isReverse) { 99 | if (mState == STATE_RUNNING) { 100 | return; 101 | } 102 | mState = STATE_RUNNING; 103 | new Handler(Looper.getMainLooper()).post(new Runnable() { 104 | @Override 105 | public void run() { 106 | if (isReverse) { 107 | mAnimator = ValueAnimator.ofFloat(1, 0); 108 | } else { 109 | mAnimator = ValueAnimator.ofFloat(0, 1); 110 | } 111 | if (mInterpolator != null) { 112 | mAnimator.setInterpolator(mInterpolator); 113 | } 114 | mAnimator.addUpdateListener(FloatValueAnimator.this); 115 | mAnimator.addListener(FloatValueAnimator.this); 116 | mAnimator.setRepeatCount(0); 117 | mAnimator.setDuration(mDuration); 118 | mAnimator.start(); 119 | } 120 | }); 121 | } 122 | 123 | public synchronized void stop() { 124 | if (mAnimator == null) { 125 | return; 126 | } 127 | if (mStopping) { 128 | return; 129 | } 130 | mStopping = true; 131 | new Handler(Looper.getMainLooper()).post(new Runnable() { 132 | @Override 133 | public void run() { 134 | if (mAnimator != null) { 135 | mAnimator.cancel(); 136 | mAnimator = null; 137 | } 138 | mStopping = false; 139 | } 140 | }); 141 | } 142 | 143 | private void onAnimValueChanged(float animValue) { 144 | for(int i = 0; i < mListeners.size(); ++i) { 145 | if (mListeners.get(i) != null) { 146 | mListeners.get(i).onAnimationUpdate(animValue); 147 | } 148 | } 149 | } 150 | 151 | private void onStop() { 152 | for(int i = 0; i < mListeners.size(); ++i) { 153 | if (mListeners.get(i) != null) { 154 | mListeners.get(i).onStop(); 155 | } 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/common/MagicActivity.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.common; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.ColorRes; 5 | import android.support.annotation.LayoutRes; 6 | import android.support.v4.content.ContextCompat; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.widget.FrameLayout; 11 | import android.widget.TextView; 12 | 13 | import com.gplibs.magic_surface_view_sample.R; 14 | import com.gplibs.magic_surface_view_sample.updater.WaveAnimUpdater; 15 | import com.gplibs.magicsurfaceview.MagicMultiSurface; 16 | import com.gplibs.magicsurfaceview.MagicMultiSurfaceUpdater; 17 | import com.gplibs.magicsurfaceview.MagicSurface; 18 | import com.gplibs.magicsurfaceview.MagicSurfaceMatrixUpdater; 19 | import com.gplibs.magicsurfaceview.MagicSurfaceModelUpdater; 20 | import com.gplibs.magicsurfaceview.MagicSurfaceView; 21 | import com.gplibs.magicsurfaceview.MagicUpdater; 22 | import com.gplibs.magicsurfaceview.MagicUpdaterListener; 23 | 24 | public abstract class MagicActivity extends AppCompatActivity { 25 | 26 | // 页面可视部分的根View 27 | private View mPageViewContainer; 28 | // 用于页面转场动画的 MagicSurfaceView 29 | private MagicSurfaceView mPageSurfaceView; 30 | // 页面TitleBar 31 | private View mPageTitleBar; 32 | // 页面内容容器 33 | private FrameLayout mFlPageContent; 34 | // Title TextView 35 | private TextView mTvPageTitle; 36 | 37 | @Override 38 | protected void onCreate(Bundle savedInstanceState) { 39 | super.onCreate(savedInstanceState); 40 | super.setContentView(R.layout.activity_magic); 41 | mPageViewContainer = findViewById(R.id.page_view_container); 42 | mPageSurfaceView = (MagicSurfaceView) findViewById(R.id.page_surface_view); 43 | mPageTitleBar = findViewById(R.id.page_title_bar); 44 | mFlPageContent = (FrameLayout) findViewById(R.id.fl_page_content); 45 | mTvPageTitle = (TextView) findViewById(R.id.tv_page_title); 46 | 47 | // 进行入场动画 48 | if (!show()) { 49 | mPageViewContainer.setVisibility(View.VISIBLE); 50 | } 51 | } 52 | 53 | @Override 54 | protected void onDestroy() { 55 | super.onDestroy(); 56 | mPageSurfaceView.onDestroy(); 57 | } 58 | 59 | @Override 60 | public void onBackPressed() { 61 | // 进行离场动画 62 | if(!hide()) { 63 | finish(); 64 | } 65 | } 66 | 67 | @Override 68 | public void setTitle(CharSequence title) { 69 | mTvPageTitle.setText(title); 70 | } 71 | 72 | @Override 73 | public void setTitle(int titleId) { 74 | mTvPageTitle.setText(titleId); 75 | } 76 | 77 | @Override 78 | public void setContentView(@LayoutRes int layoutResID) { 79 | LayoutInflater.from(this).inflate(layoutResID, mFlPageContent, true); 80 | } 81 | 82 | protected MagicSurfaceView getPageSurfaceView() { 83 | return mPageSurfaceView; 84 | } 85 | 86 | protected View getPageViewContainer() { 87 | return mPageViewContainer; 88 | } 89 | 90 | protected void showPage() { 91 | mPageViewContainer.setVisibility(View.VISIBLE); 92 | } 93 | 94 | protected void hidePage() { 95 | mPageViewContainer.setVisibility(View.INVISIBLE); 96 | } 97 | 98 | protected void hidePageTitleBar() { 99 | mPageTitleBar.setVisibility(View.GONE); 100 | } 101 | 102 | protected void setPageBackground(@ColorRes int colorResource) { 103 | mPageViewContainer.setBackgroundColor(ContextCompat.getColor(this, colorResource)); 104 | } 105 | 106 | protected void setPageContentBg(@ColorRes int colorResource) { 107 | mFlPageContent.setBackgroundResource(colorResource); 108 | } 109 | 110 | /** 111 | * 获取页面转场动画对应的 Updater 112 | * @param isHide true:离场 false:入场 113 | * @return 114 | */ 115 | protected MagicUpdater getPageUpdater(boolean isHide) { 116 | if (isHide) { 117 | return new WaveAnimUpdater(true, Direction.RIGHT, false); 118 | } else { 119 | return new WaveAnimUpdater(false, Direction.RIGHT, false); 120 | } 121 | } 122 | 123 | /** 124 | * 获取页面碎片化转场动画对应的 Updater 125 | * @param isHide true:离场 false:入场 126 | * @return 127 | */ 128 | protected MagicMultiSurfaceUpdater getPageMultiUpdater(boolean isHide) { 129 | return null; 130 | } 131 | 132 | /** 133 | * 页面转场动画对应 SurfaceModel 行数 134 | * @return 135 | */ 136 | protected int pageAnimRowCount() { 137 | return 30; 138 | } 139 | 140 | /** 141 | * 页面转场动画对应 SurfaceModel 列数 142 | * @return 143 | */ 144 | protected int pageAnimColCount() { 145 | return 30; 146 | } 147 | 148 | /** 149 | * 页面转场动画入场动画完成后调用 150 | * @return 151 | */ 152 | protected void onPageAnimEnd() { 153 | } 154 | 155 | /** 156 | * 开始入场动画 157 | * @return 158 | */ 159 | private boolean show() { 160 | MagicUpdater updater = getPageUpdater(false); 161 | if (updater != null) { 162 | return showWithSurface(updater); 163 | } 164 | MagicMultiSurfaceUpdater multiUpdater = getPageMultiUpdater(false); 165 | if (multiUpdater != null) { 166 | return showWithMultiSurface(multiUpdater); 167 | } 168 | return false; 169 | } 170 | 171 | private boolean showWithSurface(MagicUpdater updater) { 172 | updater.addListener(new MagicUpdaterListener() { 173 | @Override 174 | public void onStart() { 175 | mPageViewContainer.setVisibility(View.INVISIBLE); 176 | } 177 | @Override 178 | public void onStop() { 179 | mPageViewContainer.setVisibility(View.VISIBLE); 180 | mPageSurfaceView.setVisibility(View.GONE); 181 | // 动画完成释放资源 182 | mPageSurfaceView.release(); 183 | onPageAnimEnd(); 184 | } 185 | }); 186 | final MagicSurface s = new MagicSurface(mPageViewContainer) 187 | .setGrid(pageAnimRowCount(), pageAnimColCount()) 188 | .drawGrid(false); 189 | if (updater instanceof MagicSurfaceMatrixUpdater) { 190 | s.setMatrixUpdater((MagicSurfaceMatrixUpdater) updater); 191 | } else { 192 | s.setModelUpdater((MagicSurfaceModelUpdater) updater); 193 | } 194 | mPageSurfaceView.setVisibility(View.VISIBLE); 195 | mPageSurfaceView.render(s); 196 | return true; 197 | } 198 | 199 | private boolean showWithMultiSurface(MagicMultiSurfaceUpdater updater) { 200 | updater.addListener(new MagicUpdaterListener() { 201 | @Override 202 | public void onStart() { 203 | mPageViewContainer.setVisibility(View.INVISIBLE); 204 | } 205 | @Override 206 | public void onStop() { 207 | mPageViewContainer.setVisibility(View.VISIBLE); 208 | mPageSurfaceView.setVisibility(View.GONE); 209 | // 动画完成释放资源 210 | mPageSurfaceView.release(); 211 | onPageAnimEnd(); 212 | } 213 | }); 214 | final MagicMultiSurface s = new MagicMultiSurface(mPageViewContainer, pageAnimRowCount(), pageAnimColCount()); 215 | s.setUpdater(updater); 216 | mPageSurfaceView.setVisibility(View.VISIBLE); 217 | mPageSurfaceView.render(s); 218 | return true; 219 | } 220 | 221 | 222 | /** 223 | * 开始离场动画 224 | * @return 225 | */ 226 | private boolean hide() { 227 | MagicUpdater updater = getPageUpdater(true); 228 | if (updater != null) { 229 | return hideWithSurface(updater); 230 | } 231 | 232 | MagicMultiSurfaceUpdater multiUpdater = getPageMultiUpdater(true); 233 | if (multiUpdater != null) { 234 | return hideWithMultiSurface(multiUpdater); 235 | } 236 | return false; 237 | } 238 | 239 | private boolean hideWithSurface(MagicUpdater updater) { 240 | updater.addListener(new MagicUpdaterListener() { 241 | @Override 242 | public void onStart() { 243 | mPageViewContainer.setVisibility(View.INVISIBLE); 244 | } 245 | @Override 246 | public void onStop() { 247 | mPageSurfaceView.setVisibility(View.GONE); 248 | // 动画完成释放资源 249 | mPageSurfaceView.release(); 250 | finish(); 251 | } 252 | }); 253 | MagicSurface s = new MagicSurface(mPageViewContainer) 254 | .setGrid(pageAnimRowCount(), pageAnimColCount()) 255 | .drawGrid(false); 256 | if (updater instanceof MagicSurfaceMatrixUpdater) { 257 | s.setMatrixUpdater((MagicSurfaceMatrixUpdater) updater); 258 | } else { 259 | s.setModelUpdater((MagicSurfaceModelUpdater) updater); 260 | } 261 | mPageSurfaceView.setVisibility(View.VISIBLE); 262 | mPageSurfaceView.render(s); 263 | return true; 264 | } 265 | 266 | private boolean hideWithMultiSurface(MagicMultiSurfaceUpdater updater) { 267 | updater.addListener(new MagicUpdaterListener() { 268 | @Override 269 | public void onStart() { 270 | mPageViewContainer.setVisibility(View.INVISIBLE); 271 | } 272 | @Override 273 | public void onStop() { 274 | mPageSurfaceView.setVisibility(View.GONE); 275 | // 动画完成释放资源 276 | mPageSurfaceView.release(); 277 | finish(); 278 | } 279 | }); 280 | final MagicMultiSurface s = new MagicMultiSurface(mPageViewContainer, pageAnimRowCount(), pageAnimColCount()); 281 | s.setUpdater(updater); 282 | mPageSurfaceView.setVisibility(View.VISIBLE); 283 | mPageSurfaceView.render(s); 284 | return true; 285 | } 286 | 287 | } 288 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/common/RandomNumber.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.common; 2 | 3 | public class RandomNumber { 4 | 5 | float mMin; 6 | float mMax; 7 | float[] mNumbers; 8 | 9 | public RandomNumber(int count, float min, float max) { 10 | mNumbers = new float[count]; 11 | mMin = min; 12 | mMax = max; 13 | } 14 | 15 | public float get(int index) { 16 | if (mNumbers[index] == 0) { 17 | mNumbers[index] = mMin + (float) Math.random() * (mMax - mMin); 18 | } 19 | return mNumbers[index]; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/launch/LaunchActivity.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.launch; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.util.Log; 6 | import android.view.View; 7 | import android.widget.Button; 8 | 9 | import com.gplibs.magic_surface_view_sample.common.MagicActivity; 10 | import com.gplibs.magic_surface_view_sample.MainActivity; 11 | import com.gplibs.magic_surface_view_sample.R; 12 | import com.gplibs.magic_surface_view_sample.common.FloatValueAnimator; 13 | import com.gplibs.magicsurfaceview.MagicScene; 14 | import com.gplibs.magicsurfaceview.MagicSceneBuilder; 15 | import com.gplibs.magicsurfaceview.MagicSurface; 16 | import com.gplibs.magicsurfaceview.MagicUpdater; 17 | import com.gplibs.magicsurfaceview.MagicUpdaterListener; 18 | import com.gplibs.magicsurfaceview.PointLight; 19 | 20 | /** 21 | * 环境光: 开始黑色 STEP3~1 由黑变白色 22 | * 背景: 0~STEP1由中心开始逐渐显示 23 | * 光源: STEP1~STEP2 由黑变亮 STEP2~STEP3 从左到右 STEP3~1 逐渐消失(颜色变为0) 24 | * 文本: STEP2~STEP3 从左到右与光源同步显示 25 | * 按钮: STEP3~1 逐渐显示出来 26 | */ 27 | public class LaunchActivity extends MagicActivity { 28 | 29 | static final float STEP1 = 0.12f; 30 | static final float STEP2 = 0.3f; 31 | static final float STEP3 = 0.8f; 32 | 33 | private FloatValueAnimator mAnimator = new FloatValueAnimator(2000); 34 | 35 | private PointLight mLight = new PointLight(0XFFFFFFFF, 0, 0, 0.1f); 36 | private int endAnimatorCount = 0; 37 | 38 | private View mViewText; 39 | private Button mBtnEnter; 40 | 41 | // 各Updater运行时间段都是按时间线错开的,btnMatrixUpdater 和 btnModelUpdater是需要同步运行的,所以可以都分到一组,在一个线程运行。 42 | 43 | // 场景动画 44 | private LaunchSceneUpdater sceneUpdater = new LaunchSceneUpdater(mAnimator, 1); 45 | // 背景模型动画 46 | private LaunchBackgroundUpdater backgroundUpdater = new LaunchBackgroundUpdater(mAnimator, 1); 47 | // 文本模型动画 48 | private LaunchTextModelUpdater textModelUpdater = new LaunchTextModelUpdater(mAnimator, 1); 49 | // 按钮矩阵动画 50 | private LaunchButtonMatrixUpdater btnMatrixUpdater = new LaunchButtonMatrixUpdater(mAnimator, 1); 51 | // 按钮模型动画 52 | private LaunchButtonModelUpdater btnModelUpdater = new LaunchButtonModelUpdater(mAnimator, 1); 53 | 54 | private MagicUpdaterListener updaterListener = new MagicUpdaterListener() { 55 | @Override 56 | public void onStart() { 57 | 58 | } 59 | @Override 60 | public void onStop() { 61 | if (++endAnimatorCount == 5) { // 所有动画结束后调用 62 | // 显示真实页面 和 文本、按钮 63 | showPage(); 64 | mBtnEnter.setVisibility(View.VISIBLE); 65 | mViewText.setVisibility(View.VISIBLE); 66 | 67 | // 隐藏 MagicSurfaceView 68 | getPageSurfaceView().setVisibility(View.GONE); 69 | 70 | // 动画完成释放资源 71 | getPageSurfaceView().release(); 72 | } 73 | } 74 | }; 75 | 76 | @Override 77 | protected void onCreate(Bundle savedInstanceState) { 78 | super.onCreate(savedInstanceState); 79 | setPageBackground(R.color.white); 80 | setPageContentBg(R.color.white); 81 | hidePageTitleBar(); 82 | hidePage(); // 起始页动画是个入场的过程,开始需要隐藏整个页面(隐藏必须使用INVISIBLE 不要使用 GONE) 83 | setContentView(R.layout.activity_launch); 84 | 85 | initViews(); 86 | initMagicObjects(); 87 | 88 | render(); 89 | } 90 | 91 | private void initViews() { 92 | mViewText = findViewById(R.id.view_text); 93 | mBtnEnter = (Button) findViewById(R.id.btn_enter); 94 | mBtnEnter.setOnClickListener(new View.OnClickListener() { 95 | @Override 96 | public void onClick(View v) { 97 | startActivity(new Intent(LaunchActivity.this, MainActivity.class)); 98 | mBtnEnter.postDelayed(new Runnable() { 99 | @Override 100 | public void run() { 101 | finish(); 102 | } 103 | }, 2000); 104 | } 105 | }); 106 | // 动画是个入场的过程,开始需要隐藏 (隐藏必须使用INVISIBLE 不要使用 GONE) 107 | mViewText.setVisibility(View.INVISIBLE); 108 | // 动画是个入场的过程,开始需要隐藏 (隐藏必须使用INVISIBLE 不要使用 GONE) 109 | mBtnEnter.setVisibility(View.INVISIBLE); 110 | } 111 | 112 | private void initMagicObjects() { 113 | backgroundUpdater.addListener(updaterListener); 114 | sceneUpdater.addListener(updaterListener); 115 | btnMatrixUpdater.addListener(updaterListener); 116 | textModelUpdater.addListener(updaterListener); 117 | btnModelUpdater.addListener(updaterListener); 118 | } 119 | 120 | /** 121 | * 返回 null 禁用Page转场动画 122 | */ 123 | @Override 124 | protected MagicUpdater getPageUpdater(boolean isHide) { 125 | return null; 126 | } 127 | 128 | private void render() { 129 | MagicSurface bgSurface = new MagicSurface(getPageViewContainer()) 130 | .setGrid(60, 60) 131 | .setModelUpdater(backgroundUpdater); 132 | 133 | MagicSurface textSurface = new MagicSurface(mViewText) 134 | .setGrid(2, 600) 135 | .setEnableDepthTest(false) 136 | .setModelUpdater(textModelUpdater) 137 | .setVisible(false); 138 | 139 | MagicSurface btnSurface = new MagicSurface(mBtnEnter) 140 | .setGrid(30, 5) 141 | .setEnableDepthTest(false) 142 | .setMatrixUpdater(btnMatrixUpdater) 143 | .setModelUpdater(btnModelUpdater) 144 | .setVisible(false); 145 | 146 | MagicScene scene = new MagicSceneBuilder(getPageSurfaceView()) 147 | .ambientColor(0XFF000000) 148 | .addLights(mLight) 149 | .setUpdater(sceneUpdater) 150 | .addSurfaces(bgSurface, textSurface, btnSurface) 151 | .build(); 152 | getPageSurfaceView().render(scene); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/launch/LaunchBackgroundUpdater.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.launch; 2 | 3 | import com.gplibs.magic_surface_view_sample.common.FloatValueAnimator; 4 | import com.gplibs.magicsurfaceview.MagicSurface; 5 | import com.gplibs.magicsurfaceview.MagicSurfaceModelUpdater; 6 | import com.gplibs.magicsurfaceview.ReusableVec; 7 | import com.gplibs.magicsurfaceview.SurfaceModel; 8 | import com.gplibs.magicsurfaceview.Vec; 9 | import com.gplibs.magicsurfaceview.VecPool; 10 | 11 | 12 | /** 13 | * 0~STEP1 14 | */ 15 | class LaunchBackgroundUpdater extends MagicSurfaceModelUpdater { 16 | 17 | private final float WAVE_LENGTH = 0.5f; 18 | 19 | private FloatValueAnimator mAnimator; 20 | private float mAnimValue = 0; 21 | 22 | private float mMaxRadius; 23 | private float mRatio = 0; 24 | private boolean mIsCompleted = false; 25 | 26 | LaunchBackgroundUpdater(FloatValueAnimator animator, int group) { 27 | super(group); 28 | mAnimator = animator; 29 | mAnimator.addListener(new FloatValueAnimator.FloatValueAnimatorListener() { 30 | @Override 31 | public void onAnimationUpdate(float value) { 32 | mAnimValue = value; 33 | // 通知框架,数据改变,可以调用 update 方法进行更新 34 | notifyChanged(); 35 | } 36 | 37 | @Override 38 | public void onStop() { 39 | // 通知框架,数据改变,可以调用 update 方法进行更新 40 | notifyChanged(); 41 | } 42 | }); 43 | } 44 | 45 | // 在绘制第一帧之前调用 (可以在此方法里进行一些初始化操作) 46 | @Override 47 | protected void willStart(MagicSurface surface) { 48 | mMaxRadius = getRadius(surface.getModel(), 0, 0); 49 | } 50 | 51 | // 在开始绘制后调用(绘制第一帧后调用,一般动画可以在此开始) 52 | @Override 53 | protected void didStart(MagicSurface surface) { 54 | mAnimator.start(false); 55 | } 56 | 57 | // 当调用Updater 的 stop() 方法之后,真正停止后会回调此方法 58 | @Override 59 | protected void didStop(MagicSurface surface) { 60 | mAnimator.stop(); 61 | } 62 | 63 | @Override 64 | protected void updateBegin(MagicSurface surface) { 65 | } 66 | 67 | /** 68 | * 修改网格模型 r行, c列处 的坐标及颜色, 修改后的值存到 outPos 和 outColor 69 | * (只需要修改网格模型各行各列点及可,点与点之间的坐标和颜色由 openGL 自动进行插值计算完成) 70 | * 注:此方法执行频率非常高;一般不要有分配新的堆内存的逻辑,会频繁产生gc操作影响性能,可以使用全局变量或者ReusableVec、VecPool 71 | * 72 | * @param surface 73 | * @param r 行 74 | * @param c 列 75 | * @param outPos 默认值为 r行c列点包含偏移量的原始坐标, 计算完成后的新坐标要更新到此变量 76 | * @param outColor 默认值为 rgba(1,1,1,1), 计算完成后的新颜色要更新到此变量 77 | */ 78 | @Override 79 | protected void updatePosition(MagicSurface surface, int r, int c, Vec outPos, Vec outColor) { 80 | if (mIsCompleted) { 81 | return; 82 | } 83 | mRatio = 1; 84 | if (mAnimValue <= LaunchActivity.STEP1) { 85 | mRatio = mAnimValue / LaunchActivity.STEP1; 86 | } 87 | float startRadius = mRatio * (mMaxRadius + WAVE_LENGTH)- WAVE_LENGTH; 88 | float radius = getRadius(outPos); 89 | float offset = radius - startRadius; 90 | if (offset < 0) { 91 | outColor.setColor(0XFFFFFFFF); 92 | } else if (offset > WAVE_LENGTH) { 93 | outColor.a(0); 94 | } else { 95 | float ratio = offset / WAVE_LENGTH; 96 | float a = ratio - 0.6f; 97 | if (a < 0) { 98 | a = 1; 99 | } else { 100 | a = (0.4f - a) / 0.4f; 101 | } 102 | outColor.setRGBA(1 - ratio, 1 - ratio, 1, a); 103 | } 104 | } 105 | 106 | @Override 107 | protected void updateEnd(MagicSurface surface) { 108 | if (!mIsCompleted) { 109 | mIsCompleted = mRatio == 1; 110 | } 111 | if (mAnimator.isStopped()) { 112 | stop(); 113 | } 114 | } 115 | 116 | private float getRadius(Vec pos) { 117 | return (float) Math.sqrt(pos.x() * pos.x() + pos.y() * pos.y()); 118 | } 119 | 120 | private float getRadius(SurfaceModel model, int x, int y) { 121 | ReusableVec pos = VecPool.get(3); 122 | try { 123 | model.getPosition(x, y, pos); 124 | return (float) Math.sqrt(pos.x() * pos.x() + pos.y() * pos.y()); 125 | } finally { 126 | pos.free(); 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/launch/LaunchButtonMatrixUpdater.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.launch; 2 | 3 | import com.gplibs.magic_surface_view_sample.common.FloatValueAnimator; 4 | import com.gplibs.magicsurfaceview.MagicSurface; 5 | import com.gplibs.magicsurfaceview.MagicSurfaceMatrixUpdater; 6 | import com.gplibs.magicsurfaceview.Vec; 7 | 8 | /** 9 | * STEP3~1 10 | */ 11 | class LaunchButtonMatrixUpdater extends MagicSurfaceMatrixUpdater { 12 | 13 | private FloatValueAnimator mAnimator; 14 | private float mAnimValue = 0; 15 | private Vec mAxis = new Vec(3); 16 | private Vec mScale = new Vec(3); 17 | 18 | LaunchButtonMatrixUpdater(FloatValueAnimator animator, int group) { 19 | super(group); 20 | mAnimator = animator; 21 | mAnimator.addListener(new FloatValueAnimator.FloatValueAnimatorListener() { 22 | @Override 23 | public void onAnimationUpdate(float value) { 24 | mAnimValue = value; 25 | // 通知框架,数据改变,可以调用 update 方法进行更新 26 | notifyChanged(); 27 | } 28 | 29 | @Override 30 | public void onStop() { 31 | // 通知框架,数据改变,可以调用 update 方法进行更新 32 | notifyChanged(); 33 | } 34 | }); 35 | } 36 | 37 | // 在绘制第一帧之前调用 (可以在此方法里进行一些初始化操作) 38 | @Override 39 | protected void willStart(MagicSurface surface) { 40 | mAxis.setXYZ(-1, 0, 0); 41 | } 42 | 43 | // 在开始绘制后调用(绘制第一帧后调用,一般动画可以在此开始) 44 | @Override 45 | protected void didStart(MagicSurface surface) { 46 | mAnimator.start(false); 47 | } 48 | 49 | // 当调用Updater 的 stop() 方法之后,真正停止后会回调此方法 50 | @Override 51 | protected void didStop(MagicSurface surface) { 52 | } 53 | 54 | /** 55 | * 在此方法里进行矩阵变换 56 | * 57 | * @param offset offse为模型相对场景中心的坐标偏移量, 如果不进行 offset 位移, model 就会显示在场景中心; 58 | * 59 | * 当使用 View 构造 MagicSurface 时, 60 | * View中心位置 相对 MagicSurfaceView中心位置的坐标偏移量 在场景坐标系中的表现就是 offset。 61 | * 62 | * @param matrix 矩阵 63 | */ 64 | @Override 65 | protected void updateMatrix(MagicSurface surface, Vec offset, float[] matrix) { 66 | if (mAnimValue > LaunchActivity.STEP3) { 67 | reset(matrix); 68 | float ratio = (mAnimValue - LaunchActivity.STEP3) / (1 - LaunchActivity.STEP3); 69 | float angle = 360 * (1 - ratio); 70 | offset.z(-surface.getModel().getHeight()); 71 | // 平移 要放在 旋转操作 前 72 | translate(matrix, offset); 73 | rotate(matrix, mAxis, angle); 74 | mScale.setXYZ(ratio, ratio, ratio); 75 | scale(matrix, mScale); 76 | } 77 | if (mAnimator.isStopped()) { 78 | stop(); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/launch/LaunchButtonModelUpdater.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.launch; 2 | 3 | import com.gplibs.magic_surface_view_sample.common.FloatValueAnimator; 4 | import com.gplibs.magicsurfaceview.MagicSurface; 5 | import com.gplibs.magicsurfaceview.MagicSurfaceModelUpdater; 6 | import com.gplibs.magicsurfaceview.Vec; 7 | 8 | class LaunchButtonModelUpdater extends MagicSurfaceModelUpdater { 9 | 10 | private FloatValueAnimator mAnimator; 11 | private float mAnimValue = 0; 12 | 13 | // 半径 14 | private float mR; 15 | // 周长 16 | private float mP; 17 | // 模型高度值相对周长对应的弧度值 18 | private float mAngle; 19 | 20 | LaunchButtonModelUpdater(FloatValueAnimator animator, int group) { 21 | super(group); 22 | mAnimator = animator; 23 | mAnimator.addListener(new FloatValueAnimator.FloatValueAnimatorListener() { 24 | @Override 25 | public void onAnimationUpdate(float value) { 26 | mAnimValue = value; 27 | // 通知框架,数据改变,可以调用 update 方法进行更新 28 | notifyChanged(); 29 | } 30 | 31 | @Override 32 | public void onStop() { 33 | // 通知框架,数据改变,可以调用 update 方法进行更新 34 | notifyChanged(); 35 | } 36 | }); 37 | } 38 | 39 | // 在绘制第一帧之前调用 (可以在此方法里进行一些初始化操作) 40 | @Override 41 | protected void willStart(MagicSurface surface) { 42 | mR = surface.getModel().getHeight(); 43 | mP = 2 * (float) Math.PI * mR; 44 | mAngle = surface.getModel().getHeight() / mP * (float) Math.PI * 2; 45 | } 46 | 47 | // 在开始绘制后调用(绘制第一帧后调用,一般动画可以在此开始) 48 | @Override 49 | protected void didStart(MagicSurface surface) { 50 | mAnimator.start(false); 51 | } 52 | 53 | // 当调用Updater 的 stop() 方法之后,真正停止后会回调此方法 54 | @Override 55 | protected void didStop(MagicSurface surface) { 56 | mAnimator.stop(); 57 | } 58 | 59 | @Override 60 | protected void updateBegin(MagicSurface surface) { 61 | } 62 | 63 | /** 64 | * 修改网格模型 r行, c列处 的坐标及颜色, 修改后的值存到 outPos 和 outColor 65 | * (只需要修改网格模型各行各列点及可,点与点之间的坐标和颜色由 openGL 自动进行插值计算完成) 66 | * 注:此方法执行频率非常高;一般不要有分配新的堆内存的逻辑,会频繁产生gc操作影响性能,可以使用全局变量或者ReusableVec、VecPool 67 | * 68 | * @param surface 69 | * @param r 行 70 | * @param c 列 71 | * @param outPos 默认值为 r行c列点包含偏移量的原始坐标, 计算完成后的新坐标要更新到此变量 72 | * @param outColor 默认值为 rgba(1,1,1,1), 计算完成后的新颜色要更新到此变量 73 | */ 74 | @Override 75 | protected void updatePosition(MagicSurface surface, int r, int c, Vec outPos, Vec outColor) { 76 | if (mAnimValue > LaunchActivity.STEP3) { 77 | float ratio = (mAnimValue - LaunchActivity.STEP3) / (1 - LaunchActivity.STEP3); 78 | ratio *= ratio; 79 | float offsetAngle = ((float) Math.PI * 2 - mAngle) * (1 - ratio); 80 | 81 | surface.getModel().getPositionExcludeOffset(r, c, outPos); 82 | 83 | float ratioY = 1 - (surface.getModel().getHeight() / 2 + outPos.y()) / surface.getModel().getHeight(); 84 | ratioY *= ratioY; 85 | float halfWidth = surface.getModel().getWidth() / 2; 86 | float offsetX = halfWidth * (1 - ratioY) * (1 - ratio); 87 | outPos.x(outPos.x() - offsetX * outPos.x() / halfWidth); // x 由从上小下大锥形 逐渐恢复原值。 88 | float offset = (outPos.y()) / surface.getModel().getHeight() * mP; 89 | float a = offset / mP * (mAngle + offsetAngle); // a 是逐渐减小的过程,直到mAngle, 曲面拉伸弧度也减小。 90 | outPos.y((float) Math.sin(a) * mR); 91 | outPos.z((float) Math.cos(a) * mR); 92 | } 93 | } 94 | 95 | @Override 96 | protected void updateEnd(MagicSurface surface) { 97 | if (mAnimValue > LaunchActivity.STEP3) { 98 | surface.getModel().updateModelNormal(); 99 | surface.setVisible(true); 100 | } 101 | if (mAnimator.isStopped()) { 102 | stop(); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/launch/LaunchSceneUpdater.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.launch; 2 | 3 | import com.gplibs.magic_surface_view_sample.common.FloatValueAnimator; 4 | import com.gplibs.magicsurfaceview.MagicScene; 5 | import com.gplibs.magicsurfaceview.MagicSceneUpdater; 6 | import com.gplibs.magicsurfaceview.MagicSurface; 7 | import com.gplibs.magicsurfaceview.PointLight; 8 | import com.gplibs.magicsurfaceview.Vec; 9 | 10 | class LaunchSceneUpdater extends MagicSceneUpdater { 11 | 12 | private FloatValueAnimator mAnimator; 13 | private float mAnimValue = 0; 14 | 15 | private float mLightColor = 1.0f; // 灯光最亮颜色值 16 | private Vec mBeginPoint = new Vec(3); // 开始移动的坐标 17 | private Vec mCurrentPoint = new Vec(3); // 当前移动到的坐标 18 | 19 | LaunchSceneUpdater(FloatValueAnimator animator, int group) { 20 | super(group); 21 | mAnimator = animator; 22 | mAnimator.addListener(new FloatValueAnimator.FloatValueAnimatorListener() { 23 | @Override 24 | public void onAnimationUpdate(float value) { 25 | mAnimValue = value; 26 | // 通知框架,数据改变,可以调用 update 方法进行更新 27 | notifyChanged(); 28 | } 29 | 30 | @Override 31 | public void onStop() { 32 | // 通知框架,数据改变,可以调用 update 方法进行更新 33 | notifyChanged(); 34 | } 35 | }); 36 | } 37 | 38 | // 在绘制第一帧之前调用 (可以在此方法里进行一些初始化操作) 39 | @Override 40 | protected void willStart(MagicScene scene) { 41 | // 获取文本Surface; 文本Surface 是在构造MagicScene时第二个添加,所以可以通过 scene.getSurface(1) 获取. 42 | MagicSurface surface = scene.getSurface(1); 43 | surface.getModel().getPosition(0, 0, mBeginPoint); 44 | mBeginPoint.y(mBeginPoint.y() - surface.getModel().getHeight() / 2); 45 | mBeginPoint.z(0.14f); 46 | 47 | Vec pos = new Vec(3); 48 | scene.getCameraPos(pos); 49 | float y = mBeginPoint.y() - pos.y(); 50 | mBeginPoint.y(mBeginPoint.y() + 0.14f * y / pos.z()); 51 | } 52 | 53 | // 在开始绘制后调用(绘制第一帧后调用,一般动画可以在此开始) 54 | @Override 55 | protected void didStart(MagicScene scene) { 56 | mAnimator.start(false); 57 | } 58 | 59 | // 当调用Updater 的 stop() 方法之后,真正停止后会回调此方法 60 | @Override 61 | protected void didStop(MagicScene scene) { 62 | mAnimator.stop(); 63 | } 64 | 65 | // 更新环境光及灯光 66 | @Override 67 | protected void update(MagicScene scene, Vec outAmbientColor) { 68 | PointLight light = scene.getLight(0); 69 | if (mAnimValue < LaunchActivity.STEP1) { 70 | // 0~STEP1 不使用灯光 71 | 72 | if (light.isEnable()) { 73 | light.setEnable(false); 74 | } 75 | } else if (mAnimValue >= LaunchActivity.STEP1 && mAnimValue <= LaunchActivity.STEP2) { 76 | // STEP1~STEP2 灯光逐渐变亮 77 | 78 | if (!light.isEnable()) { 79 | light.setEnable(true); 80 | } 81 | float c = mLightColor * (mAnimValue - 0.2f) / 0.1f; 82 | light.setColor(c, c, c, 1.f); 83 | light.setPosition(mBeginPoint); 84 | } else if (mAnimValue < LaunchActivity.STEP3) { 85 | // STEP2~STEP3 移动灯光 86 | 87 | if (light.getColor().r() != mLightColor) { 88 | light.setColor(mLightColor, mLightColor, mLightColor, 1.f); 89 | } 90 | float r = (mAnimValue - LaunchActivity.STEP2) / (LaunchActivity.STEP3 - LaunchActivity.STEP2); 91 | mCurrentPoint.copy(mBeginPoint); 92 | mCurrentPoint.x(mCurrentPoint.x() + r * scene.getWidth()); 93 | light.setPosition(mCurrentPoint); 94 | } else if (mAnimValue >= LaunchActivity.STEP3) { 95 | // STEP3~1 灯光变暗,环境光变亮 96 | 97 | float r = (mAnimValue - LaunchActivity.STEP3) / (1 - LaunchActivity.STEP3); 98 | outAmbientColor.setRGBA(r, r, r, 1.f); 99 | float c = mLightColor * (1 - r); 100 | light.setColor(c, c, c, 1.f); 101 | } 102 | 103 | // 动画停止时 调用stop()停止Updater 104 | if (mAnimator.isStopped()) { 105 | stop(); 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/launch/LaunchTextModelUpdater.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.launch; 2 | 3 | import com.gplibs.magic_surface_view_sample.common.FloatValueAnimator; 4 | import com.gplibs.magicsurfaceview.MagicSurface; 5 | import com.gplibs.magicsurfaceview.MagicSurfaceModelUpdater; 6 | import com.gplibs.magicsurfaceview.Vec; 7 | 8 | /** 9 | * STEP2~STEP3 10 | */ 11 | class LaunchTextModelUpdater extends MagicSurfaceModelUpdater { 12 | 13 | private FloatValueAnimator mAnimator; 14 | private float mAnimValue = 0; 15 | private float mRatio = 0; 16 | private boolean mIsCompleted; 17 | private float mLeft; 18 | 19 | LaunchTextModelUpdater(FloatValueAnimator animator, int group) { 20 | super(group); 21 | mAnimator = animator; 22 | mAnimator.addListener(new FloatValueAnimator.FloatValueAnimatorListener() { 23 | @Override 24 | public void onAnimationUpdate(float value) { 25 | mAnimValue = value; 26 | // 通知框架,数据改变,可以调用 update 方法进行更新 27 | notifyChanged(); 28 | } 29 | 30 | @Override 31 | public void onStop() { 32 | // 通知框架,数据改变,可以调用 update 方法进行更新 33 | notifyChanged(); 34 | } 35 | }); 36 | } 37 | 38 | // 在绘制第一帧之前调用 (可以在此方法里进行一些初始化操作) 39 | @Override 40 | protected void willStart(MagicSurface surface) { 41 | Vec pos = new Vec(3); 42 | surface.getModel().getPosition(0, 0, pos); 43 | mLeft = pos.x(); 44 | } 45 | 46 | // 在开始绘制后调用(绘制第一帧后调用,一般动画可以在此开始) 47 | @Override 48 | protected void didStart(MagicSurface surface) { 49 | mAnimator.start(false); 50 | } 51 | 52 | // 当调用Updater 的 stop() 方法之后,真正停止后会回调此方法 53 | @Override 54 | protected void didStop(MagicSurface surface) { 55 | mAnimator.stop(); 56 | } 57 | 58 | @Override 59 | protected void updateBegin(MagicSurface surface) { 60 | } 61 | 62 | /** 63 | * 修改网格模型 r行, c列处 的坐标及颜色, 修改后的值存到 outPos 和 outColor 64 | * (只需要修改网格模型各行各列点及可,点与点之间的坐标和颜色由 openGL 自动进行插值计算完成) 65 | * 注:此方法执行频率非常高;一般不要有分配新的堆内存的逻辑,会频繁产生gc操作影响性能,可以使用全局变量或者ReusableVec、VecPool 66 | * 67 | * @param surface 68 | * @param r 行 69 | * @param c 列 70 | * @param outPos 默认值为 r行c列点包含偏移量的原始坐标, 计算完成后的新坐标要更新到此变量 71 | * @param outColor 默认值为 rgba(1,1,1,1), 计算完成后的新颜色要更新到此变量 72 | */ 73 | @Override 74 | protected void updatePosition(MagicSurface surface, int r, int c, Vec outPos, Vec outColor) { 75 | if (mAnimValue > LaunchActivity.STEP2 && !mIsCompleted) { 76 | mRatio = (mAnimValue - LaunchActivity.STEP2) / (LaunchActivity.STEP3 - LaunchActivity.STEP2); 77 | if (mRatio > 1) { 78 | mRatio = 1; 79 | } 80 | float centerX = mLeft + mRatio * surface.getModel().getWidth(); 81 | float offset = centerX - outPos.x(); 82 | outColor.a(offset <= 0 ? 0 : 1); 83 | } 84 | } 85 | 86 | @Override 87 | protected void updateEnd(MagicSurface surface) { 88 | if(mAnimValue > LaunchActivity.STEP2 && !mIsCompleted) { 89 | surface.setVisible(true); 90 | } 91 | mIsCompleted = mRatio == 1; 92 | if (mAnimator.isStopped()) { 93 | stop(); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/updater/MacWindowAnimUpdater.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.updater; 2 | 3 | import com.gplibs.magic_surface_view_sample.common.Direction; 4 | import com.gplibs.magic_surface_view_sample.common.FloatValueAnimator; 5 | import com.gplibs.magicsurfaceview.MagicSurface; 6 | import com.gplibs.magicsurfaceview.MagicSurfaceModelUpdater; 7 | import com.gplibs.magicsurfaceview.SurfaceModel; 8 | import com.gplibs.magicsurfaceview.Vec; 9 | 10 | /** 11 | * 模仿Mac窗口动画 12 | */ 13 | public class MacWindowAnimUpdater extends MagicSurfaceModelUpdater { 14 | 15 | private final float MODIFY_TARGET_TOTAL_TIME = 0.1f; // 动画使用 1/10 的时间完成下端收缩或者展开。 16 | 17 | private FloatValueAnimator mAnimator; 18 | private float mAnimValue = 0; 19 | 20 | private float mStartChangeOffsetTime; // 开始移动位置的时间 21 | private boolean mIsHideAnim = true; 22 | private float mTarget; 23 | private int mDirection = Direction.BOTTOM; 24 | 25 | private Vec mToCenter = new Vec(3); 26 | private Vec mToBegin = new Vec(3); 27 | private Vec mToEnd = new Vec(3); 28 | private Vec mFromBegin = new Vec(3); 29 | private Vec mFromEnd = new Vec(3); 30 | private float mOffset; 31 | private boolean mIsVertical; 32 | private boolean mRangeOfSelf = false; 33 | private float mMoveLengthValue; 34 | private float mFromSize; 35 | 36 | public MacWindowAnimUpdater(boolean isHideAnim, int direction, float target, boolean rangeOfSelf) { 37 | super(); 38 | mIsHideAnim = isHideAnim; 39 | mDirection = direction; 40 | mTarget = target; 41 | mRangeOfSelf = rangeOfSelf; 42 | 43 | mAnimator = new FloatValueAnimator(600); 44 | mAnimator.addListener(new FloatValueAnimator.FloatValueAnimatorListener() { 45 | @Override 46 | public void onAnimationUpdate(float value) { 47 | mAnimValue = value; 48 | // 通知框架,数据改变,可以调用 update 方法进行更新 49 | notifyChanged(); 50 | } 51 | 52 | @Override 53 | public void onStop() { 54 | // 通知框架,数据改变,可以调用 update 方法进行更新 55 | notifyChanged(); 56 | } 57 | }); 58 | } 59 | 60 | // 在绘制第一帧之前调用 (可以在此方法里进行一些初始化操作) 61 | @Override 62 | protected void willStart(MagicSurface surface) { 63 | SurfaceModel model = surface.getModel(); 64 | switch (mDirection) { 65 | case Direction.LEFT: 66 | model.getPosition(0, model.getColLineCount() - 1, mFromBegin); 67 | model.getPosition(model.getRowLineCount() - 1, model.getColLineCount() - 1, mFromEnd); 68 | if (mRangeOfSelf) { 69 | surface.getPosition(0, mTarget, mToCenter); 70 | } else { 71 | surface.getScene().getPosition(0, mTarget, mToCenter); 72 | } 73 | break; 74 | case Direction.RIGHT: 75 | model.getPosition(0, 0, mFromBegin); 76 | model.getPosition(model.getRowLineCount() - 1, 0, mFromEnd); 77 | if (mRangeOfSelf) { 78 | surface.getPosition(1, mTarget, mToCenter); 79 | } else { 80 | surface.getScene().getPosition(1, mTarget, mToCenter); 81 | } 82 | break; 83 | case Direction.TOP: 84 | model.getPosition(model.getRowLineCount() - 1, 0, mFromBegin); 85 | model.getPosition(model.getRowLineCount() - 1, model.getColLineCount() - 1, mFromEnd); 86 | if (mRangeOfSelf) { 87 | surface.getPosition(mTarget, 0, mToCenter); 88 | } else { 89 | surface.getScene().getPosition(mTarget, 0, mToCenter); 90 | } 91 | break; 92 | case Direction.BOTTOM: 93 | model.getPosition(0, 0, mFromBegin); 94 | model.getPosition(0, model.getColLineCount() - 1, mFromEnd); 95 | if (mRangeOfSelf) { 96 | surface.getPosition(mTarget, 1, mToCenter); 97 | } else { 98 | surface.getScene().getPosition(mTarget, 1, mToCenter); 99 | } 100 | break; 101 | } 102 | 103 | mAnimValue = mIsHideAnim ? 0 : 1; 104 | mIsVertical = Direction.isVertical(mDirection); 105 | float h; 106 | if (mIsVertical) { 107 | h = model.getHeight(); 108 | mFromSize = model.getWidth(); 109 | mMoveLengthValue = mFromBegin.y() - mToCenter.y(); 110 | } else { 111 | h = model.getWidth(); 112 | mFromSize = model.getHeight(); 113 | mMoveLengthValue = mFromBegin.x() - mToCenter.x(); 114 | } 115 | float r = Math.abs(h / mMoveLengthValue); 116 | mStartChangeOffsetTime = r * r * MODIFY_TARGET_TOTAL_TIME; 117 | } 118 | 119 | // 在开始绘制后调用(绘制第一帧后调用,一般动画可以在此开始) 120 | @Override 121 | protected void didStart(MagicSurface surface) { 122 | mAnimator.start(!mIsHideAnim); 123 | } 124 | 125 | // 当调用Updater 的 stop() 方法之后,真正停止后会回调此方法 126 | @Override 127 | protected void didStop(MagicSurface surface) { 128 | mAnimator.stop(); 129 | } 130 | 131 | @Override 132 | protected void updateBegin(MagicSurface surface) { 133 | updateTarget(surface); 134 | updateOffset(); 135 | } 136 | 137 | /** 138 | * 修改网格模型 r行, c列处 的坐标及颜色, 修改后的值存到 outPos 和 outColor 139 | * (只需要修改网格模型各行各列点及可,点与点之间的坐标和颜色由 openGL 自动进行插值计算完成) 140 | * 注:此方法执行频率非常高;一般不要有分配新的堆内存的逻辑,会频繁产生gc操作影响性能,可以使用全局变量或者ReusableVec、VecPool 141 | * 142 | * @param surface 143 | * @param r 行 144 | * @param c 列 145 | * @param outPos 默认值为 r行c列点包含偏移量的原始坐标, 计算完成后的新坐标要更新到此变量 146 | * @param outColor 默认值为 rgba(1,1,1,1), 计算完成后的新颜色要更新到此变量 147 | */ 148 | @Override 149 | protected void updatePosition(MagicSurface surface, int r, int c, Vec outPos, Vec outColor) { 150 | if (mIsVertical) { 151 | outPos.y(outPos.y() - mOffset); 152 | float y = Math.abs(outPos.y()); 153 | float t = mRangeOfSelf ? surface.getHeight() / 2 : surface.getScene().getHeight() / 2; 154 | if (y > t) { 155 | outPos.y(mOffset > 0 ? -t : t); 156 | } 157 | } else { 158 | outPos.x(outPos.x() - mOffset); 159 | float x = Math.abs(outPos.x()); 160 | float t = mRangeOfSelf ? surface.getWidth() / 2 : surface.getScene().getWidth() / 2; 161 | if (x > t) { 162 | outPos.x(mOffset > 0 ? -t : t); 163 | } 164 | } 165 | updatePosition(outPos, mFromBegin, mFromEnd, mToBegin, mToEnd); 166 | } 167 | 168 | @Override 169 | protected void updateEnd(MagicSurface surface) { 170 | if (mAnimator.isStopped()) { 171 | // 调用 stop 方法,通知框架开始停止此 updater, 停止后会调用 didStop 方法。 172 | stop(); 173 | } 174 | } 175 | 176 | private void updateTarget(MagicSurface surface) { 177 | SurfaceModel model = surface.getModel(); 178 | 179 | float r = MODIFY_TARGET_TOTAL_TIME - mAnimValue; 180 | if (r < 0) { 181 | r = 0; 182 | } 183 | r /= MODIFY_TARGET_TOTAL_TIME; 184 | float range = r * (mIsVertical ? model.getWidth() : model.getHeight()); 185 | if (range < 0.02f) { 186 | range = 0.02f; 187 | } 188 | 189 | if (mIsVertical) { 190 | float modelCenterX = mFromBegin.x() + model.getWidth() / 2; 191 | float targetX = modelCenterX + (1 - r) * (mToCenter.x() - modelCenterX); 192 | mToBegin.setXY(targetX - range / 2, mToCenter.y()); 193 | mToEnd.setXY(targetX + range / 2, mToCenter.y()); 194 | } else { 195 | float modelCenterY = mFromBegin.y() - model.getHeight() / 2; 196 | float targetY = modelCenterY + (1 - r) * (mToCenter.y() - modelCenterY); 197 | mToBegin.setXY(mToCenter.x(), targetY + range / 2); 198 | mToEnd.setXY(mToCenter.x(), targetY - range / 2); 199 | } 200 | } 201 | 202 | private void updateOffset() { 203 | if (mAnimValue > mStartChangeOffsetTime) { 204 | float r = (mAnimValue - mStartChangeOffsetTime) / (1 - mStartChangeOffsetTime); 205 | mOffset = mMoveLengthValue * r; 206 | } else { 207 | mOffset = 0; 208 | } 209 | } 210 | 211 | private void updatePosition( 212 | Vec pos, Vec fromBegin, Vec fromEnd, 213 | Vec toBegin, Vec toEnd) { 214 | float coordBegin = getNewPos(pos, fromBegin, toBegin); 215 | float coordEnd = getNewPos(pos, fromEnd, toEnd); 216 | float r = mIsVertical ? ((pos.x() - fromBegin.x()) / mFromSize) : ((fromBegin.y() - pos.y()) / mFromSize); 217 | float coord = coordBegin + (coordEnd - coordBegin) * r; 218 | if (mIsVertical) { 219 | pos.x(coord); 220 | } else { 221 | pos.y(coord); 222 | } 223 | } 224 | 225 | private float getNewPos(Vec pos, Vec start, Vec end) { 226 | float halfRatio = 0.5f; 227 | float ratio; 228 | if (mIsVertical) { 229 | ratio = (pos.y() - start.y()) / (end.y() - start.y()); 230 | } else { 231 | ratio = (pos.x() - start.x()) / (end.x() - start.x()); 232 | } 233 | float half; 234 | if (mIsVertical) { 235 | half = (end.x() - start.x()) / 2; 236 | } else { 237 | half = (end.y() - start.y()) / 2; 238 | } 239 | float coord = (mIsVertical ? start.x() : start.y()); 240 | if (ratio < halfRatio) { 241 | float r = ratio / halfRatio; 242 | coord += r * r * half; 243 | } else { 244 | float r = (1 - ratio) / (1 - halfRatio); 245 | coord += (2 - r * r) * half; 246 | } 247 | return coord; 248 | } 249 | 250 | } 251 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/updater/MultiScrapUpdater.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.updater; 2 | 3 | import com.gplibs.magic_surface_view_sample.common.AnimHelper; 4 | import com.gplibs.magic_surface_view_sample.common.Direction; 5 | import com.gplibs.magic_surface_view_sample.common.FloatValueAnimator; 6 | import com.gplibs.magic_surface_view_sample.common.RandomNumber; 7 | import com.gplibs.magicsurfaceview.MagicMultiSurface; 8 | import com.gplibs.magicsurfaceview.MagicMultiSurfaceUpdater; 9 | import com.gplibs.magicsurfaceview.Vec; 10 | 11 | public class MultiScrapUpdater extends MagicMultiSurfaceUpdater { 12 | 13 | private final float ANIM_TIME = 0.5f; 14 | 15 | private FloatValueAnimator mAnimator = new FloatValueAnimator(1000); 16 | private AnimHelper mAnimHelper; 17 | private int mDirection; 18 | private boolean mIsHide; 19 | private boolean mIsVertical; 20 | private RandomNumber[] mRandoms; 21 | private RandomNumber mRandom; 22 | private Vec mAxis = new Vec(0.5f, 0.5f, 1); 23 | 24 | public MultiScrapUpdater(boolean isHide, int direction) { 25 | mIsHide = isHide; 26 | mDirection = direction; 27 | mAnimator.addListener(new FloatValueAnimator.FloatValueAnimatorListener() { 28 | @Override 29 | public void onAnimationUpdate(float value) { 30 | mAnimHelper.update(value); 31 | notifyChanged(); 32 | } 33 | 34 | @Override 35 | public void onStop() { 36 | notifyChanged(); 37 | } 38 | }); 39 | } 40 | 41 | @Override 42 | protected void willStart(MagicMultiSurface surface) { 43 | surface.getScene().setCameraZ(2.f); 44 | mAnimHelper = new AnimHelper(surface, mDirection, mIsHide); 45 | mIsVertical = Direction.isVertical(mDirection); 46 | int count = mIsVertical ? surface.getRows() : surface.getCols(); 47 | float t = (1 - ANIM_TIME) / count; 48 | mRandoms = new RandomNumber[count]; 49 | for (int i = 0; i < mRandoms.length; ++i) { 50 | int n = mIsVertical ? surface.getCols(): surface.getRows(); 51 | float time = mAnimHelper.getStartAnimTime(i, mRandoms.length, false, 1 - ANIM_TIME - t); 52 | mRandoms[i] = new RandomNumber(n, time, time + t); 53 | } 54 | mRandom = new RandomNumber(surface.getRows() * surface.getCols(), 0, 1); 55 | } 56 | 57 | @Override 58 | protected void didStart(MagicMultiSurface surface) { 59 | mAnimator.start(!mIsHide); 60 | } 61 | 62 | @Override 63 | protected void didStop(MagicMultiSurface surface) { 64 | 65 | } 66 | 67 | @Override 68 | protected void updateBegin(MagicMultiSurface surface) { 69 | 70 | } 71 | 72 | @Override 73 | protected void update(MagicMultiSurface surface, int r, int c, float[] matrix, Vec offset, Vec color) { 74 | float startTime = mRandoms[mIsVertical ? r : c].get(mIsVertical ? c : r); 75 | float ratio = mAnimHelper.getAnimProgress(startTime, ANIM_TIME); 76 | float ratio1 = mRandom.get(r * surface.getCols() + c); 77 | color.a(1 - ratio); 78 | float angle = 360 * ratio1 * ratio; 79 | float d = ratio1 * mAnimHelper.getMoveDistance(AnimHelper.MOVE_TYPE_SCENE, startTime, ANIM_TIME); 80 | if (mIsVertical) { 81 | offset.y(offset.y() + d); 82 | offset.x(offset.x() + ratio1 * ratio * surface.getWidth()); 83 | } else { 84 | offset.x(offset.x() + d); 85 | } 86 | offset.z(offset.z() + 0.5f * ratio1 * ratio); 87 | reset(matrix); 88 | translate(matrix, offset); 89 | rotate(matrix, mAxis, angle); 90 | } 91 | 92 | @Override 93 | protected void updateEnd(MagicMultiSurface surface) { 94 | if (mAnimator.isStopped()) { 95 | stop(); 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/updater/MultiSlideUpdater.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.updater; 2 | 3 | import com.gplibs.magic_surface_view_sample.common.AnimHelper; 4 | import com.gplibs.magic_surface_view_sample.common.Direction; 5 | import com.gplibs.magic_surface_view_sample.common.FloatValueAnimator; 6 | import com.gplibs.magicsurfaceview.MagicMultiSurface; 7 | import com.gplibs.magicsurfaceview.MagicMultiSurfaceUpdater; 8 | import com.gplibs.magicsurfaceview.Vec; 9 | 10 | public class MultiSlideUpdater extends MagicMultiSurfaceUpdater { 11 | 12 | private final float MOVING_TOTAL_TIME = 0.4f; 13 | 14 | private FloatValueAnimator mAnimator = new FloatValueAnimator(600); 15 | private boolean mIsHide; 16 | private boolean mIsVertical; 17 | private int mDirection; 18 | private AnimHelper mAnimHelper; 19 | private Vec mAxis; 20 | 21 | public MultiSlideUpdater(boolean isHide, int direction) { 22 | mIsHide = isHide; 23 | mDirection = direction; 24 | mAnimator.addListener(new FloatValueAnimator.FloatValueAnimatorListener() { 25 | @Override 26 | public void onAnimationUpdate(float value) { 27 | mAnimHelper.update(value); 28 | notifyChanged(); 29 | } 30 | 31 | @Override 32 | public void onStop() { 33 | notifyChanged(); 34 | } 35 | }); 36 | } 37 | 38 | @Override 39 | protected void willStart(MagicMultiSurface surface) { 40 | mIsVertical = Direction.isVertical(mDirection); 41 | mAnimHelper = new AnimHelper(surface, mDirection, mIsHide); 42 | mAxis = mIsVertical ? new Vec(0, 1, 0) : new Vec(1, 0, 0); 43 | } 44 | 45 | @Override 46 | protected void didStart(MagicMultiSurface surface) { 47 | mAnimator.start(!mIsHide); 48 | } 49 | 50 | @Override 51 | protected void didStop(MagicMultiSurface surface) { 52 | 53 | } 54 | 55 | @Override 56 | protected void updateBegin(MagicMultiSurface surface) { 57 | 58 | } 59 | 60 | @Override 61 | protected void update(MagicMultiSurface surface, int r, int c, float[] matrix, Vec offset, Vec color) { 62 | float startTime = mAnimHelper.getStartAnimTime( 63 | mIsVertical ? r : c, 64 | mIsVertical ? surface.getRows() : surface.getCols(), 65 | false, 1 - MOVING_TOTAL_TIME); 66 | float ratio = mAnimHelper.getAnimProgress(startTime, MOVING_TOTAL_TIME); 67 | float len = mAnimHelper.getMoveDistance(AnimHelper.MOVE_TYPE_SCENE, startTime, MOVING_TOTAL_TIME); 68 | reset(matrix); 69 | if (mIsVertical) { 70 | offset.y(offset.y() + len); 71 | } else { 72 | offset.x(offset.x() + len); 73 | } 74 | translate(matrix, offset); 75 | rotate(matrix, mAxis, 110 * ratio); 76 | color.a(1 - ratio); 77 | } 78 | 79 | @Override 80 | protected void updateEnd(MagicMultiSurface surface) { 81 | if (mAnimator.isStopped()) { 82 | stop(); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/updater/VortexAnimUpdater.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.updater; 2 | 3 | import com.gplibs.magic_surface_view_sample.common.FloatValueAnimator; 4 | import com.gplibs.magicsurfaceview.MagicSurface; 5 | import com.gplibs.magicsurfaceview.MagicSurfaceModelUpdater; 6 | import com.gplibs.magicsurfaceview.ReusableVec; 7 | import com.gplibs.magicsurfaceview.SurfaceModel; 8 | import com.gplibs.magicsurfaceview.Vec; 9 | import com.gplibs.magicsurfaceview.VecPool; 10 | 11 | /** 12 | * 旋涡动画 13 | */ 14 | public class VortexAnimUpdater extends MagicSurfaceModelUpdater { 15 | 16 | private FloatValueAnimator mAnimator; 17 | private float mAnimValue = 0; 18 | 19 | private boolean mIsHide; 20 | 21 | private float maxRadius; 22 | private float mRotateTime = 0.2f; 23 | 24 | public VortexAnimUpdater(boolean isHide) { 25 | mIsHide = isHide; 26 | mAnimValue = mIsHide ? 0 : 1; 27 | 28 | mAnimator = new FloatValueAnimator(600); 29 | mAnimator.addListener(new FloatValueAnimator.FloatValueAnimatorListener() { 30 | @Override 31 | public void onAnimationUpdate(float value) { 32 | mAnimValue = value; 33 | // 通知框架,数据改变,可以调用 update 方法进行更新 34 | notifyChanged(); 35 | } 36 | 37 | @Override 38 | public void onStop() { 39 | // 通知框架,数据改变,可以调用 update 方法进行更新 40 | notifyChanged(); 41 | } 42 | }); 43 | } 44 | 45 | // 在绘制第一帧之前调用 (可以在此方法里进行一些初始化操作) 46 | @Override 47 | protected void willStart(MagicSurface surface) { 48 | SurfaceModel model = surface.getModel(); 49 | Vec topLeft = new Vec(3); 50 | model.getPosition(0, 0, topLeft); 51 | maxRadius = Math.max( 52 | getRadius(model, 0, 0), 53 | Math.max( 54 | getRadius(model, 0, 1), 55 | Math.max(getRadius(model, 1, 0), getRadius(model, 1, 1)) 56 | ) 57 | ); 58 | } 59 | 60 | // 在开始绘制后调用(绘制第一帧后调用,一般动画可以在此开始) 61 | @Override 62 | protected void didStart(MagicSurface surface) { 63 | mAnimator.start(!mIsHide); 64 | } 65 | 66 | // 当调用Updater 的 stop() 方法之后,真正停止后会回调此方法 67 | @Override 68 | protected void didStop(MagicSurface surface) { 69 | mAnimator.stop(); 70 | } 71 | 72 | @Override 73 | protected void updateBegin(MagicSurface surface) { 74 | 75 | } 76 | 77 | /** 78 | * 修改网格模型 r行, c列处 的坐标及颜色, 修改后的值存到 outPos 和 outColor 79 | * (只需要修改网格模型各行各列点及可,点与点之间的坐标和颜色由 openGL 自动进行插值计算完成) 80 | * 注:此方法执行频率非常高;一般不要有分配新的堆内存的逻辑,会频繁产生gc操作影响性能,可以使用全局变量或者ReusableVec、VecPool 81 | * 82 | * @param surface 83 | * @param r 行 84 | * @param c 列 85 | * @param outPos 默认值为 r行c列点包含偏移量的原始坐标, 计算完成后的新坐标要更新到此变量 86 | * @param outColor 默认值为 rgba(1,1,1,1), 计算完成后的新颜色要更新到此变量 87 | */ 88 | @Override 89 | protected void updatePosition(MagicSurface surface, int r, int c, Vec outPos, Vec outColor) { 90 | float radius = (float) Math.sqrt(outPos.x() * outPos.x() + outPos.y() * outPos.y()); 91 | float rTime = 1; 92 | if (mAnimValue <= mRotateTime) { 93 | rTime = mAnimValue / mRotateTime; 94 | } else { 95 | float offset = maxRadius * (mAnimValue - mRotateTime) / (1 - mRotateTime); 96 | float newRadius = radius - offset; 97 | if (newRadius < 0) { 98 | newRadius = 0; 99 | } 100 | updatePos(outPos, radius, newRadius); 101 | radius = newRadius; 102 | } 103 | float ratio = radius / maxRadius; 104 | float zOffset = (1 - ratio) * 2 * rTime; 105 | outPos.z(outPos.z() - zOffset * zOffset); 106 | updatePos(outPos, (float) Math.PI * 2 * rTime * (1 - ratio)); 107 | } 108 | 109 | @Override 110 | protected void updateEnd(MagicSurface surface) { 111 | if (mAnimator.isStopped()) { 112 | stop(); 113 | } 114 | } 115 | 116 | private void updatePos(Vec pos, float oldRadius, float newRadius) { 117 | if (newRadius == 0) { 118 | pos.setXY(0, 0); 119 | return; 120 | } 121 | float r = newRadius / oldRadius; 122 | pos.setXY( 123 | pos.x() * r, 124 | pos.y() * r 125 | ); 126 | } 127 | 128 | private void updatePos(Vec pos, float angle) { 129 | if (pos.x() == 0 && pos.y() == 0) { 130 | return; 131 | } 132 | 133 | float r = (float) Math.sqrt(pos.x() * pos.x() + pos.y() * pos.y()); 134 | float a0; 135 | int index = getIndex(pos); 136 | if (index < 0) { 137 | a0 = getA(pos); 138 | } else { 139 | a0 = (float) Math.asin(pos.x() / r); 140 | if (a0 > 0) { 141 | if (index > 0) { 142 | a0 = (float) Math.PI - a0; 143 | } 144 | } else { 145 | if (index == 3) { 146 | a0 = (float) Math.PI * 2 + a0; 147 | } else { 148 | a0 = (float) Math.PI - a0; 149 | } 150 | } 151 | } 152 | float a1 = a0 + angle; 153 | 154 | double x = Math.sin(a1) * r; 155 | double y = Math.sqrt((x / Math.sin(a1)) * (x / Math.sin(a1)) - x * x); 156 | pos.setXY((float) x, (float) y); 157 | updatePosWithIndex(pos, getNewIndex(a1)); 158 | } 159 | 160 | private int getNewIndex(double angle) { 161 | return ((int) (angle / ((float) Math.PI / 2))) % 4; 162 | } 163 | 164 | private void updatePosWithIndex(Vec vec, int index) { 165 | switch (index) { 166 | case 1: 167 | case 2: 168 | vec.y(-vec.y()); 169 | break; 170 | } 171 | } 172 | 173 | private int getIndex(Vec pos) { 174 | if (pos.x() > 0 && pos.y() > 0) { 175 | return 0; 176 | } else if (pos.x() > 0 && pos.y() < 0) { 177 | return 1; 178 | } else if (pos.x() < 0 && pos.y() < 0) { 179 | return 2; 180 | } else if (pos.x() < 0 && pos.y() > 0) { 181 | return 3; 182 | } else { 183 | return -1; 184 | } 185 | } 186 | 187 | private float getA(Vec pos) { 188 | if (pos.x() == 0) { 189 | if (pos.y() > 0) { 190 | return 0; 191 | } else { 192 | return (float) Math.PI; 193 | } 194 | } else { 195 | if (pos.x() > 0) { 196 | return (float) Math.PI / 2; 197 | } else { 198 | return (float) Math.PI * 3 / 2; 199 | } 200 | } 201 | } 202 | 203 | private float getRadius(SurfaceModel model, int x, int y) { 204 | ReusableVec pos = VecPool.get(3); 205 | try { 206 | model.getPosition(x, y, pos); 207 | return (float) Math.sqrt(pos.x() * pos.x() + pos.y() * pos.y()); 208 | } finally { 209 | pos.free(); 210 | } 211 | } 212 | 213 | } 214 | -------------------------------------------------------------------------------- /app/src/main/java/com/gplibs/magic_surface_view_sample/updater/WaveAnimUpdater.java: -------------------------------------------------------------------------------- 1 | package com.gplibs.magic_surface_view_sample.updater; 2 | 3 | import com.gplibs.magic_surface_view_sample.common.Direction; 4 | import com.gplibs.magic_surface_view_sample.common.FloatValueAnimator; 5 | import com.gplibs.magic_surface_view_sample.common.AnimHelper; 6 | import com.gplibs.magicsurfaceview.MagicSurface; 7 | import com.gplibs.magicsurfaceview.MagicSurfaceModelUpdater; 8 | import com.gplibs.magicsurfaceview.Vec; 9 | 10 | /** 11 | * WaveAnimUpdater 将 model 中的每个点按PI范围内正弦波移动。 12 | * 并在移动过程中修改透明度。 13 | */ 14 | public class WaveAnimUpdater extends MagicSurfaceModelUpdater { 15 | 16 | // 每个点移动所需时间占整个动画时间的比例 17 | private final float MOVING_TIME = 0.3f; 18 | 19 | // 是否为隐藏动画 20 | private boolean mIsHide; 21 | // 动画方向 22 | private int mDirection; 23 | 24 | private FloatValueAnimator mAnimator; 25 | private AnimHelper mAnimHelper; 26 | private boolean mIsVertical; 27 | private boolean mRangeOfSelf; 28 | 29 | public WaveAnimUpdater(boolean isHide, int direction, boolean rangeOfSelf) { 30 | mIsHide = isHide; 31 | mDirection = direction; 32 | mRangeOfSelf = rangeOfSelf; 33 | 34 | mAnimator = new FloatValueAnimator(600); 35 | mAnimator.addListener(new FloatValueAnimator.FloatValueAnimatorListener() { 36 | @Override 37 | public void onAnimationUpdate(float value) { 38 | mAnimHelper.update(value); 39 | // 通知框架,数据改变,可以调用 update 方法进行更新 40 | notifyChanged(); 41 | } 42 | 43 | @Override 44 | public void onStop() { 45 | // 通知框架,数据改变,可以调用 update 方法进行更新 46 | notifyChanged(); 47 | } 48 | }); 49 | } 50 | 51 | // 在绘制第一帧之前调用 (可以在此方法里进行一些初始化操作) 52 | @Override 53 | protected void willStart(MagicSurface surface) { 54 | mAnimHelper = new AnimHelper(surface, mDirection, mIsHide); 55 | mIsVertical = Direction.isVertical(mDirection); 56 | } 57 | 58 | // 在开始绘制后调用(绘制第一帧后调用,一般动画可以在此开始) 59 | @Override 60 | protected void didStart(MagicSurface surface) { 61 | mAnimator.start(!mIsHide); 62 | } 63 | 64 | // 当调用Updater 的 stop() 方法之后,真正停止后会回调此方法 65 | @Override 66 | protected void didStop(MagicSurface surface) { 67 | mAnimator.stop(); 68 | } 69 | 70 | @Override 71 | protected void updateBegin(MagicSurface surface) { 72 | 73 | } 74 | 75 | /** 76 | * 修改网格模型 r行, c列处 的坐标及颜色, 修改后的值存到 outPos 和 outColor 77 | * (只需要修改网格模型各行各列点及可,点与点之间的坐标和颜色由 openGL 自动进行插值计算完成) 78 | * 注:此方法执行频率非常高;一般不要有分配新的堆内存的逻辑,会频繁产生gc操作影响性能,可以使用全局变量或者ReusableVec、VecPool 79 | * 80 | * @param surface 81 | * @param r 行 82 | * @param c 列 83 | * @param outPos 默认值为 r行c列点包含偏移量的原始坐标, 计算完成后的新坐标要更新到此变量 84 | * @param outColor 默认值为 rgba(1,1,1,1), 计算完成后的新颜色要更新到此变量 85 | */ 86 | @Override 87 | protected void updatePosition(MagicSurface surface, int r, int c, Vec outPos, Vec outColor) { 88 | float startTime = mAnimHelper.getStartAnimTime(outPos, false, (1 - MOVING_TIME)); 89 | float offset = mAnimHelper.getMoveDistance(mRangeOfSelf ? AnimHelper.MOVE_TYPE_SELF : AnimHelper.MOVE_TYPE_SCENE, startTime, MOVING_TIME); 90 | if (mIsVertical) { 91 | outPos.y(outPos.y() + offset); 92 | } else { 93 | outPos.x(outPos.x() + offset); 94 | } 95 | float ratio = mAnimHelper.getAnimProgress(startTime, MOVING_TIME); 96 | outPos.z((float) Math.sin(Math.PI * ratio) / 2); 97 | outColor.a(1 - ratio); 98 | } 99 | 100 | @Override 101 | protected void updateEnd(MagicSurface surface) { 102 | if (mAnimator.isStopped()) { 103 | // 调用 stop 方法,通知框架开始停止此 updater, 停止后会调用 didStop 方法。 104 | stop(); 105 | } 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dark_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/surface_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_launch.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 17 | 18 | 32 | 33 |