【移動應(yīng)用開發(fā)技術(shù)】Android怎么自定義View實(shí)現(xiàn)簡約風(fēng)歌詞控件_第1頁
【移動應(yīng)用開發(fā)技術(shù)】Android怎么自定義View實(shí)現(xiàn)簡約風(fēng)歌詞控件_第2頁
【移動應(yīng)用開發(fā)技術(shù)】Android怎么自定義View實(shí)現(xiàn)簡約風(fēng)歌詞控件_第3頁
【移動應(yīng)用開發(fā)技術(shù)】Android怎么自定義View實(shí)現(xiàn)簡約風(fēng)歌詞控件_第4頁
【移動應(yīng)用開發(fā)技術(shù)】Android怎么自定義View實(shí)現(xiàn)簡約風(fēng)歌詞控件_第5頁
已閱讀5頁,還剩11頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

【移動應(yīng)用開發(fā)技術(shù)】Android怎么自定義View實(shí)現(xiàn)簡約風(fēng)歌詞控件

本篇內(nèi)容介紹了“Android怎么自定義View實(shí)現(xiàn)簡約風(fēng)歌詞控件”的有關(guān)知識,在實(shí)際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓在下帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!首先,我們得知道正常的歌詞格式是怎樣的,大概是長這個樣子:

1[ti:喜歡你]

2[ar:.]

3[al:]

4[by:]

5[offset:0]

6[00:00.10]喜歡你-G.E.M.鄧紫棋(GemTang)

7[00:00.20]詞:黃家駒

8[00:00.30]曲:黃家駒

9[00:00.40]編曲:LupoGroinig10[00:00.50]11[00:12.65]細(xì)雨帶風(fēng)濕透黃昏的街道12[00:18.61]抹去雨水雙眼無故地仰望13[00:24.04]望向孤單的晚燈14[00:26.91]15[00:27.44]是那傷感的記憶16[00:30.52]17[00:34.12]再次泛起心里無數(shù)的思念18[00:39.28]19[00:40.10]以往片刻歡笑仍掛在臉上20[00:45.49]愿你此刻可會知21[00:48.23]22[00:48.95]是我衷心的說聲23[00:53.06]24[00:54.35]喜歡你那雙眼動人25[00:59.35]26[01:00.10]笑聲更迷人27[01:02.37]28[01:03.15]愿再可輕撫你29[01:08.56]30[01:09.35]那可愛面容31[01:12.40]挽手說夢話32[01:14.78]33[01:15.48]像昨天你共我34[01:20.84]35[01:26.32]滿帶理想的我曾經(jīng)多沖動36[01:32.45]屢怨與她相愛難有自由37[01:37.82]愿你此刻可會知38[01:40.40]39[01:41.25]是我衷心的說聲40[01:44.81]41[01:46.39]喜歡你那雙眼動人42[01:51.72]43[01:52.42]笑聲更迷人44[01:54.75]45[01:55.48]愿再可輕撫你46[02:00.93]47[02:01.68]那可愛面容48[02:03.99]49[02:04.73]挽手說夢話50[02:07.13]51[02:07.82]像昨天你共我52[02:14.53]53[02:25.54]每晚夜里自我獨(dú)行54[02:29.30]隨處蕩多冰冷55[02:35.40]56[02:37.83]以往為了自我掙扎57[02:41.62]從不知她的痛苦58[02:52.02]59[02:54.11]喜歡你那雙眼動人60[03:00.13]笑聲更迷人61[03:02.38]62[03:03.14]愿再可輕撫你63[03:08.77]64[03:09.33]那可愛面容65[03:11.71]66[03:12.41]挽手說夢話67[03:14.61]68[03:15.45]像昨天你共我

1[ti:喜歡你]

2[ar:.]

3[al:]

4[by:]

5[offset:0]

6[00:00.10]喜歡你-G.E.M.鄧紫棋(GemTang)

7[00:00.20]詞:黃家駒

8[00:00.30]曲:黃家駒

