Android实现音乐播放器歌词显示效果

这篇文章主要介绍了Android实现音乐播放器歌词显示效果,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

10多年的襄垣网站建设经验,针对设计、前端、开发、售后、文案、推广等六对一服务,响应快,48小时及时工作处理。全网整合营销推广的优势是能够根据用户设备显示端的尺寸不同,自动调整襄垣建站的显示方式,使网站能够适用不同显示终端,在浏览器中调整网站的宽度,无论在任何一种浏览器上浏览网站,都能展现优雅布局与设计,从而大程度地提升浏览体验。成都创新互联从事“襄垣网站设计”,“襄垣网站推广”以来,每个客户项目都认真落实执行。

这两天有个任务,说是要写一个QQ音乐播放器歌词的那种效果,毕竟刚学自定义View,没有什么思路,然后就Google.写了一个歌词效果,效果图在后面,下面是我整理的代码。

首先实现这种效果有两种方式:

1.自定义View里重载onDraw方法,自己绘制歌词

2.用ScrollView实现

第一种方式比较精确,但要支持滑动之后跳转播放的话难度很大,所以我选择第二种,自定义ScrollView。

我也不多说,直接上代码,代码中有注释。

一.自定义LycicView extends ScrollView

里面包括一个空白布局,高度是LycicView的一半,再是一个布局存放歌词的,最后是一个空白布局高度是LycicView的一半。

这里动态的向第二个布局里面添加了显示歌词的TextView,并利用ViewTreeObserver得到每个textview的高度,方便知道每个textview歌词所要滑动到的高度。

public class LycicView extends ScrollView {
 LinearLayout rootView;//父布局
 LinearLayout lycicList;//垂直布局
 ArrayList lyricItems = new ArrayList();//每项的歌词集合
 
 ArrayList lyricTextList = new ArrayList();//每行歌词文本集合,建议先去看看手机音乐里的歌词格式和内容
 ArrayList lyricTimeList = new ArrayList();//每行歌词所对应的时间集合
 ArrayList lyricItemHeights;//每行歌词TextView所要显示的高度
 
 int height;//控件高度
 int width;//控件宽度
 int prevSelected = 0;//前一个选择的歌词所在的item
 
 
 public LycicView(Context context) {
 super(context);
 init();
 }
 
 public LycicView(Context context, AttributeSet attrs) {
 super(context, attrs);
 init();
 }
 
 public LycicView(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 init();
 }
 private void init(){
 rootView = new LinearLayout(getContext());
 rootView.setOrientation(LinearLayout.VERTICAL);
 //创建视图树,会在onLayout执行后立即得到正确的高度等参数
 ViewTreeObserver vto = rootView.getViewTreeObserver();
 vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
 @Override
 public void onGlobalLayout() {
 height = LycicView.this.getHeight();
 width = LycicView.this.getWidth();
 
 refreshRootView();
 
 }
 });
 addView(rootView);//把布局加进去
 }
 
 /**
 *
 */
 void refreshRootView(){
 rootView.removeAllViews();//刷新,先把之前包含的所有的view清除
 //创建两个空白view
 LinearLayout blank1 = new LinearLayout(getContext());
 LinearLayout blank2 = new LinearLayout(getContext());
 //高度平分
 LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(width,height/2);
 rootView.addView(blank1,params);
 if(lycicList !=null){
 rootView.addView(lycicList);//加入一个歌词显示布局
 rootView.addView(blank2,params);
 }
 
 }
 
 /**
 *设置歌词,
 */
 void refreshLyicList(){
 if(lycicList == null){
 lycicList = new LinearLayout(getContext());
 lycicList.setOrientation(LinearLayout.VERTICAL);
 //刷新,重新添加
 lycicList.removeAllViews();
 lyricItems.clear();
 lyricItemHeights = new ArrayList();
 prevSelected = 0;
 //为每行歌词创建一个TextView
 for(int i = 0;i=16
 lyricItemHeights.add(index,textView.getHeight());//将高度添加到对应的item位置
 }
 });
 lycicList.addView(textView);
 lyricItems.add(index,textView);
 }
 }
 }
 /**
 * 滚动到index位置
 */
 public void scrollToIndex(int index){
 if(index < 0){
 scrollTo(0,0);
 }
 //计算index对应的textview的高度
 if(index < lyricTextList.size()){
 int sum = 0;
 for(int i = 0;i<=index-1;i++){
 sum+=lyricItemHeights.get(i);
 }
 //加上index这行高度的一半
 sum+=lyricItemHeights.get(index)/2;
 scrollTo(0,sum);
 }
 }
 
 /**
 * 歌词一直滑动,小于歌词总长度
 * @param length
 * @return
 */
 
 int getIndex(int length){
 int index = 0;
 int sum = 0;
 while(sum <= length){
 sum+=lyricItemHeights.get(index);
 index++;
 }
 //从1开始,所以得到的是总item,脚标就得减一
 return index - 1;
 }
 
 /**
 * 设置选择的index,选中的颜色
 * @param index
 */
 void setSelected(int index){
 //如果和之前选的一样就不变
 if(index == prevSelected){
 return;
 }
 for(int i = 0;i textList,ArrayList timeList){
 //因为你从歌词lrc里面可以看出,每行歌词前面都对应有时间,所以两者必须相等
 if(textList.size() != timeList.size()){
 throw new IllegalArgumentException();
 }
 this.lyricTextList = textList;
 this.lyricTimeList = timeList;
 
 refreshLyicList();
 }
 
 @Override
 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
 super.onScrollChanged(l, t, oldl, oldt);
 //滑动时,不往回弹,滑到哪就定位到哪
 setSelected(getIndex(t));
 if(listener != null){
 listener.onLyricScrollChange(getIndex(t),getIndex(oldt));
 }
 }
 OnLyricScrollChangeListener listener;
 public void setOnLyricScrollChangeListener(OnLyricScrollChangeListener l){
 this.listener = l;
 }
 
 /**
 * 向外部提供接口
 */
 public interface OnLyricScrollChangeListener{
 void onLyricScrollChange(int index,int oldindex);
 }
}

