In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article introduces the "Android how to customize View to achieve simple style lyrics control" related knowledge, in the actual case of the operation process, many people will encounter such a dilemma, and then let the editor lead you to learn how to deal with these situations! I hope you can read it carefully and be able to achieve something!
Put up the effect picture first
I. Analysis of lyrics
First of all, we need to know what the normal lyric format looks like, something like this:
1 [ti: like you]
2 [ar:.]
3 [al:]
4 [by:]
5 [offset:0]
Love you-G.E.M. Deng Ziqi (Gem Tang)
Word: Huang Jiaju
8 [00Ru 00.30] Music: Wong Ka Kui
9 [00RV 00.40] arrangement: Lupo Groinig
10 [00:00.50]
11 [00Plus 12.65] drizzling streets with rheumatism through the dusk
Rain Water looked up without reason from his eyes
13 [00Plus 24.04] look at the lonely night light
14 [00:26.91]
15 [00] 27.44 is the sad memory
16 [00:30.52]
17 [0014. 12] there are countless thoughts in my heart again.
18 [00:39.28]
19 [00Rule 40.10] laughter still hangs on his face for a moment
May you know at this moment
21 [00:48.23]
22 [00POS 48.95] I say it from the bottom of my heart
23 [00:53.06]
24 [00VR 54.35] I like your lovely eyes.
25 [00:59.35]
26 [01] laughter is more charming
27 [01:02.37]
28 [01PUR 03.15] May I caress you again
29 [01:08.56]
30 [01RV] that lovely face
31 [01] hand in hand talking in sleep
32 [01:14.78]
33 [01] like yesterday you shared with me
34 [01:20.84]
35 [01] full of ideals, I used to be so impulsive.
36 [01PUR 32.45] repeatedly complain that it is difficult to be free to fall in love with her.
37 [01] may you know at this moment
38 [01:40.40]
39 [01RV] I say it from the bottom of my heart
40 [01:44.81]
41 [01RV] I like your eyes.
42 [01:51.72]
43 [01] laughter is more charming
44 [01:54.75]
45 [01PUR 55.48] May I touch you again
46 [02:00.93]
47 [02RV] that lovely face
48 [02:03.99]
49 [02Partition 04.73] arm in arm talking in sleep
50 [02:07.13]
Like yesterday you shared me with me.
52 [02:14.53]
53 [02GRO 25.54] walk alone every night
54 [02PUR 29.30] how cold it is everywhere
55 [02:35.40]
56 [02PUR 37.83] used to struggle for oneself
57 [02VR 41.62] never knew her pain
58 [02:52.02]
59 [02VR 54.11] I like your lovely eyes.
60 [03WR 00.13] laughter is more charming
61 [03:02.38]
62 [03PUR 03.14] I wish to caress you again
63 [03:08.77]
64 [03WR 09.33] that lovely face
65 [03:11.71]
66 [03Partition 12.41] arm in arm talking in sleep
67 [03:14.61]
68 [03GR 15.45] like yesterday you shared with me
As can be seen from the above, this format is preceded by the start time, corresponding one by one from left to right, seconds, milliseconds, followed by lyrics. So we need to create an entity class to store the lyrics of each sentence.
1. Lyrics entity class LrcBean
1public class LrcBean {2 private String lrc;// lyrics 3 private long start;// start time 4 private long end;// end time 5 6 public String getLrc () {7 return lrc; 8} 910 public void setLrc (String lrc) {11 this.lrc = lrc;12} 1314 public long getStart () {15 return start;16} 1718 public void setStart (long start) {19 this.start = start 20} 2122 public long getEnd () {23 return end;24} 2526 public void setEnd (long end) {27 this.end = end;28} 29}
For every lyrics, we need information such as the start time, the end time and the lyrics, so you will have questions? The format of the lyrics mentioned above seems to be only the start time of the lyrics, so how do we know the end time? In fact, it is very simple, the beginning time of this lyric is the end time of the last lyric. With the lyrics entity class, we have to start to analyze the lyrics!
two。 Analysis of lyrics tool class LrcUtil
1public class LrcUtil {2 3 / * * 4 * parses lyrics, encapsulating string lyrics into LrcBean collection 5 * @ param lrcStr string lyrics with fixed format Generally 6 * [ti: like you] 7 * [ar:.] 8 * [al:] 9 * [by:] 10 * [offset:0] 11 * [00al 00.10] like you-G.E.M. Deng Ziqi (Gem Tang) 12 * [00Rou 00.20] words: Huang Jiaju 13 * [00RV 00.30] Music: Huang Jiaju 14 * [00RV 00.40] arrangement: Lupo Groinig15 * @ return lyrics Collection 16 * / 17 public static List parseStr2List (String lrcStr) {18 List res = new ArrayList () 19 / / Segmentation of the string based on line breaks 20 String [] subLrc = lrcStr.split (""); 21 / skip the first four lines, starting with the fifth line, because we don't need 22 for (int I = 5; I) for the lyrics of the first four lines
< 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(first1){57 //当集合数目大于1时,这句的歌词的开始时间就是上一句歌词的结束时间58 res.get(res.size()-2).setEnd(startTime);59 }6061 }62 return res;63 }6465 /**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. 邓紫棋 (Gem Tang)"这句歌词,如果我们不做特殊处理,在后面绘制的时候,就会发现这句歌词会超过屏幕大小,很影响美观,所以我们只截取歌曲名和演唱者,有些说明直接省略掉了。解析好了歌词,接下来就是重头戏-歌词绘制! 二、歌词绘制 歌词绘制就涉及到了自定义View的知识,所以还未接触自定义View的小伙伴需要先去看看自定View的基础知识。歌词绘制的主要工作主要由下面几部分构成: 为歌词控件设置自定义属性,在构造方法中获取并设置自定义属性的默认值 初始化两支画笔。分别是歌词普通画笔,歌词高亮画笔。 获取当前播放歌词的位置 画歌词,根据当前播放歌词的位置来决定用哪支画笔画 歌词随歌曲播放同步滑动 重新绘制 1.设置自定View属性,在代码中设置默认值 在res文件中的values中新建一个attrs.xml文件,然后定义歌词的自定义View属性 123 4 5 6 7 8 9 这里只自定义了歌词颜色,歌词高亮颜色,歌词大小,歌词行间距的属性,可根据自己需要自行添加。 然后在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 //默认字体大小为16sp15 textSize = ta.getDimensionPixelSize(R.styleable.LrcView_textSize, (int) (16 * fontScale));16 //默认行间距为30dp17 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);//文字居中 910 //初始化当前歌词画笔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 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 currentPosition = 0 return;15 11 return;12} else if (curTime > lrcBeanList.get (lrcBeanList.size ()-1). GetStart () {13 currentPosition = lrcBeanList.size ()-1 return;15} 16 for (int I = 0; I
< lrcBeanList.size(); i++) {17 if (curTime >= lrcBeanList.get (I). GetStart () & & curTime 10601000, this is because in practical use, it is found that when the player is not played, the curTime will be very large, so there is this judgment (because a normal song will not exceed 10 minutes).
In this method we will find that there are lyrics and players, you may be confused, these are not assigned yet? Confusion is right, so we need to provide external methods to pass to the lyrics control lyrics collection and players.
1 / / pass the lyrics collection to the custom View 2 public LrcView setLrc (String lrc) {3 lrcBeanList = LrcUtil.parseStr2List (lrc); 4 return this; 5} 6 7 / / pass the mediaPlayer to the custom View 8 public LrcView setPlayer (MediaPlayer player) {9 this.player = player;10 return this;11}
The parameters of setLrc in the external method must be in the form of a string in the standard lyric format mentioned earlier, so that we can parse the string into a collection of lyrics using the parsing method in the parsing tool class LrcUtil above.
3. Draw lyrics
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}
If flexible sliding is not achieved, just judge whether the current playing time of the song is greater than the end time of the lyrics in the current position, and then slide scrollTo (0, (int) currentPosition * lineSpacing). But in order to achieve elastic sliding, we need to divide a slide into several small slides and complete it in a period of time, so we dynamically set the value of y, because of continuous redrawing, we can complete the View sliding in 0.5 seconds, so we can achieve synchronous elastic sliding of the lyrics.
500 is actually 0.5s, because here the units of currentTime and startTime are ms.
1 float y = (currentTime-startTime) > 500? CurrentPosition * lineSpacing: lastPosition * lineSpacing + (currentPosition-lastPosition) * lineSpacing * ((currentTime-startTime) / 500f); 5. Keep redrawing
Only by constantly redrawing can the lyrics slide synchronously, which is redrawn every 0.1s.
1postInvalidateDelayed (100s); / / delay 0.1s refresh
You think it's over? In fact, not yet, the answer is revealed below!
III. Use
And then we happily refer to this custom View in xml
The name before LrcView creates the full package name for this class for you.
one
Pass the standard lyrics string and player to the custom View in the Java code.
1lrcView.setLrc (lrc) .setPlayer (player)
Click run, looking forward to your own results, and then you will look confused, what? Why is it a blank? there is nothing! In fact, at this time, if you rearrange the process of drawing the lyrics above, you will find out where the problem lies. First of all, our custom View control executes the onDraw method first when it is referenced into the layout, so when you call the setLrc and setPlayer methods, you will not call the onDraw method again, which means that you have not passed in the lyrics string and the player, so of course there will be a blank.
Solution: we just added an external method to call onDraw in the custom View lyrics control, and just this invalidate () can call the onDraw method again.
1 public LrcView draw () {2 currentPosition = 0 return this;6 3 lastPosition = 0 x 4 invalidate (); 5 return this;6}
Then in the main code, we have to call the draw method after calling setLrc and setPlayer
1lrcView.setLrc (lrc) .setPlayer (player). Draw (); "how Android customizes View to implement simple style lyrics control" ends here. Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.