編輯:關於Android編程
一個安卓開發的朋友發我一個視頻並向詢問我視頻中效果怎麼實現,我當即給他說 ,這個簡單,用幀動畫就可以實現。然後就被他pass掉了,於是我只好祭出plan B。但是我當時沒有時間,於是一邊坐地鐵一邊發語音給他說步驟(導致樓主本打算做到漕河泾一不小心做到了徐家匯,然後掉頭往漕河泾做的時候發現既然到了徐家匯,就在徐家匯轉車最近,於是趕緊調轉車頭,再往徐家匯做)。做完之後覺得只要思路對了就很簡單,於是給大家分享一下思路
按照慣例,先上效果圖,然後將關鍵代碼和思路,下面是效果圖
demo下載地址 demo下載地址
如何寫一個復雜的自定義控件呢,筆者一般采用MVC模式,即是模型(model)-視圖(view)-控制器(controller),而之前筆者寫的兩個自定義控件裡均采用了這個方法,下面放上兩個實例,大家有興趣的也可以參考下
示例一,自定義日歷控件 自定義的日歷控件
實例二 ,會在點擊附近產生四處擴散的類似水珠沸騰的效果demo下載
在本篇文章筆者則一開頭的效果圖為例為大家講解如何以mvc方式寫自定義控件
我們怎麼把自定義控件變得簡單呢,首先就是把復雜的自定義控件分解為單個對象,下面我門就針對效果把他分解,看下圖
首先我們根絕圖可以把圖中的效果分為兩個部分,分別在圖中以箭頭標出,第一部分就是錢袋,第二部分就是單個的錢幣
首先我們分別對兩者進行分析,
我們通過效果圖可知,錢袋就是一張不懂的圖,我們只需要畫一張錢袋作為背景就OK了
錢幣才是這個自定義空間控件的關鍵,乍看之下使人眼花缭亂,但是我們一一個錢幣作為對象的話就會變的很簡單了,下面我們針對錢幣的對象進行分析
/** * 錢的對象 * Created by 玉光 on 2016-8-29. */ public class Money {
y=a*(x-b)^2+c;而確定一個拋物線則需要頂點坐標和另外一個坐標,而a則代表了拋物線的傾斜度,因此 需要一個頂點坐標和a屬性 最後再定義每次的水平移動的舉例,然後根據y=a*(x-b)^2+c計算出y坐標。
分析過後聲明變量
/**
* 錢幣的x坐標
*/
public float locationX;
/**
* 錢幣的y坐標
*/
public float locationY;
/**
* 錢幣的類型
*/
public int type;
/**
* 移動的距離
*/
public int distance;
/**
* 拋物線的頂點
*/
public Point fixedPoint;
/**
* 確定拋物線的路線的參數,即 y=a*(x-b)^2+c 裡面的參數a
*/
public float a;
定義構造函數,
public Money(float x, float y) {
fixedPoint = new Point();
this.locationX = x;
this.locationY = y;
type = (int) (Math.random() * 3);
fixedPoint.x =(int) ((Math.random() + 0.5f) * x);
fixedPoint.y = (int) ((Math.random() + 1) * y / 3);
distance = (int) ((fixedPoint.x - x) / 5);
if (distance==0){
updateDistance();
}
//因為 y=a*(x-b)^2+c ,b就等於拋物線定點x的左邊,c就等於拋物線頂點y的坐標,所以a=(y-c)/(x-b)^2
a = (y - fixedPoint.y) / ((x - fixedPoint.x) * (x - fixedPoint.x));
}
其中x,y代表錢幣的初始位置,是要我們決定的,所以需要傳入,頂點和類型為了顯示多變性則為隨機產生,其他的則是由定點,初始位置計算出來的。
定義方法
為了能使錢幣出現移動的效果,我們定義一個移動位置的方法
/**
* 更新圖片坐標的方法,每次x坐標移動distance,y經過拋物線算出
*/
public void updateLocation() {
locationX += distance;
locationY = a * (locationX - fixedPoint.x) * (locationX - fixedPoint.x) + fixedPoint.y;
}
x每次移動distance位置,y則有拋物線公式根據x計算出來
為了使模型和view分開,我們再定義一個畫的方法
/**
* 畫錢幣的函數
*
* @param canvas
* @param a 錢幣a的圖像
* @param b 錢幣b的圖像
* @param c 錢幣c的圖像
* @param paint 畫筆
*/
public void drawMoney(Canvas canvas, Bitmap a, Bitmap b, Bitmap c, Paint paint) {
switch (type) {
case 0:
canvas.drawBitmap(a, locationX, locationY, paint);
break;
case 1:
canvas.drawBitmap(b, locationX, locationY, paint);
break;
case 2:
canvas.drawBitmap(c, locationX, locationY, paint);
break;
}
}
我們建立控制類
聲明一個moneymanager類
/**
* 錢幣的管理類
* Created by 玉光 on 2016-8-29.
*/
public class MoneyManager {
定義兩個函數,一個是產生十個錢幣對象集合的方法,另外一個是更新集合內數據的方法
/**
* 產生儲存十個錢對象的集合
* @param x
* @param y
* @return
*/
public static List createMoney( float x, float y) {
moneys = new ArrayList<>();
Money money = null;
for (int i = 0; i < 10; i++) {
money = new Money(x, y);
moneys.add(money);
}
return moneys;
}
/**
* 更新儲存錢對象的集合
* @param moneys
* @param view
* @param x
* @param y
* @return
*/
public static List updateMoneys(List moneys, View view, float x, float y) {
List moneyList=new ArrayList<>();
int width =view.getMeasuredWidth();
int height =view.getMeasuredHeight();
//更新集合裡面每個對象的坐標
for (Money money : moneys) {
money.updateLocation();
//如果對象的范圍還在控件內,則添加,不在則扔掉
if (money.locationX>0&&money.locationX0&&money.locationY這樣就可以更新money的坐標了
建立View對象
首先創建moneyview對象
/**
* 撒錢的試圖
* Created by 玉光 on 2016-8-29.
*/
public class MoneyView extends View {
初始化集合
//初始化集合
moneys = MoneyManager.createMoney(width / 2, height / 2 - moneyCationHeight / 10);
重寫ondraw方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//畫錢袋
canvas.drawBitmap(moneyCationScale, width / 2 - moneyCationWidth / 10, height / 2 - moneyCationHeight / 10, paint);
//如果集合裡沒有內容就不在進行繪制
if (moneys.size() <= 0) {
//添加動畫結束監聽
if (listener != null) {
listener.onEnd();
}
} else {
//如果集合裡有內容字繪制集合,
for (int i = 0; i < moneys.size(); i++) {
moneys.get(i).drawMoney(canvas, money, money1, money2, paint);
}
//更新集合裡面錢的坐標位置
moneys = MoneyManager.updateMoneys(moneys, this, width / 2 - moneyWidth / 2, height / 2 - moneyCationHeight / 10 - moneyHeight / 2);
//延時50毫秒重新繪制
postInvalidateDelayed(50);
}
}
好了一個自定義控件基本上算是完成了,最後添加結束監聽
/**
* 結束監聽的接口
*/
public interface OnEndListener {
void onEnd();
}
private OnEndListener listener;
/**
* 設置結束監聽
*
* @param listener
*/
public void SetOnEndListener(OnEndListener listener) {
this.listener = listener;
}
總結
一個復雜的動畫就這樣被我們完成了,復雜類型的自定控件最重要的對象的分析,首先把無關緊要的剝離出去,然後在確定對象,在寫對象過程中要確定哪些屬性是需要我們進行控制的以達到動畫的效果,然後建立控制類,更新我們需要控制的屬性,最後只需在view裡面遍歷集合,並調用繪制方法就可以了。
下面是自定義控件的結構圖
作者有時間的時候會幫同行們實現一些網上不容易找到效果,如果你也需要幫助,不妨私信一下作者,歡迎大家一起交流和進步!
Intent組件雖然不是四大組件,但卻是連接四大組件的橋梁,學習好這個知識,也非常的重要。一、什麼是Intent1、Intent的概念:Android中提供了Intent
1、一個應用通過ContentObserver來觀察自己所監聽的數據(某個特定的URI)是否發生了變化2、ContentObserver放在Activity中。Coten
Motion SensorsAndroid平台提供了多種感應器,讓你監控設備的運動。這些傳感器的兩個總是基於硬件的(加速度計和陀螺儀),並且可以要麼基於硬件或基於軟件的這
關鍵詞:藍牙硬件接口 UART PCM blueZ 版本:基於android4.2之前版本 bluez內核:linux/linux3.08系統:android/and