9[00:00.40]編曲:LupoGroinig10[00:00.50]11[00:12.65]細(xì)雨帶風(fēng)濕透黃昏的街道12[00:18.61]抹去雨水雙眼無故地仰望13[00:24.04]望向孤單的晚燈14[00:26.91]15[00:27.44]是那傷感的記憶16[00:30.52]17[00:34.12]再次泛起心里無數(shù)的思念18[00:39.28]19[00:40.10]以往片刻歡笑仍掛在臉上20[00:45.49]愿你此刻可會知21[00:48.23]22[00:48.95]是我衷心的說聲23[00:53.06]24[00:54.35]喜歡你那雙眼動人25[00:59.35]26[01:00.10]笑聲更迷人27[01:02.37]28[01:03.15]愿再可輕撫你29[01:08.56]30[01:09.35]那可愛面容31[01:12.40]挽手說夢話32[01:14.78]33[01:15.48]像昨天你共我34[01:20.84]35[01:26.32]滿帶理想的我曾經(jīng)多沖動36[01:32.45]屢怨與她相愛難有自由37[01:37.82]愿你此刻可會知38[01:40.40]39[01:41.25]是我衷心的說聲40[01:44.81]41[01:46.39]喜歡你那雙眼動人42[01:51.72]43[01:52.42]笑聲更迷人44[01:54.75]45[01:55.48]愿再可輕撫你46[02:00.93]47[02:01.68]那可愛面容48[02:03.99]49[02:04.73]挽手說夢話50[02:07.13]51[02:07.82]像昨天你共我52[02:14.53]53[02:25.54]每晚夜里自我獨(dú)行54[02:29.30]隨處蕩多冰冷55[02:35.40]56[02:37.83]以往為了自我掙扎57[02:41.62]從不知她的痛苦58[02:52.02]59[02:54.11]喜歡你那雙眼動人60[03:00.13]笑聲更迷人61[03:02.38]62[03:03.14]愿再可輕撫你63[03:08.77]64[03:09.33]那可愛面容65[03:11.71]66[03:12.41]挽手說夢話67[03:14.61]68[03:15.45]像昨天你共我從上面可以看出這種格式前面是開始時間,從左往右一一對應(yīng)分,秒,毫秒,后面就是歌詞。所以我們要創(chuàng)建一個實(shí)體類來保存每一句的歌詞信息。1.歌詞實(shí)體類LrcBean

1public

class

LrcBean

{

2

private

String

lrc;//歌詞

3

private

long

start;//開始時間

4

private

long

end;//結(jié)束時間

5

6

public

String

getLrc()

{

7

return

lrc;

8

}

9

10

public

void

setLrc(String

lrc)

{

11

this.lrc

=

lrc;

12

}

13

14

public

long

getStart()

{

15

return

start;

16

}

17

18

public

void

setStart(long

start)

{

19

this.start

=

start;

20

}

21

22

public

long

getEnd()

{

23

return

end;

24

}

25

26

public

void

setEnd(long

end)

{

27

this.end

=

end;

28

}

29}每句歌詞,我們需要開始時間,結(jié)束時間和歌詞這些信息,那么你就會有疑問了?上面提到的歌詞格式好像只有歌詞開始時間,那我們怎么知道結(jié)束時間呢?其實(shí)很簡單,這一句歌詞的開始時間就是上一句歌詞的結(jié)束時間。有了歌詞實(shí)體類,我們就得開始對歌詞進(jìn)行解析了!2.解析歌詞工具類LrcUtil

1public

class

LrcUtil

