網(wǎng)站首頁 編程語言 正文
一、前言
這個冬天,老家一直沒有下雨, 正好圣誕節(jié),就想著制作一個下雪的特效。
圣誕祝福:平安夜,舞翩阡。雪花飄,飛滿天。心與心,永相伴。
圣誕節(jié)是傳統(tǒng)的宗教節(jié)日,對于基 督徒,那是慶祝耶穌的誕生,紀(jì)念耶穌和發(fā)揚基督精神。現(xiàn)在整個西方社會都在過圣誕節(jié),像許多宗教節(jié)日一樣,它已經(jīng)越來越民俗化了。
盡管如此,圣誕節(jié)依然倍受尊重。人們在圣誕快樂中懷有對耶穌的敬仰,歡樂的節(jié)慶里含有莊嚴(yán)肅穆的神念。歡度圣誕佳節(jié)的人都不拒絕耶穌的教誨,要仁愛、善良、誠實、忍耐、感恩……在信神的國度,不是基 督徒的人們,也都知道人應(yīng)該感恩,心存謝意。對需要幫助的人給予關(guān)愛;對他人的幫助給予感謝。這是西方社會價值觀的一部份,而不是說圣誕夜就只是一家坐在壁爐前,共進(jìn)有火雞或烤鵝的圣誕大餐或是冬季里開的一個最熱鬧的大派對。
二、創(chuàng)意名
Android實現(xiàn)雪花特效自定義view
三、效果展示
四、實現(xiàn)步驟
1.創(chuàng)建一個view,里面加載雪花類的集合,有一個死循環(huán)線程,一直執(zhí)行動畫
public class myRunnable implements Runnable {
@Override
public void run() {
while (true){
Canvas canvas =null;
try {
synchronized (holder){
canvas = holder.lockCanvas();
//清除畫布
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
for (Snowflake snowflake :list){
snowflake.draw(canvas);
snowflake.update();
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (canvas!=null){
holder.unlockCanvasAndPost(canvas);
}
}
}
}
}
這樣的話,可以讓所有的雪花圖片動起來
2.創(chuàng)建雪花類,其實就是一個bitmap,然后設(shè)置不同尺寸和動畫
這步相對來說簡單一些,其實就是將bitmap繪制到畫布上面
public void reset(){
size = randomizer.randomInt(sizeMinInPx, sizeMaxInPx, true);
if (image!=null){
if (bitmap==null){
bitmap = Bitmap.createScaledBitmap(image, size, size, false);
}
}
float speed = (float)(size - sizeMinInPx) / (sizeMaxInPx - sizeMinInPx) * (speedMax - speedMin) + speedMin;
double angle = Math.toRadians(randomizer.randomDouble(angleMax) * randomizer.randomSignum());
speedX = speed* Math.sin(angle);
speedY = speed* Math.cos(angle);
alpha = randomizer.randomInt(alphaMin, alphaMax, false);
paint.setAlpha(alpha);
positionX = randomizer.randomDouble(parentWidth);
this.positionY=randomizer.randomDouble(parentHeight);
if (!alreadyFalling){
this.positionY = this.positionY-parentHeight-size;
}
}
3.界面展示
實現(xiàn)manifest加載視圖即可
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#000" tools:context="com.marvin.snowfall_master.MainActivity"> <com.itbird.SnowfallView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/sf_snow" app:snowflakesNum="200" app:snowflakeAlphaMin="150" app:snowflakeAlphaMax="255" app:snowflakeAngleMax="5" app:snowflakeSizeMin="2dp" app:snowflakeSizeMax="40dp" app:snowflakeSpeedMin="2" app:snowflakeSpeedMax="10" app:snowflakesFadingEnabled="true" app:snowflakesAlreadyFalling="false" app:snowflakeImage="@mipmap/snowflake" /> </android.support.constraint.ConstraintLayout>
五、編碼實現(xiàn)
界面類SnowfallView
public class SnowfallView extends SurfaceView implements SurfaceHolder.Callback {
private int DEFAULT_SNOWFLAKES_NUM = 200;
private int DEFAULT_SNOWFLAKE_ALPHA_MIN = 150;
private int DEFAULT_SNOWFLAKE_ALPHA_MAX = 250;
private int DEFAULT_SNOWFLAKE_ANGLE_MAX = 10;
private int DEFAULT_SNOWFLAKE_SIZE_MIN_IN_DP = 2;
private int DEFAULT_SNOWFLAKE_SIZE_MAX_IN_DP = 8;
private int DEFAULT_SNOWFLAKE_SPEED_MIN = 2;
private int DEFAULT_SNOWFLAKE_SPEED_MAX = 8;
private boolean DEFAULT_SNOWFLAKES_FADING_ENABLED = false;
private boolean DEFAULT_SNOWFLAKES_ALREADY_FALLING = false;
private int snowflakesNum;
private Bitmap snowflakeImage;
private int snowflakeAlphaMin;
private int snowflakeAlphaMax;
private int snowflakeAngleMax;
private int snowflakeSizeMinInPx;
private int snowflakeSizeMaxInPx;
private int snowflakeSpeedMin;
private int snowflakeSpeedMax;
private boolean snowflakesFadingEnabled;
private boolean snowflakesAlreadyFalling;
//雪花類集合
private ArrayList<Snowflake> list =new ArrayList<>();
private SnowfallView.myRunnable myRunnable = new myRunnable();
private Thread myThread;
private SurfaceHolder holder;
public SnowfallView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context,attrs);
}
private void init(Context context, AttributeSet attributeSet) {
TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.SnowfallView);
snowflakesNum = typedArray.getInt(R.styleable.SnowfallView_snowflakesNum, DEFAULT_SNOWFLAKES_NUM);
snowflakeImage = drawable2Bitmap(typedArray.getDrawable(R.styleable.SnowfallView_snowflakeImage));
snowflakeAlphaMin = typedArray.getInt(R.styleable.SnowfallView_snowflakeAlphaMin, DEFAULT_SNOWFLAKE_ALPHA_MIN);
snowflakeAlphaMax = typedArray.getInt(R.styleable.SnowfallView_snowflakeAlphaMax, DEFAULT_SNOWFLAKE_ALPHA_MAX);
snowflakeAngleMax = typedArray.getInt(R.styleable.SnowfallView_snowflakeAngleMax, DEFAULT_SNOWFLAKE_ANGLE_MAX);
snowflakeSizeMinInPx = typedArray.getDimensionPixelSize(R.styleable.SnowfallView_snowflakeSizeMin, dp2Px(DEFAULT_SNOWFLAKE_SIZE_MIN_IN_DP));
snowflakeSizeMaxInPx = typedArray.getDimensionPixelSize(R.styleable.SnowfallView_snowflakeSizeMax, dp2Px(DEFAULT_SNOWFLAKE_SIZE_MAX_IN_DP));
snowflakeSpeedMin = typedArray.getInt(R.styleable.SnowfallView_snowflakeSpeedMin, DEFAULT_SNOWFLAKE_SPEED_MIN);
snowflakeSpeedMax = typedArray.getInt(R.styleable.SnowfallView_snowflakeSpeedMax, DEFAULT_SNOWFLAKE_SPEED_MAX);
snowflakesFadingEnabled = typedArray.getBoolean(R.styleable.SnowfallView_snowflakesFadingEnabled, DEFAULT_SNOWFLAKES_FADING_ENABLED);
snowflakesAlreadyFalling = typedArray.getBoolean(R.styleable.SnowfallView_snowflakesAlreadyFalling, DEFAULT_SNOWFLAKES_ALREADY_FALLING);
typedArray.recycle();
holder = this.getHolder();
holder.addCallback(this);
//設(shè)置背景為透明
setZOrderOnTop(true);
holder.setFormat(PixelFormat.TRANSPARENT);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//獲取雪花集合
for (int i=0;i<snowflakesNum;i++){
list.add(new Snowflake(w, h, snowflakeImage, snowflakeAlphaMin, snowflakeAlphaMax
, snowflakeAngleMax, snowflakeSizeMinInPx, snowflakeSizeMaxInPx, snowflakeSpeedMin, snowflakeSpeedMax
, snowflakesFadingEnabled, snowflakesAlreadyFalling));
}
}
@Override
protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (changedView==this&&visibility==GONE){
//初始化雪花類
try {
for (Snowflake snowflake :list){
snowflake.reset();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isInEditMode()){
return;
}
}
/**
* dp轉(zhuǎn)px
* @param dp
* @return
*/
private int dp2Px(int dp){
return (int) (dp*getResources().getDisplayMetrics().density);
}
/**
* drawble轉(zhuǎn)Bitmap
* @param drawable
* @return
*/
private Bitmap drawable2Bitmap(Drawable drawable){
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0,0,drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());
drawable.draw(canvas);
return bitmap;
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
if (myThread==null){
myThread = new Thread(myRunnable);
}
if(!myThread.isAlive()){
myThread.start();
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
if (myThread!=null){
myThread.interrupt();
}
}
public class myRunnable implements Runnable {
@Override
public void run() {
while (true){
Canvas canvas =null;
try {
synchronized (holder){
canvas = holder.lockCanvas();
//清除畫布
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
for (Snowflake snowflake :list){
snowflake.draw(canvas);
snowflake.update();
}
}
}catch (Exception e){
e.printStackTrace();
}finally {
if (canvas!=null){
holder.unlockCanvasAndPost(canvas);
}
}
}
}
}
}
雪花類Snowflake
public class Snowflake {
private int parentWidth;
private int parentHeight;
private int alphaMin;
private int alphaMax;
private int angleMax;
private int sizeMinInPx;
private int sizeMaxInPx;
private int speedMin;
private int speedMax;
private Bitmap image;
private boolean fadingEnabled;
private boolean alreadyFalling;
private int size = 0 ;
private int alpha = 255;
private Bitmap bitmap = null;
private double speedX= 0.0;
private double speedY = 0.0;
private double positionX = 0.0;
private double positionY = 0.0;
private final Randomizer randomizer;
private Paint paint;
public Snowflake(int parentWidth, int parentHeight, Bitmap image
,int alphaMin,int alphaMax,int angleMax,int sizeMinInPx,int sizeMaxInPx,
int speedMin,int speedMax,boolean fadingEnabled,boolean alreadyFalling ){
this.parentWidth = parentWidth;
this.parentHeight = parentHeight;
this.alphaMin = alphaMin;
this.alphaMax = alphaMax;
this.angleMax = angleMax;
this.sizeMinInPx = sizeMinInPx;
this.sizeMaxInPx = sizeMaxInPx;
this.speedMin = speedMin;
this.speedMax = speedMax;
this.image = image;
this.fadingEnabled=fadingEnabled;
this.alreadyFalling=alreadyFalling;
randomizer = new Randomizer();
initPaint();
reset();
}
/**
* 初始化畫筆
*/
private void initPaint() {
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.rgb(255,255,255));
paint.setStyle(Paint.Style.FILL);
}
public void reset(double positionY){
size = randomizer.randomInt(sizeMinInPx, sizeMaxInPx, true);
if (image!=null){
if (bitmap==null){
bitmap = Bitmap.createScaledBitmap(image, size, size, false);
}
}
float speed = (float)(size - sizeMinInPx) / (sizeMaxInPx - sizeMinInPx) * (speedMax - speedMin) + speedMin;
double angle = Math.toRadians(randomizer.randomDouble(alphaMax) * randomizer.randomSignum());
if (angle<-1||angle>1){
angle = 0;
}
speedX = speed* Math.sin(angle);
speedY = speed* Math.cos(angle);
alpha = randomizer.randomInt(alphaMin, alphaMax, false);
paint.setAlpha(alpha);
positionX = randomizer.randomDouble(parentWidth);
this.positionY = positionY;
}
public void reset(){
size = randomizer.randomInt(sizeMinInPx, sizeMaxInPx, true);
if (image!=null){
if (bitmap==null){
bitmap = Bitmap.createScaledBitmap(image, size, size, false);
}
}
float speed = (float)(size - sizeMinInPx) / (sizeMaxInPx - sizeMinInPx) * (speedMax - speedMin) + speedMin;
double angle = Math.toRadians(randomizer.randomDouble(angleMax) * randomizer.randomSignum());
speedX = speed* Math.sin(angle);
speedY = speed* Math.cos(angle);
alpha = randomizer.randomInt(alphaMin, alphaMax, false);
paint.setAlpha(alpha);
positionX = randomizer.randomDouble(parentWidth);
this.positionY=randomizer.randomDouble(parentHeight);
if (!alreadyFalling){
this.positionY = this.positionY-parentHeight-size;
}
}
public void update(){
positionX = positionX+speedX;
positionY = positionY+speedY;
if (positionY>parentHeight){
positionY = -(double)size;
reset(positionY);
}
if (fadingEnabled){
paint.setAlpha((int) (alpha * ((float) (parentHeight - positionY) / parentHeight)));
}
}
public void draw(Canvas canvas){
if (bitmap!=null){
canvas.drawBitmap(bitmap,(float)positionX,(float)positionY,paint);
}else {
canvas.drawCircle((float)positionX,(float)positionY,(float)size,paint);
}
}
}
總結(jié)
原文鏈接:https://blog.csdn.net/baobei0921/article/details/128448005
相關(guān)推薦
- 2022-07-10 oracle中的session
- 2022-07-21 linux環(huán)境下執(zhí)行jar與終止
- 2024-03-21 【Spring Boot】Spring Boot 配置文件詳解(application.yml、ap
- 2022-10-27 Python?Pandas中布爾索引的用法詳解_python
- 2022-04-20 超全整理visual?studio快捷鍵使用技巧_相關(guān)技巧
- 2022-11-15 C++構(gòu)造析構(gòu)賦值運算函數(shù)應(yīng)用詳解_C 語言
- 2023-01-31 GraphQL在Django中的使用教程_python
- 2022-09-08 Pytorch中expand()的使用(擴(kuò)展某個維度)_python
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支