【移动应用开发技术】Android怎么自定义View实现简约风歌词控件_第1页
【移动应用开发技术】Android怎么自定义View实现简约风歌词控件_第2页
【移动应用开发技术】Android怎么自定义View实现简约风歌词控件_第3页
【移动应用开发技术】Android怎么自定义View实现简约风歌词控件_第4页
【移动应用开发技术】Android怎么自定义View实现简约风歌词控件_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

【移动应用开发技术】Android怎么自定义View实现简约风歌词控件

本篇内容介绍了“Android怎么自定义View实现简约风歌词控件”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让在下带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!首先,我们得知道正常的歌词格式是怎样的,大概是长这个样子:

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]细雨带风湿透黄昏的街道12[00:18.61]抹去雨水双眼无故地仰望13[00:24.04]望向孤单的晚灯14[00:26.91]15[00:27.44]是那伤感的记忆16[00:30.52]17[00:34.12]再次泛起心里无数的思念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]满带理想的我曾经多冲动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]每晚夜里自我独行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]细雨带风湿透黄昏的街道12[00:18.61]抹去雨水双眼无故地仰望13[00:24.04]望向孤单的晚灯14[00:26.91]15[00:27.44]是那伤感的记忆16[00:30.52]17[00:34.12]再次泛起心里无数的思念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]满带理想的我曾经多冲动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]每晚夜里自我独行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.歌词实体类LrcBean

1public

class

LrcBean

{

2

private

String

lrc;//歌词

3

private

long

start;//开始时间

4

private

long

end;//结束时间

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}每句歌词,我们需要开始时间,结束时间和歌词这些信息,那么你就会有疑问了?上面提到的歌词格式好像只有歌词开始时间,那我们怎么知道结束时间呢?其实很简单,这一句歌词的开始时间就是上一句歌词的结束时间。有了歌词实体类,我们就得开始对歌词进行解析了!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

//根据转行字符对字符串进行分割

20

String[]

subLrc

=

lrcStr.split("

");

21

//跳过前四行,从第五行开始,因为前四行的歌词我们并不需要

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

//进制转化,转化成毫秒形式的时间

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)》电影中国区主题曲)

-

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

//如果是最后一句歌词,其结束时间是不知道的,我们将人为的设置为开始时间加上100s

54

if(i

==

subLrc.length-1){

55

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

56

}else

if(res.size()>1){

57

//当集合数目大于1时,这句的歌词的开始时间就是上一句歌词的结束时间

58

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

59

}

60

61

}

62

return

res;

63

}

64

65

/**

66

*

根据时分秒获得总时间

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}相信上面的代码和注释已经将这个歌词解析解释的挺明白了,需要注意的是上面对i=5,也就是歌词真正开始的第一句做了特殊处理,因为i=5这句有可能是很长的,假设i=5是“光年之外(《太空旅客(Passengers)》电影中国区主题曲)-G.E.M.邓紫棋(GemTang)”这句歌词,如果我们不做特殊处理,在后面绘制的时候,就会发现这句歌词会超过屏幕大小,很影响美观,所以我们只截取歌曲名和演唱者,有些说明直接省略掉了。解析好了歌词,接下来就是重头戏-歌词绘制!歌词绘制就涉及到了自定义View的知识,所以还未接触自定义View的小伙伴需要先去看看自定View的基础知识。歌词绘制的主要工作主要由下面几部分构成:为歌词控件设置自定义属性,在构造方法中获取并设置自定义属性的默认值初始化两支画笔。分别是歌词普通画笔,歌词高亮画笔。获取当前播放歌词的位置画歌词,根据当前播放歌词的位置来决定用哪支画笔画歌词随歌曲播放同步滑动重新绘制1.设置自定View属性,在代码中设置默认值在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>这里只自定义了歌词颜色,歌词高亮颜色,歌词大小,歌词行间距的属性,可根据自己需要自行添加。然后在Java代码中,设置默认值。

1

private

int

lrcTextColor;//歌词颜色

2

private

int

highLineTextColor;//当前歌词颜色

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

//默认字体大小为16sp

15

textSize

=

ta.getDimensionPixelSize(R.styleable.LrcView_textSize,

(int)

(16

*

fontScale));

16

//默认行间距为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

//初始化当前歌词画笔

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

}我们把初始化的方法放到了构造方法中,这样就可以避免在重绘时再次初始化。另外由于我们把init方法只放到了第三个构造方法中,所以在上面两个构造方法需要将super改成this,这样就能保证哪个构造方法都能执行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.重复执行onDraw方法因为后面的步骤都是在onDraw方法中执行的,所以我们先贴出onDraw方法中的代码

1

@Override

2

protected

void

onDraw(Canvas

canvas)

{

3

super.onDraw(canvas);

4

5

getMeasuredWidthAndHeight();//得到测量后的宽高

6

getCurrentPosition();//得到当前歌词的位置

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

}为什么要获得控件的宽高呢?因为在下面我们需要画歌词,画歌词时需要画的位置,这时候就需要用到控件的宽高了。2.得到当前歌词的位置

1

private

List<LrcBean>

lrcBeanList;//歌词集合

2

private

int

currentPosition;//当前歌词的位置

3

private

MediaPlayer

player;//当前的播放器

4

5

6

private

void

getCurrentPosition()

{

7

int

curTime

=

player.getCurrentPosition();

8

//如果当前的时间大于10分钟,证明歌曲未播放,则当前位置应该为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

}我们根据当前播放的歌曲时间来遍历歌词集合,从而判断当前播放的歌词的位置。细心的你可能会发现在currentPosition=0中有个curTime>10601000的判断,这是因为在实际使用中发现当player还未播放时,这时候得到的curTime会很大,所以才有了这个判断(因为正常的歌曲不会超过10分钟)。在这个方法我们会发现出现了歌词集合和播放器,你可能会感到困惑,这些不是还没赋值吗?困惑就对了,所以我们需要提供外部方法来给外部传给歌词控件歌词集合和播放器。

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的参数必须是前面提到的标准歌词格式的字符串形式,这样我们就能利用上文的解析工具类LrcUtil中的解析方法将字符串解析成歌词集合。3.画歌词1

private

void

drawLrc(Canvas

canvas)

{

2

for

(int

i

=

0;

i

<

lrcBeanList.size();

i++)

{

3

if

(currentPosition

==

i)

{//如果是当前的歌词就用高亮的画笔画

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

}知道了当前歌词的位置就很容易画歌词了。遍历歌词集合,如果是当前歌词,则用高亮的画笔画,其它歌词就用普通画笔画。这里需注意的是两支画笔画的位置公式都是一样的,坐标位置为x=宽的一半,y=高的一半+当前位置*行间距。随着当前位置的变化,就能画出上下句歌词来。所以其实绘制出来后你会发现歌词是从控件的正中央开始绘制的,这是为了方便与下面歌词同步滑动功能配合。4.歌词同步滑动

1

//歌词滑动

2

private

void

scrollLrc()

{

3

//下一句歌词的开始时间

4

long

startTime

=

lrcBeanList.get(currentPosition).getStart();

5

long

currentTime

=

player.getCurrentPosition();

6

7

//判断是否换行,在0.5内完成滑动,即实现弹性滑动

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

}如果不实现弹性滑动的话,只要判断当前播放歌曲的时间是否大于当前位置歌词的结束时间,然后进行scrollTo(0,(int)currentPosition*lineSpacing)滑动即可。但是为了实现弹性滑动,我们需要将一次滑动

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论