{

2

3

/**

4

*

解析歌詞,將字符串歌詞封裝成LrcBean的集合

5

*

@param

lrcStr

字符串的歌詞,歌詞有固定的格式,一般為

6

*

[ti:喜歡你]

7

*

[ar:.]

8

*

[al:]

9

*

[by:]

10

*

[offset:0]

11

*

[00:00.10]喜歡你

-

G.E.M.

鄧紫棋

(Gem

Tang)

12

*

[00:00.20]詞:黃家駒

13

*

[00:00.30]曲:黃家駒

14

*

[00:00.40]編曲:Lupo

Groinig

15

*

@return

歌詞集合

16

*/

17

public

static

List<LrcBean>

parseStr2List(String

lrcStr){

18

List<LrcBean>

res

=

new

ArrayList<>();

19

//根據(jù)轉(zhuǎn)行字符對字符串進(jìn)行分割

20

String[]

subLrc

=

lrcStr.split("

");

21

//跳過前四行,從第五行開始,因?yàn)榍八男械母柙~我們并不需要

22

for

(int

i

=

5;

i

<

subLrc.length;

i++)

{

23

String

lineLrc

=

subLrc[i];

24

//[00:00.10]喜歡你

-

G.E.M.

鄧紫棋

(Gem

Tang)

25

String

min

=

lineLrc.substring(lineLrc.indexOf("[")+1,lineLrc.indexOf("[")+3);

26

String

sec

=

lineLrc.substring(lineLrc.indexOf(":")+1,lineLrc.indexOf(":")+3);

27

String

mills

=

lineLrc.substring(lineLrc.indexOf(".")+1,lineLrc.indexOf(".")+3);

28

//進(jìn)制轉(zhuǎn)化,轉(zhuǎn)化成毫秒形式的時間

29

long

startTime

=

getTime(min,sec,mills);

30

//歌詞

31

String

lrcText

=

lineLrc.substring(lineLrc.indexOf("]")+1);

32

//有可能是某個時間段是沒有歌詞,則跳過下面

33

if(lrcText.equals(""))

continue;

34

//在第一句歌詞中有可能是很長的,我們只截取一部分,即歌曲加演唱者

35

//比如

光年之外

(《太空旅客(Passengers)》電影中國區(qū)主題曲)

-

G.E.M.

鄧紫棋

(Gem

Tang)

36

if

(i

==

5)

{

37

int

lineIndex

=

lrcText.indexOf("-");

38

int

first

=

lrcText.indexOf("(");

39

if(first<lineIndex&&first!=-1){

40

lrcText

=

lrcText.substring(0,first)+lrcText.substring(lineIndex);

41

}

42

LrcBean

lrcBean

=

new

LrcBean();

43

lrcBean.setStart(startTime);

44

lrcBean.setLrc(lrcText);

45

res.add(lrcBean);

46

continue;

47

}

48

//添加到歌詞集合中

49

LrcBean

lrcBean

=

new

LrcBean();

50

lrcBean.setStart(startTime);

51

lrcBean.setLrc(lrcText);

52

res.add(lrcBean);

53

//如果是最后一句歌詞,其結(jié)束時間是不知道的,我們將人為的設(shè)置為開始時間加上100s

54

if(i

==

subLrc.length-1){

55

res.get(res.size()-1).setEnd(startTime+100000);

56

}else

if(res.size()>1){

57

//當(dāng)集合數(shù)目大于1時,這句的歌詞的開始時間就是上一句歌詞的結(jié)束時間

58

res.get(res.size()-2).setEnd(startTime);

59

}

60

61

}

62

return

res;

63

}

64

65

/**

66

*

根據(jù)時分秒獲得總時間

67

*

@param

min

分鐘

68

*

@param

sec

69

*

@param

mills

毫秒

70

*

@return

總時間

71

*/

72

private

static

long

getTime(String

min,String

sec,String

mills){

73

return

Long.valueOf(min)*60*1000+Long.valueOf(sec)*1000+Long.valueOf(mills);

74

}

75}相信上面的代碼和注釋已經(jīng)將這個歌詞解析解釋的挺明白了,需要注意的是上面對i=5,也就是歌詞真正開始的第一句做了特殊處理,因?yàn)閕=5這句有可能是很長的,假設(shè)i=5是“光年之外(《太空旅客(Passengers)》電影中國區(qū)主題曲)-G.E.M.鄧紫棋(GemTang)”這句歌詞,如果我們不做特殊處理,在后面繪制的時候,就會發(fā)現(xiàn)這句歌詞會超過屏幕大小,很影響美觀,所以我們只截取歌曲名和演唱者,有些說明直接省略掉了。解析好了歌詞,接下來就是重頭戲-歌詞繪制!歌詞繪制就涉及到了自定義View的知識,所以還未接觸自定義View的小伙伴需要先去看看自定View的基礎(chǔ)知識。歌詞繪制的主要工作主要由下面幾部分構(gòu)成:為歌詞控件設(shè)置自定義屬性,在構(gòu)造方法中獲取并設(shè)置自定義屬性的默認(rèn)值初始化兩支畫筆。分別是歌詞普通畫筆,歌詞高亮畫筆。獲取當(dāng)前播放歌詞的位置畫歌詞,根據(jù)當(dāng)前播放歌詞的位置來決定用哪支畫筆畫歌詞隨歌曲播放同步滑動重新繪制1.設(shè)置自定View屬性,在代碼中設(shè)置默認(rèn)值在res文件中的values中新建一個attrs.xml文件,然后定義歌詞的自定義View屬性1<?xml

version="1.0"

encoding="utf-8"?>

2<resources>

3

<declare-styleable

name="LrcView">

4

<attr

name="highLineTextColor"

format="color|reference|integer"/>

5

<attr

name="lrcTextColor"

format="color|reference|integer"/>

6

<attr

name="lineSpacing"

format="dimension"/>

7

<attr

name="textSize"

format="dimension"/>

8

</declare-styleable>

9</resources>這里只自定義了歌詞顏色,歌詞高亮顏色,歌詞大小,歌詞行間距的屬性,可根據(jù)自己需要自行添加。然后在Java代碼中,設(shè)置默認(rèn)值。

1

private

int

lrcTextColor;//歌詞顏色

2

private

int

