手机画面内容结合魔术手法在魔术表演中可以达到一种很强的视觉场景冲击,比如手机里的蜘蛛爬出来的魔术,这里做一个简易的app,
首先找到蜘蛛的png图片,多做几张可以实现更好的爬动效果,这里用一张来试验,把图片中的白色背景转换为透明颜色,
python
from PIL import Image
# 打开图片
img = Image.open('spider0.png')
img = img.convert("RGBA")
datas = img.getdata()
newData = []
for item in datas:
# 如果像素的颜色接近白色,则将其改为完全透明
if item[0] > 240 and item[1] > 240 and item[2] > 240:
newData.append((255, 255, 255, 0))
else:
newData.append(item)
img.putdata(newData)
img.save("spider.png", "PNG")
app例子
java
package com.example.magic;
import androidx.appcompat.app.AppCompatActivity;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.os.Bundle;
// app/src/main/java/com/example/spiderphoto/MainActivity.java
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
public class MainActivity extends AppCompatActivity {
private static final int REQUEST_CAMERA_PERMISSION = 100;
private static final int REQUEST_IMAGE_CAPTURE = 101;
private ImageView imageView;
private View spiderView;
private Button btnTakePhoto;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = findViewById(R.id.imageView);
spiderView = findViewById(R.id.spiderView);
btnTakePhoto = findViewById(R.id.btnTakePhoto);
btnTakePhoto.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (checkCameraPermission()) {
dispatchTakePictureIntent();
} else {
requestCameraPermission();
}
}
});
}
private boolean checkCameraPermission() {
return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_GRANTED;
}
private void requestCameraPermission() {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA},
REQUEST_CAMERA_PERMISSION);
}
private void dispatchTakePictureIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
dispatchTakePictureIntent();
} else {
Toast.makeText(this, "需要相机权限才能拍照", Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
// 显示照片
imageView.setImageBitmap(imageBitmap);
imageView.setVisibility(View.VISIBLE);
btnTakePhoto.setVisibility(View.GONE);
// 启动蜘蛛动画
startSpiderCrawl();
}
}
private void startSpiderCrawl00() {
ImageView spider = findViewById(R.id.spiderView);
spider.setVisibility(View.VISIBLE);
// 获取屏幕高度(用于计算移动距离)
int screenHeight = getResources().getDisplayMetrics().heightPixels;
// 1. 主动画:垂直向上移动(从底部到顶部外)
ObjectAnimator moveUp = ObjectAnimator.ofFloat(
spider, "translationY",
screenHeight - spider.getHeight(), // 起点:底部(减去自身高度)
-spider.getHeight() * 1.2f // 终点:顶部上方完全消失
);
moveUp.setDuration(8000);
// 2. 辅助动画:左右轻微晃动(模拟爬行时的身体摆动)
ObjectAnimator sway = ObjectAnimator.ofFloat(spider, "translationX", 0f, -20f, 0f, 20f, 0f);
sway.setDuration(8000);
sway.setRepeatCount(ObjectAnimator.INFINITE); // 循环晃动
// 3. 轻微缩放(模拟腿部蹬地的弹跳感)
ObjectAnimator bounce = ObjectAnimator.ofFloat(spider, "scaleY", 1.0f, 1.1f, 1.0f, 0.95f, 1.0f);
bounce.setDuration(800);
bounce.setRepeatCount(ObjectAnimator.INFINITE);
bounce.setRepeatMode(ObjectAnimator.REVERSE);
// 同时播放三个动画
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(moveUp, sway, bounce);
animatorSet.start();
// 动画结束后清理
moveUp.addListener(new android.animation.AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(android.animation.Animator animation) {
spider.setVisibility(View.INVISIBLE);
sway.cancel();
bounce.cancel();
btnTakePhoto.setVisibility(View.VISIBLE);
}
});
}
private void startSpiderCrawl() {
spiderView.setVisibility(View.VISIBLE);
// 创建从底部到顶部的平移动画
TranslateAnimation animation = new TranslateAnimation(
Animation.RELATIVE_TO_PARENT, 0f,
Animation.RELATIVE_TO_PARENT, 0f,
Animation.RELATIVE_TO_PARENT, 0.5f, // 起点:底部
Animation.RELATIVE_TO_PARENT, -1.2f // 终点:顶部上方(完全消失)
);
animation.setDuration(8000); // 8秒
animation.setFillAfter(true);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
spiderView.setVisibility(View.INVISIBLE);
btnTakePhoto.setVisibility(View.VISIBLE); // 恢复按钮
}
@Override
public void onAnimationRepeat(Animation animation) {}
});
spiderView.startAnimation(animation);
}
}