android基础学习之一个简单的歌词滚动软件的实现

本文介绍了一种自定义Android View实现歌词滚动的方法。通过继承View并重写绘图方法,结合线程定时更新歌词显示位置,实现了歌词随播放进度滚动的效果。

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

在开发当中我们时常会自己定义View对象,今天我写了一个View对象,来实现了歌词的滚动,因为知识不全面,所以之前或者现在的代码都有一定的缺陷,在以后会慢慢修改,,现在只是为了了解大概框图,然后不断学习,废话不多说代码实现

程序入口

package com.example.viewdemo;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }


    
}


在写xml文件的时候,我们自己定义的View一定要记得引入包名

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

   <com.example.viewdemo.LrcView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" />


</RelativeLayout>

自定义View' 代码注解里面应该说的很清楚了

package com.example.viewdemo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

import org.xml.sax.InputSource;

import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

public class LrcView extends View {
  private Paint paint;
  private int text_x,text_y;
  private int width,height;
  private int refreshIndex;
  private int currentLrcIndex;
  private ArrayList<String> lrcs;
  private ArrayList<Integer> lrcTimes;
  private int move_y;
  private int move_count;
  //3个构造方法,前两个用于xml解析,第三个是用于java构建对象
	public LrcView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		//通过为最多的参数设置初始化,然后让其它的都直接调用它
		init();
	}
	public LrcView(Context context, AttributeSet attrs) {
		
		this(context,attrs,0);
	}
	public LrcView(Context context) {
		this(context,null);
	}
	private void init() {
		//创建画笔
		paint=new Paint();
		paint.setTextSize(30);
		//获取字体的大小,字体是正方形的
		float TextSize=paint.getTextSize();
		text_x=0;
		text_y=(int) TextSize;
		//每次取得歌词时,向上移动一个字的高度
		move_y=(int) TextSize;
		//歌词初始值
		currentLrcIndex=-1;
		refreshIndex=-2;
		//读取歌词
		try {
			readLrc();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		new Thread(new Runnable() {
			
			@Override
			public void run() {
				//时间一般由多媒体框架返回,但是这里我们是测试,所以我们就使用线程的开始时间
				long musicStart=System.currentTimeMillis();
				while(true){
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					//计算应该放哪一句歌词
					long currentTime=System.currentTimeMillis();
					long duration=currentTime-musicStart;
					int lrcDataLength=lrcTimes.size();
					//从所有的歌词中找到当前时间应该显示的歌词的下标
					for(int i=0;i<lrcDataLength;i++){
						int time=lrcTimes.get(i);
						System.out.println("time="+time);
						System.out.println("duration="+duration);
						//找到第一个大于我们当前的时间点,那么前一个就是我们需要找的歌词
						if(time>duration){
							currentLrcIndex=i-1;
							if(currentLrcIndex!=-1&&refreshIndex!=currentLrcIndex){
								//调用postInvalidata()方法,这个方法回毁掉onDraw方法绘制试图
								postInvalidate();
								//下标更新
								refreshIndex=currentLrcIndex;
							}
							break;
						}
					}
				}
				
			}
		}).start();
	}
	//重写onLayout方法,为了获得容器的宽和高
	@Override
		protected void onLayout(boolean changed, int left, int top, int right,
				int bottom) {
			// TODO Auto-generated method stub
			super.onLayout(changed, left, top, right, bottom);
			width=right-left;
			height=bottom-top;
		}
	//重写onDraw方法,实现视图的展示
	@Override
		protected void onDraw(Canvas canvas) {
			// TODO Auto-generated method stub
			super.onDraw(canvas);
			int lrcShowLength=lrcs.size();
			for(int i=0;i<lrcShowLength;i++){
				if(i==currentLrcIndex){
					paint.setColor(Color.BLUE);
				}else{
					paint.setColor(Color.BLACK);
				}
				//取出歌词
				String lrc=lrcs.get(i);
				//重新获取画笔的大小
				float textSize=paint.getTextSize();
				float[] widths=new float[lrcs.size()];
				int number=paint.getTextWidths(lrc, 0, lrc.length()-1, widths);
				int textwidth=0;
				for (float w : widths) {
					textwidth+=w;
				}
				//设置文字的锚点x坐标
				text_x=width/2-textwidth/2;
				//设置文字的锚点的y坐标
				int text_y_offset=(int) (i*textSize);
				int text_time_offset=move_y*move_count;
				text_y=(int) (height/2+textSize/2+text_y_offset+text_time_offset);
				canvas.drawText(lrc, text_x, text_y, paint);
			}
//每绘制一次,我们的坐标就像上移动一次
			move_count--;
		}
	private void readLrc() throws IOException {
		lrcs=new ArrayList<String>();
		lrcTimes=new ArrayList<Integer>();
		//由于每个View的构造器都有一个context,那么在LrcView中也会有一个context
		Context context=getContext();
		//assests中的文件不会被转换成为2进制
		AssetManager assetsManager=context.getAssets();
		InputStream in=assetsManager.open("text.txt");
		InputStreamReader isr=new InputStreamReader(in);
		BufferedReader bReader=new BufferedReader(isr);
		String lineStr = null;
		bReader.readLine() ;
		//
		while ((lineStr = bReader.readLine()) != null) {
			// 不为空,则能读取到数据
			String timeStr = lineStr.substring(1, 9);
			String lrcStr = lineStr.substring(10);
//			System.out.println("timeStr = "+timeStr);
//			System.out.println("lrcStr = "+lrcStr);
			//解析 00:00.00
			String min = timeStr.substring(0, 2) ;
			String sec = timeStr.substring(3, 5) ;
			String ms = timeStr.substring(6) ;
			//使用封装类,将数字组成的字符串,转换为数字
			int minI = Integer.valueOf(min) ;
			int secI = Integer.valueOf(sec) ;
			int msI = Integer.valueOf(ms) ;
			int lrcTime = minI*60*1000 + secI*1000 + msI*10 ;
			System.out.println("lrcTime = "+lrcTime);
			//添加时间点
			lrcTimes.add(lrcTime) ;
			//添加歌词
			lrcs.add(lrcStr) ;
		}
		
		
	}

}
需要解析的lrc歌词文件,自己可以去看,格式是差不多的,这里主要是提供了一种思路

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值