-
這個效果做起來好像沒什麼意義,如果不加監聽回調 圖片就能直接替代。寫這篇博客的目的是鍛鍊一下思維能力,以更好的面多各種自定義view需求。
本文是和代碼同步寫的。也就是說在寫文章的時候才敲的代碼。這樣會顯得文章有些許混亂。但是我想這樣記錄下來,一個自定義view的真正的製作過程,是一點一點,一步步跟着思路的改變,完善的。不可能一下子就做出一個完整的view。。技術也是這樣,不可能一步登天。都是一步一步的積累。
另外,每一篇博客都是建立在之前博客的基礎知識上的,如果你剛接觸自定義view。可以來說說自定義view簡單學習的方式這裏看我以前的文章。記錄了我學習自定義view的過程,而且前幾篇博客或多或少犯了一些錯誤。這裏我並不想改正博文中的錯誤,因爲些錯誤是大家經常會犯的,後來的博客都有指出這些錯誤,以及不再犯,這是一個學習的過程。所以我想把錯誤的經歷記錄下來。等成爲高手 回頭看看當年的自己是多麼菜。。也會有成就感。。
老規矩效果圖如下:
首先畫一個六邊形,畫之前來計算一下六邊形的相關知識:
假設一個正六邊形的邊長爲a ,因爲每個角都是120° 所以可得高爲根號三a ,如圖所示。
有了這些信息我們就可以繪製一個六邊形出來,如下:
123456789float
height = (
float
) (Math.sqrt(
3
)*mLength);
mPath.moveTo(mLength/
2
,
0
);
mPath.lineTo(
0
,height/
2
);
mPath.lineTo(mLength/
2
,height);
mPath.lineTo((
float
) (mLength*
1.5
),height);
mPath.lineTo(
2
*mLength,height/
2
);
mPath.lineTo((
float
) (mLength*
1.5
),
0
);
mPath.lineTo(mLength/
2
,
0
);
mPath.close();
繪製效果:然後將其根據一個偏移量進行平移,就可以用循環繪製出多個六邊形
這裏offset是偏移量,緊挨着的話應該是偏移一個六邊形的寬,寬由上圖可知爲 a/2+a+a/2 即 2a;
1234567891011for
(
int
i =
0
; i <
3
;i++) {
int
offset = mLength *
2
* i;
mPath.moveTo(mLength /
2
+ offset,
0
);
mPath.lineTo(
0
+ offset, height /
2
);
mPath.lineTo(mLength /
2
+ offset, height);
mPath.lineTo((
float
) (mLength *
1.5
) + offset, height);
mPath.lineTo(
2
* mLength + offset, height /
2
);
mPath.lineTo((
float
) (mLength *
1.5
)+offset,
0
);
mPath.lineTo(mLength /
2
+offset,
0
);
mPath.close();
}
發現效果如下這不對啊,很奇怪啊。。 底下空出來的一個三角形放不下我們的第二行啊。。
那麼怎麼辦呢。。 加大offset! 加大多少呢。。 應該多增加一個邊長。。這樣就正好留空了。 來試試
現在來準備畫第二行....
發現我們之前path的座標都是相對寫死的。。 所以要回過頭改一下,改成給定一個起點,就可以繪製出一個六邊形,經過計算,得出下圖
這裏a代表邊長。
改完之後的代碼是:
12345678910111213141516171819float
height = (
float
) (Math.sqrt(
3
)*mLength);
for
(
int
i =
0
; i <
3
;i++) {
//橫座標偏移量
int
offset = mLength *
3
* i ;
//左上角的x
int
x = mLength/
2
+ offset;
int
y =
0
;
//根據左上角一點 繪製整個正六邊形
mPath.moveTo(x, y);
mPath.lineTo(x -mLength/
2
, height /
2
+ y);
mPath.lineTo(x, height+y);
mPath.lineTo(x + mLength, height +y);
mPath.lineTo((
float
) (x +
1.5
*mLength), height /
2
+y);
mPath.lineTo(x + mLength, y);
mPath.lineTo(x, y);
mPath.close();
}
繪製出來的效果是一樣的。但是方法以及變了。然後來畫第二行,第二行起點的path應該在這裏
座標是: 2a , height/2 這裏的偏移量不變。
首先將畫path的方法提取出來(as快捷鍵ctrl + alt + m)
1234567891011//根據左上角一點 繪製整個正六邊形
private
void
getPath(
float
height,
float
x,
float
y) {
mPath.moveTo(x, y);
mPath.lineTo(x -mLength/
2
, height /
2
+ y);
mPath.lineTo(x, height+y);
mPath.lineTo(x + mLength, height +y);
mPath.lineTo((
float
) (x +
1.5
*mLength), height /
2
+y);
mPath.lineTo(x + mLength, y);
mPath.lineTo(x, y);
mPath.close();
}
1234567891011for
(
int
i =
0
;i<
2
;i++){
float
offset = mLength *
3
* i ;
float
x = mLength*
2
+ offset;
float
y = height/
2
;
getPath(height,x,y);
}
canvas.drawPath(mPath,mPaint);
現在ondraw的全部代碼如下:
12345678910111213141516171819202122232425262728293031323334@Override
protected
void
onDraw(Canvas canvas) {
mPaint.setColor(Color.parseColor(
"#FFBB33"
));
//正六邊形的高
float
height = (
float
) (Math.sqrt(
3
)*mLength);
for
(
int
i =
0
; i <
3
;i++) {
//橫座標偏移量
float
offset = mLength *
3
* i ;
//左上角的x
float
x = mLength/
2
+ offset;
float
y =
0
;
getPath(height, x, y);
}
canvas.drawPath(mPath,mPaint);
mPath.reset();
mPaint.setColor(Color.parseColor(
"#AA66CC"
));
for
(
int
i =
0
;i<
2
;i++){
float
offset = mLength *
3
* i ;
float
x = mLength*
2
+ offset;
float
y = height/
2
;
getPath(height,x,y);
}
canvas.drawPath(mPath,mPaint);
}
接下來對每行的個數進行一下控制。12345//每行的個數
private
int
mColumnsCount =
3
;
//行數
private
int
mLineCount =
3
;
對應的循環也改變,最外面套一個大循環,來控制多行繪製1234for
(
int
j =
0
; j < mLineCount; j++) {
if
(j%
2
==
0
) 繪製奇數行
else
繪製偶數行
}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647@Override
protected
void
onDraw(Canvas canvas) {
//正六邊形的高
float
height = (
float
) (Math.sqrt(
3
) * mLength);
for
(
int
j =
0
; j < mLineCount; j++) {
if
(j %
2
==
0
) {
mPaint.setColor(Color.parseColor(
"#FFBB33"
));
for
(
int
i =
0
; i < mColumnsCount; i++) {
//橫座標偏移量
float
offset = mLength *
3
* i;
//左上角的x
float
x = mLength /
2
+ offset;
float
y = j * height /
2
;
getPath(height, x, y);
}
canvas.drawPath(mPath, mPaint);
mPath.reset();
}
else
{
mPaint.setColor(Color.parseColor(
"#AA66CC"
));
for
(
int
i =
0
; i < mColumnsCount; i++) {
float
offset = mLength *
3
* i;
float
x = mLength *
2
+ offset;
float
y = (height /
2
) * j;
getPath(height, x, y);
}
canvas.drawPath(mPath, mPaint);
mPath.reset();
}
}
}
好像顏色一樣就不好看了。。那我們來動態改變一下顏色..
添加一個屬性list來存放color
1private
ArrayList<integer> mColorList;</integer>
1234567891011mColorList =
new
ArrayList<>();
mColorList.add(Color.parseColor(
"#33B5E5"
));
mColorList.add(Color.parseColor(
"#AA66CC"
));
mColorList.add(Color.parseColor(
"#99CC00"
));
mColorList.add(Color.parseColor(
"#FFBB33"
));
mColorList.add(Color.parseColor(
"#FF4444"
));
123for
(
int
j =
0
; j < mLineCount; j++) {
mPaint.setColor(mColorList.get(j));
嗯。。看起來像一點樣子了。。。 給中間加點文字吧。。
先給每個蜂窩編號
按上面的循環 j爲行數 i爲列數
研究規律發現 編號等於 j*3 + i
我們有六邊形左上角的座標xy 可以輕易的計算出中心座標
這些都有了。開一個list存放中間的文字:
12//存放文字的list
private
ArrayList<string> mTextList ;</string>
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138mTextList =
new
ArrayList<>();
for
(
int
i =
0
;i<mlinecount*mcolumnscount;i++){ mtextpaint=
"new"
pre=
""
wing=
""
>
繪製文字: 這裏要注意他和path的繪製順序,如果path後繪製則會覆蓋掉文字<pre
class
=
"brush:java;"
>
float
txtLength = mTextPaint.measureText(mTextList.get(txtId));
canvas.drawText(mTextList.get(txtId),x+mLength/
2
-txtLength/
2
,y+height/
2
+
5
, mTextPaint);</pre>
<p>下面是全部的ondraw</p>
<pre
class
=
"brush:java;"
>
@Override
protected
void
onDraw(Canvas canvas) {
//正六邊形的高
float
height = (
float
) (Math.sqrt(
3
) * mLength);
for
(
int
j =
0
; j < mLineCount; j++) {
mPaint.setColor(mColorList.get(j));
if
(j %
2
==
0
) {
// mPaint.setColor(Color.parseColor("#FFBB33"));
for
(
int
i =
0
; i < mColumnsCount; i++) {
int
txtId = j*
3
+i;
//橫座標偏移量
float
offset = mLength *
3
* i;
//左上角的x
float
x = mLength /
2
+ offset;
float
y = j * height /
2
;
mPath.reset();
getPath(height, x, y);
canvas.drawPath(mPath, mPaint);
float
txtLength = mTextPaint.measureText(mTextList.get(txtId));
canvas.drawText(mTextList.get(txtId),x+mLength/
2
-txtLength/
2
,y+height/
2
+
5
, mTextPaint);
}
}
else
{
// mPaint.setColor(Color.parseColor("#AA66CC"));
for
(
int
i =
0
; i < mColumnsCount; i++) {
int
txtId = j*
3
+i;
float
offset = mLength *
3
* i;
float
x = mLength *
2
+ offset;
float
y = (height /
2
) * j;
mPath.reset();
getPath(height, x, y);
canvas.drawPath(mPath, mPaint);
float
txtLength = mTextPaint.measureText(mTextList.get(txtId));
canvas.drawText(mTextList.get(txtId),x+mLength/
2
-txtLength/
2
,y+height/
2
+
5
, mTextPaint);
}
}
}
}</pre>
<br>
現在的效果圖如下:
<p><img alt=
"\" src="
http:
//www.2cto.com/uploadfile/Collfiles/20160125/20160125091503178.jpg" style="width: 377px; height: 453px;"></p>
<p>好,那現在讓他靈活一點。添加各種set方法,比如行數啊 列數啊 邊長啊 文字內容啊 顏色啊之類的。</p>
<pre
class
=
"brush:java;"
>
/**
* 設置列數
* @param mColumnsCount
*/
public
void
setColumnsCount(
int
mColumnsCount) {
this
.mColumnsCount = mColumnsCount;
invalidate();
}
/**
* 設置行數
* @param mLineCount
*/
public
void
setLineCount(
int
mLineCount) {
this
.mLineCount = mLineCount;
invalidate();
}
/**
* 設置文本數據
*/
public
void
setTextList(ArrayList<string> textList) {
mTextList.clear();
mTextList.addAll(textList);
invalidate();
}
/**
* 設置顏色數據
* @param colorList
*/
public
void
setColorList(ArrayList<integer> colorList) {
mColorList.clear();
mColorList.addAll(colorList);
invalidate();
}</integer></string></pre>
然後 你有沒有忘記測量呢? 只要把最外面的矩形大小給他就行
<pre
class
=
"brush:java;"
>
@Override
protected
void
onMeasure(
int
widthMeasureSpec,
int
heightMeasureSpec) {
int
widthSize = MeasureSpec.getSize(widthMeasureSpec);
int
widthMode = MeasureSpec.getMode(widthMeasureSpec);
int
heightSize = MeasureSpec.getSize(heightMeasureSpec);
int
heightMode = MeasureSpec.getMode(heightMeasureSpec);
if
(widthMode == MeasureSpec.AT_MOST){
widthSize = (
int
) ((3f*mColumnsCount+
0
.5f) *mLength);
}
else
{
// throw new IllegalStateException("only support wrap_content");
}
if
(heightMode == MeasureSpec.AT_MOST){
heightSize = (
int
) ((mLineCount/2f +
0
.5f) * (Math.sqrt(
3
) * mLength));
}
else
{
// throw new IllegalStateException("only support wrap_content");
}
setMeasuredDimension(widthSize,heightSize);
}</pre>
<p>這下使用wrap_content 來看看view的大小:</p>
<p><img alt=
"\" src="
http:
//www.2cto.com/uploadfile/Collfiles/20160125/20160125091504190.jpg" style="width: 426px; height: 473px;"></p>
<p>嗯。。測量也對着。。。 這裏我只實現了wrap_content 大家可以以及擴展 讓他支持EXACTLY</p>
自定義view詳解,手把手帶你畫一個漂亮蜂窩view Android自定義view
轉自:http://www.2cto.com/kf/201601/487139.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.