Android实现歌词滑动显示

本文介绍了一个自定义的LyricView组件,它能够实现歌词与音乐播放同步滚动的效果,支持设置歌词列表、播放状态和歌词索引。通过使用LinearGradient设置背景渐变色,提供了一种美观的视觉体验。此组件适用于Android应用中音乐播放器的歌词展示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

继承TextView自定义LyricView

import java.util.List;

import com.anjoyo.musicplayer.bean.LyricBean;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.Typeface;
import android.graphics.Paint.Align;
import android.graphics.Shader.TileMode;
import android.util.AttributeSet;
import android.widget.TextView;

public class LyricView extends TextView {

	/** 控件的高 */
	private float mHeight;
	/** 控件的宽 */
	private float mWidth;
	private Paint mPaint;
	private Paint prePaint;
	private Paint nextPaint;
	
	/** 当前歌曲的歌词 */
	private List<LyricBean> lyricBeanList;
	/** 歌词进度,List中的位置 */
	private int index;
	
	private float heightSign;
	private boolean start;
	
	private Shader inShader = new LinearGradient(0, 0, 0, LYRIC_ONE_HEIGHT, 
			Color.argb(0xcc, 0xcc, 0xcc, 0xcc), 
			Color.argb(0xff, 0xff, 0xff, 0xff), TileMode.MIRROR);
	private Shader outShader = new LinearGradient(0, LYRIC_ONE_HEIGHT, 0, 0, 
			Color.argb(0xcc, 0xcc, 0xcc, 0xcc), 
			Color.argb(0xff, 0xff, 0xff, 0xff), TileMode.MIRROR);
	
	/** 歌词显示的字体大小 */
	private static final int LYRIC_TEXT_SIZE = 36;
	/** 每行歌词的高度 */
	private static final int LYRIC_ONE_HEIGHT = 60;
	
	public LyricView(Context context) {
		super(context);
		initView();
	}

	public LyricView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initView();
	}

	public LyricView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initView();
		
		new UpdateThread().start();
	}
	
	private void initView() {
		setFocusable(true);
		 
		mPaint = new Paint();
		mPaint.setAntiAlias(true);// 设置画笔的锯齿效果
		mPaint.setTextAlign(Align.CENTER);
		mPaint.setTextSize(LYRIC_TEXT_SIZE);
		mPaint.setTypeface(Typeface.SERIF);
		
		prePaint = new Paint(mPaint);
		prePaint.setShader(outShader);
		nextPaint = new Paint(mPaint);
		nextPaint.setShader(inShader);
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		if (canvas == null) {
			return;
		}
		mPaint.setColor(Color.argb(0xff, 0xff, 0xff, 0xff));//当前歌词词句颜色
		if (lyricBeanList == null || lyricBeanList.size() < 1 || index > lyricBeanList.size() - 1) {
			canvas.drawText("好音质,MusicPlayer!", mWidth / 2, mHeight / 2, mPaint);
			return;
		}
		canvas.drawText(lyricBeanList.get(index).getLyric(), mWidth / 2, heightSign, mPaint);
		
		mPaint.setColor(Color.argb(0xcc, 0xcc, 0xcc, 0xcc));//非当前歌词词句颜色
		
		float currentY = heightSign;
		//画出本句之前的歌词
		for (int i = index - 1; i >= 0; i--) {
			currentY -= LYRIC_ONE_HEIGHT;
			if (i == index - 1) {
				canvas.drawText(lyricBeanList.get(i).getLyric(), mWidth / 2,
						currentY, prePaint);
			} else {
				canvas.drawText(lyricBeanList.get(i).getLyric(), mWidth / 2,
						currentY, mPaint);
			}
		}
		currentY = heightSign;
		//画出本句之后的歌词
		for (int i = index + 1; i < lyricBeanList.size(); i++) {
			currentY += LYRIC_ONE_HEIGHT;
			if (i == index + 1) {
				canvas.drawText(lyricBeanList.get(i).getLyric(), mWidth / 2,
						currentY, nextPaint);	
			} else {
				canvas.drawText(lyricBeanList.get(i).getLyric(), mWidth / 2,
						currentY, mPaint);		
			}
		}
	}
	
	public void setLyricList(List<LyricBean> lyricBeanList) {
		this.lyricBeanList = lyricBeanList;
	}
	
	public void setStart(boolean start) {
		this.start = start;
	}
	
	public boolean getStart() {
		return this.start;
	}
	
	public void setIndex(int index) {
		if (this.index != index) {
			this.index = index;
			heightSign = mHeight / 2 + LYRIC_ONE_HEIGHT / 2;
		}
	}
	
	private class UpdateThread extends Thread {
		@Override
		public void run() {
			while (true) {
				if (start && lyricBeanList.size() > index + 1) {
					if (heightSign > mHeight / 2f - LYRIC_ONE_HEIGHT / 2f) {
						heightSign -= LYRIC_ONE_HEIGHT / 
								(float)(lyricBeanList.get(index + 1).getLyricTime() 
										- lyricBeanList.get(index).getLyricTime()) * 50;
					}
					postInvalidate();
				}
				try {
					sleep(50);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		mWidth = w;
		mHeight = h;
		heightSign = h / 2f + LYRIC_ONE_HEIGHT / 2f;
	}

	
}



LyricBean.java如下


import java.util.List;

/**
 * 一句歌词
 * 
 * @author HLP
 */
public class LyricBean {

	/** 一句歌词 */
	private String lyric;
	/** 本句歌词开始的时间 */
	private int lyricTime;
	/** 本句歌词每个字的持续时间 ,构成数组 */
	private List<Integer> wordsTime;

	public LyricBean(String lyric, int lyricTime, List<Integer> wordsTime) {
		super();
		this.lyric = lyric;
		this.lyricTime = lyricTime;
		this.wordsTime = wordsTime;
	}

	public String getLyric() {
		return lyric;
	}

	public void setLyric(String lyric) {
		this.lyric = lyric;
	}

	public int getLyricTime() {
		return lyricTime;
	}

	public void setLyricTime(int lyricTime) {
		this.lyricTime = lyricTime;
	}

	public List<Integer> getWordsTime() {
		return wordsTime;
	}

	public void setWordsTime(List<Integer> wordsTime) {
		this.wordsTime = wordsTime;
	}

}


版权所有,转载请注明出处!http://blog.youkuaiyun.com/kuailebeihun_/article/details/22993711


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值