直接上图,GIF制作太麻烦了。
就是上面的雪花会慢慢飘落,但是不影响下面的点击事件,效果全凭想象。😁
首先说明一下,下面就是一张截的京东首页图,然后上面的雪花是使用SurfaceView来制作的,为了模拟点击事件,在SurfaceView下面放了一个按钮用来测试事件分发。
SurfaceView
在Android系统中,有一种特殊的视图,称为SurfaceView,它拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面。由于拥有独立的绘图表面,因此SurfaceView的UI就可以在一个独立的线程中进行绘制。又由于不会占用主线程资源,SurfaceView一方面可以实现复杂而高效的UI,另一方面又不会导致用户输入得不到及时响应。
摘自https://blog.csdn.net/luoshengyang/article/details/8661317/,老罗的博客详细介绍了SurfaceView实现原理。
总结下来就是使用SurfaceView可以在一个单独的线程去更新UI,那么既然在单独的线程更新UI,那就肯定不会影响主线程了,所以说SurfaceView非常适合这种雪花效果了。
创建Activity的布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/jd"/>
<TextView
android:id="@+id/tv_test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="250dp"
android:layout_marginTop="250dp"
android:textColor="#000"
android:textStyle="bold"
android:textSize="30sp"
android:text="点我测试点击事件"
/>
<wanda.com.androiddemo.MySurfaceView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
MySurfaceView.java
public static final String TAG = "MySurfaceView";
private SurfaceHolder mHolder;
private Thread mThread;
private Canvas mCanvas;
private boolean bIsRunning = false;
private List<Snow> mSnowList = new ArrayList<>();
private static final int snowCount = 16;
private Paint mPaint;
private Bitmap mBitmap;
public MySurfaceView(Context context) {
this(context, null);
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
Log.d(TAG, "init");
setZOrderOnTop(true);
getHolder().setFormat(PixelFormat.TRANSLUCENT);
// 从父类SurfaceView中获取到SurfaceHolder,然后通过SurfaceHolder来添加监听,
// 监听SurfaceView的生命周期,也就是下面的三个方法
mHolder = getHolder();
mHolder.addCallback(this);
// 设置获得焦点
setFocusable(true);
setFocusableInTouchMode(true);
// 设置常亮
setKeepScreenOn(true);
//初始化雪花
for(int i=0;i<snowCount;i++){
int randomT = (int) (Math.random()*30000);
int x = (int) (Math.random()*1080);
Log.d(TAG,"randomT is "+randomT+" and x is "+x);
Snow snow = new Snow(60,0,x,-50,System.currentTimeMillis()+randomT);
mSnowList.add(snow);
}
mBitmap = decodeSampledBitmapFromResource(getResources(),R.mipmap.snow,50,50);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "surfaceCreated");
Log.d(TAG, "surfaceCreated Thread Name is " + Thread.currentThread().getId());
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
bIsRunning = true;
mThread = new Thread(this);
mThread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void run() {
while (bIsRunning){
// 通过SurfaceHolder获取canvas
try {
mCanvas = mHolder.lockCanvas();
// 拿到canvas不就可以想干啥就干啥了
if (mCanvas != null) {
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
for(int i=0;i<snowCount;i++){
Snow snow = mSnowList.get(i);
double t = System.currentTimeMillis() - snow.startTime;
if(t<=0){
continue;
}
double time =t/1000;
int x = (int) (snow.startX+time*snow.hor_v);
int y = (int) (snow.startY+time*snow.ver_v);
if(y>1920){
snow.startTime = System.currentTimeMillis();
}
Bitmap bitmap = rotateBitmap(mBitmap,10*i);
mCanvas.drawBitmap(bitmap,x,y,mPaint);
}
}
} catch (Exception e) {
Log.d(TAG,"e is "+e.getMessage());
} finally {
if (mCanvas != null) {
Log.d(TAG,"unlockCanvasAndPost");
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "surfaceDestroyed");
bIsRunning = false;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
return false;
}
private Bitmap rotateBitmap(Bitmap origin, float dgress) {
Bitmap newBM=null;
try {
if (origin == null) {
return null;
}
int width = origin.getWidth();
int height = origin.getHeight();
Matrix matrix = new Matrix();
matrix.setRotate(dgress);
// 围绕原地进行旋转
newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);
if (newBM.equals(origin)) {
return newBM;
}
}
catch (Exception e){
Log.d(TAG,"e is "+e.getMessage());
}
return newBM;
}
private Bitmap decodeSampledBitmapFromResource(Resources resources,
int resId, int reqWidth, int reqHeight) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(resources, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(resources, resId, options);
}
private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
final int height = options.outHeight;
Log.i(TAG,""+height);
final int width = options.outWidth;
Log.i(TAG,""+width);
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
代码很简单哈,就不解释了。直接show my code for u。