編輯:關於Android編程
這本是一個愉快的季節,但是,呵呵,胡扯! 因為這篇文章的發表時間是2015年的聖誕節,所以我們需要給Style Android用制造出一些節日氣氛。感謝讀者們,因為有的讀者可能沒有在慶祝聖誕,有些讀者可能還是6月份。
那麼問題來了,我們應該做些什麼來讓這個節日像是真正的節日呢? 最簡單的方法:帶上聖誕帽,拍個照。
但是我感覺這個圖片有些單調,所以來弄點雪花,讓雪花飄下來。
我們可以添加一個包含這個圖片的自定義View
res/layout/activity_main.xml
<code class="hljs xml"><!--{cke_protected}{C}%3C!%2D%2D%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%2D%2D%3E--> <relativelayout android:layout_height="match_parent" android:layout_width="match_parent" tools:context="com.stylingandroid.snowfall.MainActivity" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <imageview android:contentdescription="@null" android:id="@+id/image" android:layout_centerinparent="true" android:layout_height="match_parent" android:layout_width="match_parent" android:scaletype="fitCenter" android:src="@drawable/tree"> <com.stylingandroid.snowfall.snowview android:layout_alignbottom="@id/image" android:layout_alignend="@id/image" android:layout_alignleft="@id/image" android:layout_alignright="@id/image" android:layout_alignstart="@id/image" android:layout_aligntop="@id/image" android:layout_height="match_parent" android:layout_width="match_parent"> </com.stylingandroid.snowfall.snowview></imageview></relativelayout></code>
盡管可以通過繼承ImageView來實現自定義View,但我決定將 SnowView
和圖片分開,這樣每次刷新動畫的時候不用重新渲染圖片,只刷新 SnowView
就行了
SnowView.java
public class SnowView extends View {
private static final int NUM_SNOWFLAKES = 150;
private static final int DELAY = 5;
private SnowFlake[] snowflakes;
public SnowView(Context context) {
super(context);
}
public SnowView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SnowView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
protected void resize(int width, int height) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.FILL);
snowflakes = new SnowFlake[NUM_SNOWFLAKES];
for (int i = 0; i < NUM_SNOWFLAKES; i++) {
snowflakes[i] = SnowFlake.create(width, height, paint);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w != oldw || h != oldh) {
resize(w, h);
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (SnowFlake snowFlake : snowflakes) {
snowFlake.draw(canvas);
}
getHandler().postDelayed(runnable, DELAY);
}
private Runnable runnable = new Runnable() {
@Override
public void run() {
invalidate();
}
};
}
代碼很簡單。 在View 的 onSizeChanged
方法中初始化 150 個隨機位置的雪花對象。 在onDraw
方法中畫出雪花,然後每隔一段時間就刷新一下位置,需要注意的是onDraw
沒有立即去執行,而是通過創建一個runnable,這樣不會阻塞UI線程
雪花下落是基於Samuel Arbesman的雪花下落的算法。
SnowFlake.java
class SnowFlake {
private static final float ANGE_RANGE = 0.1f;
private static final float HALF_ANGLE_RANGE = ANGE_RANGE / 2f;
private static final float HALF_PI = (float) Math.PI / 2f;
private static final float ANGLE_SEED = 25f;
private static final float ANGLE_DIVISOR = 10000f;
private static final float INCREMENT_LOWER = 2f;
private static final float INCREMENT_UPPER = 4f;
private static final float FLAKE_SIZE_LOWER = 7f;
private static final float FLAKE_SIZE_UPPER = 20f;
private final Random random;
private final Point position;
private float angle;
private final float increment;
private final float flakeSize;
private final Paint paint;
public static SnowFlake create(int width, int height, Paint paint) {
Random random = new Random();
int x = random.getRandom(width);
int y = random.getRandom(height);
Point position = new Point(x, y);
float angle = random.getRandom(ANGLE_SEED) / ANGLE_SEED * ANGE_RANGE + HALF_PI - HALF_ANGLE_RANGE;
float increment = random.getRandom(INCREMENT_LOWER, INCREMENT_UPPER);
float flakeSize = random.getRandom(FLAKE_SIZE_LOWER, FLAKE_SIZE_UPPER);
return new SnowFlake(random, position, angle, increment, flakeSize, paint);
}
SnowFlake(Random random, Point position, float angle, float increment, float flakeSize, Paint paint) {
this.random = random;
this.position = position;
this.angle = angle;
this.increment = increment;
this.flakeSize = flakeSize;
this.paint = paint;
}
private void move(int width, int height) {
double x = position.x + (increment * Math.cos(angle));
double y = position.y + (increment * Math.sin(angle));
angle += random.getRandom(-ANGLE_SEED, ANGLE_SEED) / ANGLE_DIVISOR;
position.set((int) x, (int) y);
if (!isInside(width, height)) {
reset(width);
}
}
private boolean isInside(int width, int height) {
int x = position.x;
int y = position.y;
return x >= -flakeSize - 1 && x + flakeSize <= width && y >= -flakeSize - 1 && y - flakeSize < height;
}
private void reset(int width) {
position.x = random.getRandom(width);
position.y = (int) (-flakeSize - 1);
angle = random.getRandom(ANGLE_SEED) / ANGLE_SEED * ANGE_RANGE + HALF_PI - HALF_ANGLE_RANGE;
}
public void draw(Canvas canvas) {
int width = canvas.getWidth();
int height = canvas.getHeight();
move(width, height);
canvas.drawCircle(position.x, position.y, flakeSize, paint);
}
}
初始化的時候,雪花的隨機位置就已經確定了。這是為了確保雪花不會每次畫的時候都在開始的位置。當一個雪花的位置超出Canvas的邊界之後,它就會被重新放到頂部的一個隨機位置,這樣就可以循環利用了,避免了重復創建。
當畫雪花下落的每一幀的時候,我們首先給SnowFlake
添加一個隨機數來改變位置,這樣可以模仿有小風吹雪花。
在把雪花畫到canvas上之前,我們會進行邊界檢查(如果需要的話,超出邊界的就重新放到頂部)
我一直在不斷的調整裡面的常量來改變下雪的效果直到我感覺滿意為止。
當然了,在canvas裡面塞這麼多東西不是一個好的方法(有其他更好的 比如OpenGL),但是,我現在要去吃火雞了,所以可能要等下一次了。
可移動頁面MoveActivity滑出式菜單從界面上看,像極了一個水平滾動視圖HorizontalScrollView,當然也可以使用HorizontalScrollVi
效果圖: 核心代碼: package com.zms.toast; import android.app.Dialog; import
自定義View控件, 算是常見的用法. 剛接觸安卓開發的時候, 很多人習慣在不同的XML布局文件裡面Copy一大段代碼, 達到相同View不斷被使用的效果,但如果以後要改
前言相信大家都知道知道,在AndroidOS中,提供了五中數據存儲方式,分別是:ContentProvider存儲、文件存儲、SharedPreference存儲、SQL