自定義View的步驟:
1、自定義View的屬性
2、在View的構(gòu)造方法中獲得我們自定義的屬性
[?3、重寫onMesure ]
4、重寫onDraw
我把3用[]標(biāo)出了,所以說3不一定是必須的,當(dāng)然了大部分情況下還是需要重寫的。
繼承View,實現(xiàn)自己想要的組件,那么需要使用到setMeasuredDimension這個方法,這個方法決定了當(dāng)前View的大小,如果不使用setMeasuredDimension這個方法,那么View的大小將不起作用。
1
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
controlWidth = getWidth();
if (controlWidth != 0) {
setMeasuredDimension(getWidth(), itemNumber * unitHeight);
controlWidth = getWidth();
}
}
2
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
//繪制線條
3
drawLine(canvas);
//繪制數(shù)據(jù)
4
drawList(canvas);
//繪制覆蓋板
5
drawMask(canvas);
}
3
/**
* 繪制線條
*
* @param canvas
*/
private void drawLine(Canvas canvas) {
if (linePaint == null) {
linePaint = new Paint();
linePaint.setColor(lineColor);
//抗鋸齒
linePaint.setAntiAlias(true);
//設(shè)置空心線寬
linePaint.setStrokeWidth(1f);
?}
canvas.drawLine(0, controlHeight / 2 - unitHeight / 2 + 2,
controlWidth, controlHeight / 2 - unitHeight / 2 + 2, linePaint);
canvas.drawLine(0, controlHeight / 2 + unitHeight / 2 - 2,
controlWidth, controlHeight / 2 + unitHeight / 2 - 2, linePaint);
}
4
/**
* 繪制數(shù)據(jù)
*
* @param canvas
*/
private synchronized void drawList(Canvas canvas) {
if (isClearing)
return;
try {
for (ItemObject itemObject : itemList) {
itemObject.drawSelf(canvas);
}
} catch (Exception e) {
// TODO: handle exception
}
5
/**
* 繪制遮蓋板
*
* @param canvas
*/
private void drawMask(Canvas canvas) {
//線性渲染
LinearGradient lg = new LinearGradient(0, 0, 0, maskHight, 0x00f2f2f2,
0x00f2f2f2, TileMode.MIRROR);
Paint paint = new Paint();
paint.setShader(lg);
canvas.drawRect(0, 0, controlWidth, maskHight, paint);
LinearGradient lg2 = new LinearGradient(0, controlHeight - maskHight,
0, controlHeight, 0x00f2f2f2, 0x00f2f2f2, TileMode.MIRROR);
Paint paint2 = new Paint();
//設(shè)置渲染對象
paint2.setShader(lg2);
canvas.drawRect(0, controlHeight - maskHight, controlWidth,
controlHeight, paint2);
}
//LinearGradient? 線性渲染?
public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, Shader.TileMode tile)
參數(shù)x0表示漸變的起始點x坐標(biāo);參數(shù)y0表示漸變的起始點y坐標(biāo);參數(shù)x1表示漸變的終點x坐標(biāo);參數(shù)y1表示漸變的終點y坐標(biāo)?。籧olor0表示漸變開始顏色;color1表示漸變結(jié)束顏色;參數(shù)tile表示平鋪方式。Shader.TileMode有3種參數(shù)可供選擇,分別為CLAMP、REPEAT和MIRROR:
CLAMP的作用是如果渲染器超出原始邊界范圍,則會復(fù)制邊緣顏色對超出范圍的區(qū)域進行著色
REPEAT的作用是在橫向和縱向上以平鋪的形式重復(fù)渲染位圖
MIRROR的作用是在橫向和縱向上以鏡像的方式重復(fù)渲染位圖
自定義view已經(jīng)畫好。現(xiàn)在接著進行觸摸事件
6
@Override
public boolean onTouchEvent(MotionEvent event) {
// isEnable是否可用
if (!isEnable)
return true;
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
/** 是否滑動中 */
isScrolling = true;
/** 按下的坐標(biāo) */
downY = (int) event.getY();
/** 按下的時間 */
downTime = System.currentTimeMillis();
break;
case MotionEvent.ACTION_MOVE:
//移動距離
7
actionMove(y - downY);
//選擇監(jiān)聽
8
onSelectListener();
break;
case MotionEvent.ACTION_UP:
// 移動距離的絕對值
int move = (y - downY);
move = move > 0 ? move : move * (-1);
// 判斷段時間移動的距離
/** 短促移動? goonTime=200*//** 短促移動距離? goonDistence=100*/
if (System.currentTimeMillis() - downTime < goonTime
&& move > goonDistence) {
10
goonMove(y - downY);
} else {
13
actionUp(y - downY);
}
17
noEmpty();
isScrolling = false;
break;
default:
break;
}
return true;
}
7
/**
* 移動的時候
*
* @param move
*/
private void actionMove(int move) {
for (ItemObject item : itemList) {
item.move(move);
?}
invalidate();
}
8
/**
* 滑動監(jiān)聽
*/
private void onSelectListener() {
/** 選擇監(jiān)聽 */
9
if (onSelectListener == null)
return;
for (ItemObject item : itemList) {
if (item.isSelected()) {
//監(jiān)聽選擇
onSelectListener.selecting(item.id, item.itemText);
}
}
}
設(shè)置監(jiān)聽接口回調(diào)
9
/**
* 選擇監(jiān)聽監(jiān)聽
*
* @author zoudong
*
*/
public interface OnSelectListener {
/**
* 結(jié)束選擇
*
* @param id
* @param text
*/
public void endSelect(int id, String text);
/**
* 選中的內(nèi)容
*
* @param id
* @param text
*/
public void selecting(int id, String text);
}
10
/**
* 繼續(xù)移動一定距離
*/
private synchronized void goonMove(final int move) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
int distence = 0;
/** 移動距離? MOVE_NUMBER=5*/
while (distence < unitHeight * MOVE_NUMBER) {
try {
Thread.sleep(5);
?} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
?}
11
actionThreadMove(move > 0 ? distence : distence * (-1));
distence += 10;
?}??? 13
actionUp(move > 0 ? distence - 10 : distence * (-1) + 10);
17
noEmpty();
?}
?}).start();
}
/*? 11
* 移動,線程中調(diào)用
*
* @param move
*/
private void actionThreadMove(int move) {
for (ItemObject item : itemList) {
item.move(move);
}
12
Message rMessage = new Message();
/** 刷新界面? REFRESH_VIEW=0x001 */
rMessage.what = REFRESH_VIEW;
handler.sendMessage(rMessage);
}
12
@SuppressLint("HandlerLeak")
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case REFRESH_VIEW:
invalidate();
break;
default:
break;
?? }
?}
};
13
/**
* 松開的時候
*
* @param move
*/
private void actionUp(int move) {
int newMove = 0;
if (move > 0) {
for (int i = 0; i < itemList.size(); i++) {
if (itemList.get(i).isSelected()) {
14
newMove = (int) itemList.get(i).moveToSelected();
if (onSelectListener != null)
//接口回調(diào) 結(jié)束選擇
onSelectListener.endSelect(itemList.get(i).id,
itemList.get(i).itemText);
break;
? }
? }
? } else {
for (int i = itemList.size() - 1; i >= 0; i--) {
if (itemList.get(i).isSelected()) {
newMove = (int) itemList.get(i).moveToSelected();
if (onSelectListener != null)
//結(jié)束選擇
onSelectListener.endSelect(itemList.get(i).id,
itemList.get(i).itemText);
break;
? }
? }
? }
for (ItemObject item : itemList) {
15
item.newY(move + 0);
? ? }
16
slowMove(newMove);
Message rMessage = new Message();
rMessage.what = REFRESH_VIEW;
handler.sendMessage(rMessage);
}
14
/**
* 獲取移動到標(biāo)準(zhǔn)位置需要的距離
*/
public float moveToSelected() {
return (controlHeight / 2 - unitHeight / 2) - (y + move);
}
15
/**
* 設(shè)置新的坐標(biāo)
*
* @param move
*/
public void newY(int _move) {
this.move = 0;
this.y = y + _move;
}
16
/**
* 緩慢移動
*
* @param move
*/
private synchronized void slowMove(final int move) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
// 判斷正負(fù)
int m = move > 0 ? move : move * (-1);
int i = move > 0 ? 1 : (-1);
// 移動速度
int speed = 1;
while (true) {
m = m - speed;
if (m <= 0) {
for (ItemObject item : itemList) {
item.newY(m * i);
?}
Message rMessage = new Message();
rMessage.what = REFRESH_VIEW;
handler.sendMessage(rMessage);
try {
Thread.sleep(2);
?} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
?}
break;
?}
for (ItemObject item : itemList) {
item.newY(speed * i);
?}
Message rMessage = new Message();
rMessage.what = REFRESH_VIEW;
handler.sendMessage(rMessage);
//釋放系統(tǒng)資源
try {
Thread.sleep(2);
?} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
?}
?}
for (ItemObject item : itemList) {
if (item.isSelected()) {
if (onSelectListener != null)
onSelectListener.endSelect(item.id, item.itemText);
break;
?}
?}
?}
?}).start();
}
17
/**
* 不能為空,必須有選項
*/
private void noEmpty() {
if (!noEmpty)
return;
for (ItemObject item : itemList) {
if (item.isSelected())
return;
?}
int move = (int) itemList.get(0).moveToSelected();
if (move < 0) {
18
defaultMove(move);h
?} else {
defaultMove((int) itemList.get(itemList.size() - 1)
.moveToSelected());
?}
for (ItemObject item : itemList) {
if (item.isSelected()) {
if (onSelectListener != null)
onSelectListener.endSelect(item.id, item.itemText);
break;
?}
?}
}
18
/**
* 移動到默認(rèn)位置
*
* @param move
*/
private void defaultMove(int move) {
for (ItemObject item : itemList) {
item.newY(move);
?}
Message rMessage = new Message();
rMessage.what = REFRESH_VIEW;
handler.sendMessage(rMessage);
}
到了這一步 基本自定義控件搞定了 剩下就是暴漏一些自己需要的接口或者方法了~源碼請查看
Android三級聯(lián)動wheel代碼分析(一)里面,等兩天接著Android三級聯(lián)動wheel代碼分析(三)。
如有不對的地方請指正,因為這個代碼較多 加上數(shù)字應(yīng)該會看的稍微清楚點。。。