highLineTextColor;//當(dāng)前歌詞顏色

3

private

int

width,

height;//屏幕寬高

4

private

int

lineSpacing;//行間距

5

private

int

textSize;//字體大小

6

7

public

LrcView(Context

context,

@Nullable

AttributeSet

attrs,

int

defStyleAttr)

{

8

super(context,

attrs,

defStyleAttr);

9

TypedArray

ta

=

context.obtainStyledAttributes(attrs,

R.styleable.LrcView);

10

lrcTextColor

=

ta.getColor(R.styleable.LrcView_lrcTextColor,

Color.GRAY);

11

highLineTextColor

=

ta.getColor(R.styleable.LrcView_highLineTextColor,

Color.BLUE);

12

float

fontScale

=

context.getResources().getDisplayMetrics().scaledDensity;

13

float

scale

=

context.getResources().getDisplayMetrics().density;

14

//默認(rèn)字體大小為16sp

15

textSize

=

ta.getDimensionPixelSize(R.styleable.LrcView_textSize,

(int)

(16

*

fontScale));

16

//默認(rèn)行間距為30dp

17

lineSpacing

=

ta.getDimensionPixelSize(R.styleable.LrcView_lineSpacing,

(int)

(30

*

scale));

18

//回收

19

ta.recycle();

20

}2.初始化兩支畫筆

1

private

void

init()

{

2

//初始化歌詞畫筆

3

dPaint

=

new

Paint();

4

dPaint.setStyle(Paint.Style.FILL);//填滿

5

dPaint.setAntiAlias(true);//抗鋸齒

6

dPaint.setColor(lrcTextColor);//畫筆顏色

7

dPaint.setTextSize(textSize);//歌詞大小

8

dPaint.setTextAlign(Paint.Align.CENTER);//文字居中

9

10

//初始化當(dāng)前歌詞畫筆

11

hPaint

=

new

Paint();

12

hPaint.setStyle(Paint.Style.FILL);

13

hPaint.setAntiAlias(true);

14

hPaint.setColor(highLineTextColor);

15

hPaint.setTextSize(textSize);

16

hPaint.setTextAlign(Paint.Align.CENTER);

17

}我們把初始化的方法放到了構(gòu)造方法中,這樣就可以避免在重繪時再次初始化。另外由于我們把init方法只放到了第三個構(gòu)造方法中,所以在上面兩個構(gòu)造方法需要將super改成this,這樣就能保證哪個構(gòu)造方法都能執(zhí)行init方法

1

public

LrcView(Context

context)

{

2

this(context,

null);

3

}

4

5

public

LrcView(Context

context,

@Nullable

AttributeSet

attrs)

{

6

this(context,

attrs,

0);

7

}

8

9

public

LrcView(Context

context,

@Nullable

AttributeSet

attrs,

int

defStyleAttr)

{

10

super(context,

attrs,

defStyleAttr);

11

TypedArray

ta

=

context.obtainStyledAttributes(attrs,

R.styleable.LrcView);

12

13

//回收

14

ta.recycle();

15

init();

16

}3.重復(fù)執(zhí)行onDraw方法因?yàn)楹竺娴牟襟E都是在onDraw方法中執(zhí)行的,所以我們先貼出onDraw方法中的代碼

1

@Override

2

protected

void

onDraw(Canvas

canvas)

{

3

super.onDraw(canvas);

4

5

getMeasuredWidthAndHeight();//得到測量后的寬高

6

getCurrentPosition();//得到當(dāng)前歌詞的位置

7

drawLrc(canvas);//畫歌詞

8

scrollLrc();//歌詞滑動

9

postInvalidateDelayed(100);//延遲0.1s刷新

10

}1.獲得控件的測量后的寬高1

private

int

width,

height;//屏幕寬高

2

private

void

getMeasuredWidthAndHeight(){

3

if

(width

==

0

||

height

==

0)

{

4

width

=

getMeasuredWidth();

5

height

=

getMeasuredHeight();

6

}

7

}為什么要獲得控件的寬高呢?因?yàn)樵谙旅嫖覀冃枰嫺柙~,畫歌詞時需要畫的位置,這時候就需要用到控件的寬高了。2.得到當(dāng)前歌詞的位置

1

private

List<LrcBean>

lrcBeanList;//歌詞集合

2

private

int

currentPosition;//當(dāng)前歌詞的位置

3

private

MediaPlayer

player;//當(dāng)前的播放器

4

5

6

private

void

getCurrentPosition()

