最近一直在完善jayPlayer(自制杰伦播放器)当然不仅仅可以播放杰伦的歌曲,其他歌手也有哈。这次添加的是歌词滚动显示效果。废话不多说先上效果图:
这个界面看上去还是阔以的,特别赞一下咪咕音乐的曲库,这首革命人永远是年轻 是我听过的最好的一版!远看这个布局也不怎么看出是如何实现的大概猜一个TextView?是的,就是TextView,每行歌词都是一个TextView,所有TextView都塞在一个ListView中,下面是我的布局文件:activity_play_lrc.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/play_lrc_frame"
android:layout_width="match_parent"
android:layout_height="450dp"
android:padding="10dp"
app:layout_constraintBottom_toTopOf="@id/seek_bar_grid"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/nav_bar_grid">
<ScrollView
android:id="@+id/play_lrc_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:padding="5dp"
android:scrollbars="none">
<ListView
android:scrollbars="none"
android:id="@+id/play_lrc_listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#00000000"
/>
</ScrollView>
</FrameLayout>
和自定义适配器是一个思路,就是重新一个适配器LrcAdapter继承自BaseAdapter,并实现几个方法即可。再看一个布局文件就是ListView中每个人Item的布局,这里就简单点,是个TextView。
show_lrc_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/show_lrc_item"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/play_lrc_view"
android:textColor="#333333"
android:textSize="20sp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Hello this lrc yo~"
android:textAlignment="center" />
</LinearLayout>
然后再写适配器LrcAdapter
package top.sencom.jayplayer.adapter;
import android.content.Context;
import android.util.SparseBooleanArray;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import java.util.List;
import top.sencom.jayplayer.R;
import top.sencom.jayplayer.lrcparser.parser.Sentence;
public class LrcAdapter extends BaseAdapter {
private List<Sentence> data;
private LayoutInflater layoutInflater;
private Context context;
private SparseBooleanArray selected;
int old = 0;
public LrcAdapter( Context context, List<Sentence> data) {
this.data = data;
this.layoutInflater = LayoutInflater.from(context);
this.context = context;
this.selected = new SparseBooleanArray();
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int position) {
return data.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = layoutInflater.inflate(R.layout.show_lrc_item, null);
TextView lrcLine = convertView.findViewById(R.id.play_lrc_view);
lrcLine.setText(data.get(position).getContent());
if(selected.get(position)){
lrcLine.setTextColor(context.getResources().getColor(R.color.colorPrimary));
lrcLine.setTextSize(TypedValue.COMPLEX_UNIT_SP,25);
}else {
lrcLine.setTextColor(context.getResources().getColor(R.color.lrcDefault));
}
return convertView;
}
public void setSelectedItem(int position){
if(old!=-1){
this.selected.put(old,false);
}
this.selected.put(position,true);
old = position;
}
}
这里我们设置了一个SparseBooleanArray 用来存放当前选中的Item的标志;用于实现当前播放行的字体加大和上色,相关方法是getView()和setSelectedItem(),old变量用来记忆上一个被选中的Item用于恢复。其实也可以不用因为都是顺序的完全可以通过-1得到。注意这里的数据data变量的类型是List,这里我的歌词解析用的是github上的https://github.com/authorfu/LrcParser但是他的代码有个小bug,早在我写基于java swing GUI开发的音乐播放器时候就发现并解决了,所以这次直接改了就用就行了。
接下来就是activity中的核心代码了,当然之前应该已经将歌词lrc文件获取到,并将其存放在reader变量中。下面给出lrc显示线程的代码:
lrcT = new Thread(new Runnable() {
@Override
public void run() {
try{
lyric= LrcParser.create(reader);
}catch(IOException e){
e.printStackTrace();
}
while (true){
try {
Thread.sleep(256);
} catch (InterruptedException e) {
e.printStackTrace();
}
Sentence sentence=lyric.findSentence(mediaPlayer.getCurrentPosition());
try {
if(sentence.getIndex() == lyric.getSize() || lrcExit){
break;
}else {
//System.out.println(sentence);
runOnUiThread(new Runnable() {
@Override
public void run() {
lrcListView.post(new Runnable() {
@Override
public void run() {
lrcAdapter.setSelectedItem(sentence.getIndex());
lrcAdapter.notifyDataSetChanged();
lrcListView.setSelectionFromTop(sentence.getIndex(),550);
}
});
}
});
}
}catch (Exception e){
break;
}
}
}
});
在歌词准备好,listview添加好适配器后就可以启动这个线程,其中核心代码如下:
runOnUiThread(new Runnable() {
@Override
public void run() {
lrcListView.post(new Runnable() {
@Override
public void run() {
lrcAdapter.setSelectedItem(sentence.getIndex());
lrcAdapter.notifyDataSetChanged();
lrcListView.setSelectionFromTop(sentence.getIndex(),550);
}
});
}
});
每次执行此方法时首先将选中的Item调整为当前播放的歌曲所匹配的歌词,然后通知listview数据集有改动这样listview就会重新绘制布局执行getView方法将旧的歌词恢复,新的歌词变大上色,最后执行listview选中方法将当前位置的歌词滚动到屏幕相对中间的地方,至此完成一行歌词显示。