ChristmasTreeView.java
package com.example.redpacket;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;public class ChristmasTreeView extends View {private Paint paint;private int x, y; // 坐标private boolean isRunning = false; // 控制动画开关public ChristmasTreeView(Context context, AttributeSet attrs) {super(context, attrs);paint = new Paint();paint.setColor(Color.GREEN);x = 380; // 树的基本横坐标y = 100; // 树的起始纵坐标}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);drawTree(canvas);}private void drawTree(Canvas canvas) {// 绘制每一层三角形drawTriangle(canvas, 1, 4); // 第一层(顶部)drawTriangle(canvas, 3, 6); // 第二层drawTriangle(canvas, 5, 8); // 第三层drawTriangle(canvas, 7, 10); // 第四层drawTriangle(canvas, 9, 12); // 第五层// 绘制树根drawRoot(canvas);}private void drawTriangle(Canvas canvas, int from, int to) {int baseWidth = 20; // 每层的基础宽度for (int i = from; i <= to; i++) {paint.setColor(Color.rgb(9, 124, 37)); // 树绿色int currentWidth = (i * 2 - 1) * baseWidth; // 当前层的宽度计算// 绘制三角形for (int j = 0; j < currentWidth; j += baseWidth) {canvas.drawRect(x - currentWidth / 2 + j, y, x - currentWidth / 2 + j + baseWidth, y + baseWidth, paint);}y += baseWidth; // 向下移动}x = 380; // 重置 x 以对齐}private void drawRoot(Canvas canvas) {paint.setColor(Color.rgb(131, 78, 0)); // 棕色根部x = 380 - 22; // 重置 x 以对齐树根y += 10; // 向下调整根部位置(根据需要调整)// 绘制根for (int i = 0; i < 4; i++) { // 根部高度for (int j = 0; j < 3; j++) { // 根部宽度canvas.drawRect(x, y, x + 20, y + 20, paint);x += 22; // 向右移动画出根部的部分}x = 380 - 22; // 确保根部对齐y += 20; // 向下移动}}public void toggleAnimation() {isRunning = !isRunning;invalidate(); // 请求重绘}public boolean isRunning() {return isRunning;}
}
main
package com.example.redpacket;import android.graphics.BitmapFactory;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;import androidx.appcompat.app.AppCompatActivity;import java.util.ArrayList;
import java.util.List;
import java.util.Random;public class MainActivity extends AppCompatActivity {private Button onOffButton;private MediaPlayer mediaPlayer;private RelativeLayout mainLayout; // 主要布局private List<ImageView> redPacketImages = new ArrayList<>(); // 红包列表private boolean isRunning = false; // 是否显示红包雨@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);onOffButton = findViewById(R.id.on_off_button);mediaPlayer = MediaPlayer.create(this, R.raw.music);mainLayout = findViewById(R.id.main_layout); // 获取主布局onOffButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (isRunning) {stopRedPacketRain();onOffButton.setText("Start Red Packet Rain");} else {startRedPacketRain();onOffButton.setText("Stop Red Packet Rain");}}});}private void startRedPacketRain() {isRunning = true;mediaPlayer.start();mediaPlayer.setLooping(true);final int screenWidth = mainLayout.getWidth();// 创建红包降落线程new Thread(new Runnable() {@Overridepublic void run() {while (isRunning) {runOnUiThread(new Runnable() {@Overridepublic void run() {createRedPacket(screenWidth);}});try {Thread.sleep(200); // 控制生成红包的速度} catch (InterruptedException e) {e.printStackTrace();}}}}).start();}private void createRedPacket(int screenWidth) {ImageView imageView = new ImageView(MainActivity.this);imageView.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.red_packet));RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(100, 100);// 将大小改为100x100layoutParams.topMargin = -100; // 从上方开始layoutParams.leftMargin = new Random().nextInt(screenWidth - 100);imageView.setLayoutParams(layoutParams);mainLayout.addView(imageView); // 添加红包视图redPacketImages.add(imageView);moveRedPacket(imageView);}private void moveRedPacket(final ImageView imageView) {new Thread(new Runnable() {@Overridepublic void run() {int currentY = -50; // 开始位置final int screenHeight = ((RelativeLayout) imageView.getParent()).getHeight();while (currentY < screenHeight && isRunning) {int finalCurrentY = currentY;runOnUiThread(new Runnable() {@Overridepublic void run() {RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) imageView.getLayoutParams();params.topMargin = finalCurrentY;imageView.setLayoutParams(params);}});currentY += 10; // 每次移动10像素try {Thread.sleep(50); // 每50毫秒更新位置} catch (InterruptedException e) {e.printStackTrace();}}runOnUiThread(new Runnable() {@Overridepublic void run() {if (redPacketImages.contains(imageView)) {imageView.setVisibility(View.GONE);redPacketImages.remove(imageView);}}});}}).start();}private void stopRedPacketRain() {isRunning = false;mediaPlayer.stop();mediaPlayer.reset();mediaPlayer.release();for (ImageView imageView : redPacketImages) {imageView.setVisibility(View.GONE);}redPacketImages.clear();}
}
xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/main_layout"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/on_off_button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="Start Red Packet Rain"/><com.example.redpacket.ChristmasTreeViewandroid:id="@+id/christmas_tree_view"android:layout_width="match_parent"android:layout_height="685dp"android:layout_below="@id/on_off_button"android:layout_gravity="center"android:layout_marginTop="69dp" />
</RelativeLayout>