二..MainActivity中的布局



 
 
 
 

具体实现代码如下:

public class MainActivity extends AppCompatActivity {
 
 LycicView view;
 EditText editText;
 Button btn;
 Handler handler = new Handler(new Handler.Callback() {
 @Override
 public boolean handleMessage(Message msg) {
 if(msg.what == 1){
 
 if(lrc_index == list.size()){
 handler.removeMessages(1);
 }
 lrc_index++;
 
 System.out.println("******"+lrc_index+"*******");
 view.scrollToIndex(lrc_index);
 handler.sendEmptyMessageDelayed(1,4000);
 }
 return false;
 }
 });
 private ArrayList lrcs;
 private ArrayList list;
 private ArrayList list1;
 private int lrc_index;
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 
 initViews();
 
 initEvents();
 }
 private void initViews(){
 view = (LycicView) findViewById(R.id.view);
 editText = (EditText) findViewById(R.id.editText);
 btn = (Button) findViewById(R.id.button);
 }
 private void initEvents(){
 InputStream is = getResources().openRawResource(R.raw.eason_tenyears);
 
 // BufferedReader br = new BufferedReader(new InputStreamReader(is));
 list = new ArrayList();
 list1 = new ArrayList<>();
 lrcs = Utils.redLrc(is);
 for(int i = 0; i< lrcs.size(); i++){
 list.add(lrcs.get(i).getLrc());
 System.out.println(lrcs.get(i).getLrc()+"=====");
 list1.add(0l);//lrcs.get(i).getTime()
 }
 view.setLyricText(list, list1);
 view.postDelayed(new Runnable() {
 @Override
 public void run() {
 view.scrollToIndex(0);
 }
 },1000);
 
 btn.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
 String text = editText.getText().toString();
 int index = 0;
 index = Integer.parseInt(text);
 view.scrollToIndex(index);
 }
 });
 view.setOnLyricScrollChangeListener(new LycicView.OnLyricScrollChangeListener() {
 @Override
 public void onLyricScrollChange(final int index, int oldindex) {
 editText.setText(""+index);
 lrc_index = index;
 System.out.println("===="+index+"======");
 //滚动handle不能放在这,因为,这是滚动监听事件,滚动到下一次,handle又会发送一次消息,出现意想不到的效果
 }
 });
 handler.sendEmptyMessageDelayed(1,4000);
 view.setOnTouchListener(new View.OnTouchListener() {
 @Override
 public boolean onTouch(View v, MotionEvent event) {
 switch (event.getAction()){
 case MotionEvent.ACTION_DOWN:
 handler.removeCallbacksAndMessages(null);
 
 System.out.println("取消了");
 break;
 case MotionEvent.ACTION_UP:
 System.out.println("开始了");
 handler.sendEmptyMessageDelayed(1,2000);
 break;
 case MotionEvent.ACTION_CANCEL://时间别消耗了
 break;
 }
 return false;
 }
 });
 
 getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE|WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
 }
 
}

其中utils类和LycicMusic是一个工具类和存放Music信息实体类

Utils类

public class Utils {
 public static ArrayList redLrc(InputStream in) {
 ArrayList alist = new ArrayList();
 //File f = new File(path.replace(".mp3", ".lrc"));
 try {
 //FileInputStream fs = new FileInputStream(f);
 InputStreamReader input = new InputStreamReader(in, "utf-8");
 BufferedReader br = new BufferedReader(input);
 String s = "";
 
 while ((s = br.readLine()) != null) {
 if (!TextUtils.isEmpty(s)) {
 String lyLrc = s.replace("[", "");
 String[] data_ly = lyLrc.split("]");
 if (data_ly.length > 1) {
 String time = data_ly[0];
 String lrc = data_ly[1];
 LrcMusic lrcMusic = new LrcMusic(lrcData(time), lrc);
 alist.add(lrcMusic);
 }
 }
 }
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } catch (Exception e) {
 e.printStackTrace();
 }
 return alist;
 }
 public static int lrcData(String time) {
 time = time.replace(":", "#");
 time = time.replace(".", "#");
 
 String[] mTime = time.split("#");
 
 //[03:31.42]
 int mtime = Integer.parseInt(mTime[0]);
 int stime = Integer.parseInt(mTime[1]);
 int mitime = Integer.parseInt(mTime[2]);
 
 int ctime = (mtime*60+stime)*1000+mitime*10;
 
 return ctime;
 }
}

LrcMusic实体类  

public class LrcMusic {
 private int time;
 private String lrc;
 
 public LrcMusic() {
 }
 
 public LrcMusic(int time, String lrc) {
 this.time = time;
 this.lrc = lrc;
 }
 
 public int getTime() {
 return time;
 }
 
 public void setTime(int time) {
 this.time = time;
 }
 
 public String getLrc() {
 return lrc;
 }
 
 public void setLrc(String lrc) {
 this.lrc = lrc;
 }
}

效果图:

Android实现音乐播放器歌词显示效果

感谢你能够认真阅读完这篇文章,希望小编分享的“Android实现音乐播放器歌词显示效果”这篇文章对大家有帮助,同时也希望大家多多支持创新互联,关注创新互联行业资讯频道,更多相关知识等着你来学习!


网站名称:Android实现音乐播放器歌词显示效果
本文路径:http://azwzsj.com/article/pieoco.html