{

7

int

curTime

=

player.getCurrentPosition();

8

//如果當(dāng)前的時間大于10分鐘,證明歌曲未播放,則當(dāng)前位置應(yīng)該為0

9

if

(curTime

<

lrcBeanList.get(0).getStart()||curTime>10*60*1000)

{

10

currentPosition

=

0;

11

return;

12

}

else

if

(curTime

>

lrcBeanList.get(lrcBeanList.size()

-

1).getStart())

{

13

currentPosition

=

lrcBeanList.size()

-

1;

14

return;

15

}

16

for

(int

i

=

0;

i

<

lrcBeanList.size();

i++)

{

17

if

(curTime

>=

lrcBeanList.get(i).getStart()

&&

curTime

<=

lrcBeanList.get(i).getEnd())

{

18

currentPosition

=

i;

19

}

20

}

21

}我們根據(jù)當(dāng)前播放的歌曲時間來遍歷歌詞集合,從而判斷當(dāng)前播放的歌詞的位置。細(xì)心的你可能會發(fā)現(xiàn)在currentPosition=0中有個curTime>10601000的判斷,這是因?yàn)樵趯?shí)際使用中發(fā)現(xiàn)當(dāng)player還未播放時,這時候得到的curTime會很大,所以才有了這個判斷(因?yàn)檎5母枨粫^10分鐘)。在這個方法我們會發(fā)現(xiàn)出現(xiàn)了歌詞集合和播放器,你可能會感到困惑,這些不是還沒賦值嗎?困惑就對了,所以我們需要提供外部方法來給外部傳給歌詞控件歌詞集合和播放器。

1

//將歌詞集合傳給到這個自定義View中

2

public

LrcView

setLrc(String

lrc)

{

3

lrcBeanList

=

LrcUtil.parseStr2List(lrc);

4

return

this;

5

}

6

7

//傳遞mediaPlayer給自定義View中

8

public

LrcView

setPlayer(MediaPlayer

player)

{

9

this.player

=

player;

10

return

this;

11

}外部方法中setLrc的參數(shù)必須是前面提到的標(biāo)準(zhǔn)歌詞格式的字符串形式,這樣我們就能利用上文的解析工具類LrcUtil中的解析方法將字符串解析成歌詞集合。3.畫歌詞1

private

void

drawLrc(Canvas

canvas)

{

2

for

(int

i

=

0;

i

<

lrcBeanList.size();

i++)

{

3

if

(currentPosition

==

i)

{//如果是當(dāng)前的歌詞就用高亮的畫筆畫

4

canvas.drawText(lrcBeanList.get(i).getLrc(),

width

/

2,

height

/

2

+

i

*

lineSpacing,

hPaint);

5

}

else

{

6

canvas.drawText(lrcBeanList.get(i).getLrc(),

width

/

2,

height

/

2

+

i

*

lineSpacing,

dPaint);

7

}

8

}

9

}知道了當(dāng)前歌詞的位置就很容易畫歌詞了。遍歷歌詞集合,如果是當(dāng)前歌詞,則用高亮的畫筆畫,其它歌詞就用普通畫筆畫。這里需注意的是兩支畫筆畫的位置公式都是一樣的,坐標(biāo)位置為x=寬的一半,y=高的一半+當(dāng)前位置*行間距。隨著當(dāng)前位置的變化,就能畫出上下句歌詞來。所以其實(shí)繪制出來后你會發(fā)現(xiàn)歌詞是從控件的正中央開始繪制的,這是為了方便與下面歌詞同步滑動功能配合。4.歌詞同步滑動

1

//歌詞滑動

2

private

void

scrollLrc()

{

3

//下一句歌詞的開始時間

4

long

startTime

=

lrcBeanList.get(currentPosition).getStart();

5

long

currentTime

=

player.getCurrentPosition();

6

7

//判斷是否換行,在0.5內(nèi)完成滑動,即實(shí)現(xiàn)彈性滑動

8

float

y

=

(currentTime

-

startTime)

>

500

?

currentPosition

*

lineSpacing

:

lastPosition

*

lineSpacing

+

(currentPosition

-

lastPosition)

*

lineSpacing

*

((currentTime

-

startTime)

/

500f);

9

scrollTo(0,(int)y);

10

if

(getScrollY()

==

currentPosition

*

lineSpacing)

{

11

lastPosition

=

currentPosition;

12

}

13

}如果不實(shí)現(xiàn)彈性滑動的話,只要判斷當(dāng)前播放歌曲的時間是否大于當(dāng)前位置歌詞的結(jié)束時間,然后進(jìn)行scrollTo(0,(int)currentPosition*lineSpacing)滑動即可。但是為了實(shí)現(xiàn)彈性滑動,我們需要將一次滑動

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論