Browse Source

Merge branch 'developer' of https://gitlab.com/Arisono/SkWeiChat-Baidu into feature

# Conflicts:
#	WeiChat/version.properties
Arison 8 years ago
parent
commit
fff7806991

+ 3 - 3
WeiChat/version.properties

@@ -1,5 +1,5 @@
-#Thu May 24 08:45:11 CST 2018
-debugName=358
+#Thu May 24 09:03:45 CST 2018
+debugName=360
 versionName=630
-debugCode=358
+debugCode=360
 versionCode=170

+ 67 - 0
app_modular/appmusic/src/main/java/com/lg/lrcview_master/DefaultLrcParser.java

@@ -0,0 +1,67 @@
+package com.lg.lrcview_master;
+
+import android.text.TextUtils;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 默认的歌词解析器
+ * @author Ligang  2014/8/19
+ *
+ */
+public class DefaultLrcParser implements ILrcParser {
+	private static final DefaultLrcParser istance = new DefaultLrcParser();
+	
+	public static final DefaultLrcParser getIstance(){
+		return istance;
+	}
+	private DefaultLrcParser() {
+	}
+	/***
+	 * 将歌词文件里面的字符串 解析成一个List<LrcRow>
+	 */
+	@Override
+	public List<LrcRow> getLrcRows(String str) {
+		
+		if(TextUtils.isEmpty(str)){
+			return null;
+		}
+		BufferedReader br = new BufferedReader(new StringReader(str));
+		
+		List<LrcRow> lrcRows = new ArrayList<LrcRow>();
+		String lrcLine;
+		try {
+			while((lrcLine = br.readLine()) != null){
+				List<LrcRow> rows = LrcRow.createRows(lrcLine);
+				if(rows != null && rows.size() > 0){
+					lrcRows.addAll(rows);
+				}
+			}
+			Collections.sort(lrcRows);
+			
+			for (int i = 0; i < lrcRows.size()-1; i++) {
+				lrcRows.get(i).setTotalTime(lrcRows.get(i+1).getTime() - lrcRows.get(i).getTime());
+			}
+			lrcRows.get(lrcRows.size()-1).setTotalTime(5000);
+		} catch (IOException e) {
+			e.printStackTrace();
+			return null;
+		}finally{
+			if(br != null){
+				try {
+					br.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+		
+		return lrcRows;
+	}
+
+}

+ 13 - 0
app_modular/appmusic/src/main/java/com/lg/lrcview_master/ILrcParser.java

@@ -0,0 +1,13 @@
+package com.lg.lrcview_master;
+
+import java.util.List;
+
+/**
+ * 歌词解析器
+ * @author Ligang  2014/8/19
+ *
+ */
+public interface ILrcParser {
+
+	List<LrcRow> getLrcRows(String str);
+}

+ 35 - 0
app_modular/appmusic/src/main/java/com/lg/lrcview_master/ILrcView.java

@@ -0,0 +1,35 @@
+package com.lg.lrcview_master;
+
+import java.util.List;
+
+
+public interface ILrcView {
+	/**
+	 * 初始化画笔,颜色,字体大小等设置
+	 */
+	void init();
+	
+	/***
+	 * 设置数据源
+	 * @param lrcRows
+	 */
+	void setLrcRows(List<LrcRow> lrcRows);
+	
+	/**
+	 * 指定时间
+	 * @param progress  时间进度
+	 * @param fromSeekBarByUser 是否由用户触摸Seekbar触发
+	 */
+	void seekTo(int progress, boolean fromSeekBar, boolean fromSeekBarByUser);
+	
+	/***
+	 * 设置歌词文字的缩放比例
+	 * @param scalingFactor
+	 */
+	void setLrcScalingFactor(float scalingFactor);
+	
+	/**
+	 * 重置
+	 */
+	void reset();
+}

+ 118 - 0
app_modular/appmusic/src/main/java/com/lg/lrcview_master/LrcRow.java

@@ -0,0 +1,118 @@
+package com.lg.lrcview_master;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * 每行歌词的实体类,实现了Comparable接口,方便List<LrcRow>的sort排序
+ * @author Ligang  2014/8/19
+ *
+ */
+public class LrcRow implements Comparable<LrcRow>{
+
+	/**开始时间 为00:10:00***/
+	private String timeStr;
+	/**开始时间 毫米数  00:10:00  为10000**/
+	private int time;
+	/**歌词内容**/
+	private String content;
+	/**该行歌词显示的总时间**/
+	private int totalTime;
+	
+	public long getTotalTime() {
+		return totalTime;
+	}
+	public void setTotalTime(int totalTime) {
+		this.totalTime = totalTime;
+	}
+	public String getTimeStr() {
+		return timeStr;
+	}
+	public void setTimeStr(String timeStr) {
+		this.timeStr = timeStr;
+	}
+	public int getTime() {
+		return time;
+	}
+	public void setTime(int time) {
+		this.time = time;
+	}
+	public String getContent() {
+		return content;
+	}
+	public void setContent(String content) {
+		this.content = content;
+	}
+
+	public LrcRow() {
+		super();
+	}
+	public LrcRow(String timeStr, int time, String content) {
+		super();
+		this.timeStr = timeStr;
+		this.time = time;
+		this.content = content;
+	}
+	/**
+	 * 将歌词文件中的某一行 解析成一个List<LrcRow> 
+	 * 因为一行中可能包含了多个LrcRow对象
+	 * 比如  [03:33.02][00:36.37]当鸽子不再象征和平  ,就包含了2个对象
+	 * @param lrcLine
+	 * @return
+	 */
+	public static final List<LrcRow> createRows(String lrcLine){
+		if(!lrcLine.startsWith("[") || lrcLine.indexOf("]") != 9){
+			return null;
+		}
+		//最后一个"]" 
+		int lastIndexOfRightBracket = lrcLine.lastIndexOf("]");
+		//歌词内容
+		String content = lrcLine.substring(lastIndexOfRightBracket+1, lrcLine.length());
+		//截取出歌词时间,并将"[" 和"]" 替换为"-"   [offset:0]
+		System.out.println("lrcLine="+lrcLine);
+		// -03:33.02--00:36.37-
+		String times = lrcLine.substring(0, lastIndexOfRightBracket+1).replace("[", "-").replace("]", "-");
+		String[] timesArray = times.split("-");
+		List<LrcRow> lrcRows = new ArrayList<LrcRow>();
+		for (String tem : timesArray) {
+			if(TextUtils.isEmpty(tem.trim())){
+				continue;
+			}
+			//
+			try{
+				LrcRow lrcRow = new LrcRow(tem, formatTime(tem), content);
+				lrcRows.add(lrcRow);
+			}catch(Exception e){
+				Log.w("LrcRow", e.getMessage());
+			}
+		}
+		return lrcRows;
+	}
+	/****
+	 * 把歌词时间转换为毫秒值  如 将00:10.00  转为10000
+	 * @param tem
+	 * @return
+	 */
+	private static int formatTime(String timeStr) {
+		timeStr = timeStr.replace('.', ':');
+		String[] times = timeStr.split(":");
+
+		return Integer.parseInt(times[0])*60*1000
+				+ Integer.parseInt(times[1])*1000 
+				+ Integer.parseInt(times[2]);
+	}
+	@Override
+	public int compareTo(LrcRow anotherLrcRow) {
+		return (int) (this.time - anotherLrcRow.time);
+	}
+	@Override
+	public String toString() {
+		return "LrcRow [timeStr=" + timeStr + ", time=" + time + ", content="
+				+ content + "]";
+	} 
+
+
+}

+ 466 - 0
app_modular/appmusic/src/main/java/com/lg/lrcview_master/LrcView.java

@@ -0,0 +1,466 @@
+package com.lg.lrcview_master;
+
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.Scroller;
+
+import java.util.List;
+
+/***
+ * 
+ * 须知:
+ * 在ViewGroup里面 scrollTo,scrollBy方法移动的是子View
+ * 在View里面scrollTo,scrollBy方法移动的是View里面绘制的内容
+ * 要点:
+ * 1:歌词的上下平移用什么实现?
+ *    用Scroller实现,Scroller只是一个工具而已,
+ *    真正实现滚动效果的还是View的scrollTo方法
+ * 2:歌词的水平滚动怎么实现?
+ *    通过属性动画ValueAnimator控制高亮歌词绘制的x轴起始坐标
+ * 
+ * @author Ligang  2014/8/19
+ *
+ */
+public class LrcView extends View implements ILrcView {
+	/**所有的歌词***/
+	private List<LrcRow> mLrcRows;
+	/**无歌词数据的时候 显示的默认文字**/
+	private static final String DEFAULT_TEXT = "英唐智慧,全球共享";
+	/**默认文字的字体大小**/
+	private static final float SIZE_FOR_DEFAULT_TEXT = 60;
+
+	/**画高亮歌词的画笔***/
+	private Paint mPaintForHighLightLrc;
+	/**高亮歌词的默认字体大小***/
+	private static final float DEFAULT_SIZE_FOR_HIGHT_LIGHT_LRC = 37;
+	/**高亮歌词当前的字体大小***/
+	private float mCurSizeForHightLightLrc = DEFAULT_SIZE_FOR_HIGHT_LIGHT_LRC;
+	/**高亮歌词的默认字体颜色**/
+	private static final int DEFAULT_COLOR_FOR_HIGHT_LIGHT_LRC = 0xff2FABCF;
+	/**高亮歌词当前的字体颜色**/
+	private int mCurColorForHightLightLrc = DEFAULT_COLOR_FOR_HIGHT_LIGHT_LRC;
+
+	/**画其他歌词的画笔***/
+	private Paint mPaintForOtherLrc;
+	/**其他歌词的默认字体大小***/
+	private static final float DEFAULT_SIZE_FOR_OTHER_LRC = 32;
+	/**其他歌词当前的字体大小***/
+	private float mCurSizeForOtherLrc = DEFAULT_SIZE_FOR_OTHER_LRC;
+	/**高亮歌词的默认字体颜色**/
+	private static final int DEFAULT_COLOR_FOR_OTHER_LRC =  0xff666666;
+	/**高亮歌词当前的字体颜色**/
+	private int mCurColorForOtherLrc = DEFAULT_COLOR_FOR_OTHER_LRC;
+
+
+	/**画时间线的画笔***/
+	private Paint mPaintForTimeLine;
+	/***时间线的颜色**/
+	private static final int COLOR_FOR_TIME_LINE = 0xffD02090;
+	/**时间文字大小**/
+	private static final int SIZE_FOR_TIME = 18;
+	/**是否画时间线**/
+	private boolean mIsDrawTimeLine = false;
+
+	/**歌词间默认的行距**/
+	private static final float DEFAULT_PADDING = 50;
+	/**歌词当前的行距**/
+	private float mCurPadding = DEFAULT_PADDING;
+
+	/**歌词的最大缩放比例**/
+	public static final float MAX_SCALING_FACTOR = 2.5f;
+	/**歌词的最小缩放比例**/
+	public static final float MIN_SCALING_FACTOR = 1.5f;
+	/**默认缩放比例**/
+	private static final float DEFAULT_SCALING_FACTOR = 1.8f;
+	/**歌词的当前缩放比例**/
+	private float mCurScalingFactor = DEFAULT_SCALING_FACTOR;
+
+	/**实现歌词竖直方向平滑滚动的辅助对象**/
+	private Scroller mScroller;
+	/***移动一句歌词的持续时间**/
+	private static final int DURATION_FOR_LRC_SCROLL = 1500;
+	/***停止触摸时 如果View需要滚动 时的持续时间**/
+	private static final int DURATION_FOR_ACTION_UP = 400;
+
+	/**控制文字缩放的因子**/
+	private float mCurFraction = 0;
+	private int mTouchSlop;
+
+	public LrcView(Context context) {
+		super(context);
+		init();
+	}
+	public LrcView(Context context, AttributeSet attrs) {
+		super(context, attrs);
+		init();
+	}
+
+
+	/**
+	 * 初始化画笔等
+	 */
+	@Override
+	public void init() {
+		mScroller = new Scroller(getContext());
+		mPaintForHighLightLrc = new Paint();
+		mPaintForHighLightLrc.setColor(mCurColorForHightLightLrc);
+		mPaintForHighLightLrc.setTextSize(mCurSizeForHightLightLrc);
+
+		mPaintForOtherLrc = new Paint();
+		mPaintForOtherLrc.setColor(mCurColorForOtherLrc);
+		mPaintForOtherLrc.setTextSize(mCurSizeForOtherLrc);
+
+		mPaintForTimeLine = new Paint();
+		mPaintForTimeLine.setColor(COLOR_FOR_TIME_LINE);
+		mPaintForTimeLine.setTextSize(SIZE_FOR_TIME);
+
+		mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+	}
+
+	private int mTotleDrawRow;
+	@Override
+	protected void onDraw(Canvas canvas) {
+		super.onDraw(canvas);
+		if(mLrcRows == null || mLrcRows.size() == 0){
+			//画默认的显示文字
+			mPaintForOtherLrc.setTextSize(SIZE_FOR_DEFAULT_TEXT);
+			float textWidth = mPaintForOtherLrc.measureText(DEFAULT_TEXT);
+			float textX = (getWidth()-textWidth)/2;
+			canvas.drawText(DEFAULT_TEXT, textX, getHeight()/2, mPaintForOtherLrc);
+			return;
+		}
+		if(mTotleDrawRow == 0){
+			//初始化将要绘制的歌词行数
+			mTotleDrawRow = (int) (getHeight()/(mCurSizeForOtherLrc+mCurPadding))+4;
+		}
+		//因为不需要将所有歌词画出来
+		int minRaw = mCurRow - (mTotleDrawRow-1)/2;
+		int maxRaw = mCurRow + (mTotleDrawRow-1)/2;
+		minRaw = Math.max(minRaw, 0); //处理上边界
+		maxRaw = Math.min(maxRaw, mLrcRows.size()-1); //处理下边界
+		//实现渐变的最大歌词行数
+		int count = Math.max(maxRaw-mCurRow, mCurRow-minRaw);
+		//两行歌词间字体颜色变化的透明度
+		int alpha = (0xFF-0x11)/count;
+		//画出来的第一行歌词的y坐标
+		float rowY = getHeight()/2 + minRaw*(mCurSizeForOtherLrc + mCurPadding);
+		for (int i = minRaw; i <= maxRaw; i++) {
+
+			if(i == mCurRow){//画高亮歌词
+				//因为有缩放效果,所有需要动态设置歌词的字体大小
+				float textSize = mCurSizeForOtherLrc + (mCurSizeForHightLightLrc - mCurSizeForOtherLrc)*mCurFraction;
+				mPaintForHighLightLrc.setTextSize(textSize);
+
+				String text = mLrcRows.get(i).getContent();//获取到高亮歌词
+				float textWidth = mPaintForHighLightLrc.measureText(text);//用画笔测量歌词的宽度
+				if(textWidth > getWidth()){
+					//如果歌词宽度大于view的宽,则需要动态设置歌词的起始x坐标,以实现水平滚动
+					canvas.drawText(text, mCurTextXForHighLightLrc, rowY, mPaintForHighLightLrc);
+				}else{
+					//如果歌词宽度小于view的宽,则让歌词居中显示
+					float textX =  (getWidth()-textWidth)/2;
+					canvas.drawText(text, textX, rowY, mPaintForHighLightLrc);
+				}
+			}else{
+				if(i == mLastRow){//画高亮歌词的上一句
+					//因为有缩放效果,所有需要动态设置歌词的字体大小
+					float textSize = mCurSizeForHightLightLrc - (mCurSizeForHightLightLrc - mCurSizeForOtherLrc)*mCurFraction;
+					mPaintForOtherLrc.setTextSize(textSize);
+				}else{//画其他的歌词
+					mPaintForOtherLrc.setTextSize(mCurSizeForOtherLrc);
+				}
+				String text = mLrcRows.get(i).getContent();
+				float textWidth = mPaintForOtherLrc.measureText(text);
+				float textX = (getWidth()-textWidth)/2;
+				//如果计算出的textX为负数,将textX置为0(实现:如果歌词宽大于view宽,则居左显示,否则居中显示)
+				textX = Math.max(textX, 0);
+				//实现颜色渐变  从0xFFFFFFFF 逐渐变为 0x11FFFFFF(颜色还是白色,只是透明度变化)
+				int curAlpha = 255-(Math.abs(i-mCurRow)-1)*alpha; //求出当前歌词颜色的透明度
+				mPaintForOtherLrc.setColor(0x1000000*curAlpha+0xff666666);
+				canvas.drawText(text, textX, rowY, mPaintForOtherLrc);
+			}
+			//计算出下一行歌词绘制的y坐标
+			rowY += mCurSizeForOtherLrc + mCurPadding;
+		}
+
+		//画时间线和时间
+		if(mIsDrawTimeLine){
+			float y = getHeight()/2 + getScrollY();
+			canvas.drawText(mLrcRows.get(mCurRow).getTimeStr(), 0, y-5, mPaintForTimeLine);
+			canvas.drawLine(0, y, getWidth(), y, mPaintForTimeLine);
+		}
+
+	}
+	
+	/**是否可拖动歌词**/
+	private boolean canDrag = false;
+	/**事件的第一次的y坐标**/
+	private float firstY;
+	/**事件的上一次的y坐标**/
+	private float lastY;
+	private float lastX;
+	@Override
+	public boolean onTouchEvent(MotionEvent event) {
+		if(mLrcRows == null || mLrcRows.size() == 0){
+			return false;
+		}
+		switch (event.getAction()) {
+		case MotionEvent.ACTION_DOWN:
+			firstY = event.getRawY();
+			lastX = event.getRawX();
+			break;
+		case MotionEvent.ACTION_MOVE:
+			if(!canDrag){
+				if(Math.abs(event.getRawY() - firstY) > mTouchSlop && Math.abs(event.getRawY()-firstY) > Math.abs(event.getRawX()-lastX)){
+					canDrag = true;
+					mIsDrawTimeLine = true;
+					mScroller.forceFinished(true);
+					stopScrollLrc();
+					mCurFraction = 1;
+				}
+				lastY = event.getRawY();
+			}
+
+			if(canDrag){
+				float offset = event.getRawY() - lastY;//偏移量
+				if( getScrollY() - offset < 0){ 
+					if(offset > 0){
+						offset = offset/3;
+					}
+				}else if(getScrollY() - offset >mLrcRows.size()*(mCurSizeForOtherLrc+mCurPadding)-mCurPadding){
+					if(offset < 0 ){
+						offset = offset/3;
+					}
+				}
+				scrollBy(getScrollX(), -(int) offset);
+				lastY = event.getRawY();
+				int currentRow = (int) (getScrollY()/(mCurSizeForOtherLrc+mCurPadding));
+				currentRow = Math.min(currentRow, mLrcRows.size()-1);
+				currentRow = Math.max(currentRow, 0);
+				seekTo(mLrcRows.get(currentRow).getTime(), false,false);
+				return true;
+			}
+			lastY = event.getRawY();
+			break;
+		case MotionEvent.ACTION_UP:
+		case MotionEvent.ACTION_CANCEL:
+			if(!canDrag){
+				if(onLrcClickListener != null){
+					onLrcClickListener.onClick();
+				}
+			}else{
+				if(onSeekToListener!= null && mCurRow != -1){
+					onSeekToListener.onSeekTo(mLrcRows.get(mCurRow).getTime());
+				}
+				if(getScrollY() < 0){
+					smoothScrollTo(0,DURATION_FOR_ACTION_UP);
+				}else if(getScrollY() >mLrcRows.size()*(mCurSizeForOtherLrc+mCurPadding)-mCurPadding){
+					smoothScrollTo((int) (mLrcRows.size()*(mCurSizeForOtherLrc+mCurPadding)-mCurPadding),DURATION_FOR_ACTION_UP);
+				}
+
+				canDrag = false;
+				mIsDrawTimeLine = false;
+				invalidate();
+			}
+			break;
+		}
+		return true;
+	}
+	/**
+	 * 为LrcView设置歌词List集合数据
+	 */
+	@Override
+	public void setLrcRows(List<LrcRow> lrcRows) {
+		reset();
+		this.mLrcRows = lrcRows;
+		invalidate();
+	}
+
+	public List<LrcRow> getmLrcRows() {
+		return mLrcRows;
+	}
+	
+	/**当前高亮歌词的行号**/
+	private int mCurRow =-1;
+	/**上一次的高亮歌词的行号**/
+	private int mLastRow = -1;
+	
+	@Override
+	public void seekTo(int progress,boolean fromSeekBar,boolean fromSeekBarByUser) {
+		if(mLrcRows == null || mLrcRows.size() == 0){
+			return;
+		} 
+		//如果是由seekbar的进度改变触发 并且这时候处于拖动状态,则返回
+		if(fromSeekBar && canDrag){
+			return;
+		}
+		for (int i = mLrcRows.size()-1; i >= 0; i--) {
+
+			if(progress >= mLrcRows.get(i).getTime()){
+				if(mCurRow != i){
+					mLastRow = mCurRow;
+					mCurRow = i;
+					log("mCurRow=i="+mCurRow);
+					if(fromSeekBarByUser){
+						if(!mScroller.isFinished()){
+							mScroller.forceFinished(true);
+						}
+						scrollTo(getScrollX(), (int) (mCurRow * (mCurSizeForOtherLrc+mCurPadding)));
+					}else{
+						smoothScrollTo( (int) (mCurRow * (mCurSizeForOtherLrc+mCurPadding)), DURATION_FOR_LRC_SCROLL);
+					}
+					//如果高亮歌词的宽度大于View的宽,就需要开启属性动画,让它水平滚动
+					float textWidth = mPaintForHighLightLrc.measureText(mLrcRows.get(mCurRow).getContent());
+					log("textWidth="+textWidth+"getWidth()="+getWidth());
+					if(textWidth > getWidth()){
+						if(fromSeekBarByUser){
+							mScroller.forceFinished(true);
+						}
+						log("开始水平滚动歌词:"+mLrcRows.get(mCurRow).getContent());
+						startScrollLrc(getWidth()-textWidth, (long) (mLrcRows.get(mCurRow).getTotalTime()*0.6));
+					}
+					invalidate();
+				}
+				break;
+			}
+		}
+
+	}
+
+	/**控制歌词水平滚动的属性动画***/
+	private ValueAnimator mAnimator;
+	/**
+	 * 开始水平滚动歌词
+	 * @param endX 歌词第一个字的最终的x坐标
+	 * @param duration 滚动的持续时间
+	 */
+	private void startScrollLrc(float endX,long duration){
+		if(mAnimator == null){
+			mAnimator = ValueAnimator.ofFloat(0,endX);
+			mAnimator.addUpdateListener(updateListener);
+		}else{
+			mCurTextXForHighLightLrc = 0;
+			mAnimator.cancel();
+			mAnimator.setFloatValues(0,endX);
+		}
+		mAnimator.setDuration(duration);
+		mAnimator.setStartDelay((long) (duration*0.3)); //延迟执行属性动画
+		mAnimator.start();
+	}
+
+	/**
+	 * 停止歌词的滚动
+	 */
+	private void stopScrollLrc(){
+		if(mAnimator != null){
+			mAnimator.cancel();
+		}
+		mCurTextXForHighLightLrc = 0;
+	}
+	/**高亮歌词当前的其实x轴绘制坐标**/
+	private float mCurTextXForHighLightLrc;
+	/***
+	 * 监听属性动画的数值值的改变
+	 */
+	AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
+
+		@Override
+		public void onAnimationUpdate(ValueAnimator animation) {
+			//TODO
+			mCurTextXForHighLightLrc = (Float) animation.getAnimatedValue();
+			log("mCurTextXForHighLightLrc="+mCurTextXForHighLightLrc);
+			invalidate();
+		}
+	};
+	/**
+	 * 设置歌词的缩放比例
+	 */
+	@Override
+	public void setLrcScalingFactor(float scalingFactor) {
+		mCurScalingFactor = scalingFactor;
+		mCurSizeForHightLightLrc = DEFAULT_SIZE_FOR_HIGHT_LIGHT_LRC * mCurScalingFactor;
+		mCurSizeForOtherLrc = DEFAULT_SIZE_FOR_OTHER_LRC * mCurScalingFactor;
+		mCurPadding = DEFAULT_PADDING * mCurScalingFactor;
+		mTotleDrawRow = (int) (getHeight()/(mCurSizeForOtherLrc+mCurPadding))+3;
+		log("mRowTotal="+mTotleDrawRow);
+		scrollTo(getScrollX(), (int) (mCurRow*(mCurSizeForOtherLrc+mCurPadding)));
+		invalidate();
+		mScroller.forceFinished(true);
+	}
+	/**
+	 * 重置
+	 */
+	@Override
+	public void reset() {
+		if(!mScroller.isFinished()){
+			mScroller.forceFinished(true);
+		}
+		mLrcRows = null;
+		scrollTo(getScrollX(), 0);
+		invalidate();
+	}
+
+
+	/**
+	 * 平滑的移动到某处
+	 * @param dstY
+	 */
+	private void smoothScrollTo(int dstY,int duration){
+		int oldScrollY = getScrollY();
+		int offset = dstY - oldScrollY;
+		mScroller.startScroll(getScrollX(), oldScrollY, getScrollX(), offset, duration);
+		invalidate();
+	}
+
+	@Override
+	public void computeScroll() {
+		if (!mScroller.isFinished()) {
+			if (mScroller.computeScrollOffset()) {
+				int oldY = getScrollY();
+				int y = mScroller.getCurrY();
+				if (oldY != y && !canDrag) {
+					scrollTo(getScrollX(), y);
+				}
+				mCurFraction = mScroller.timePassed()*3f/DURATION_FOR_LRC_SCROLL;
+				mCurFraction = Math.min(mCurFraction, 1F);
+				invalidate();
+			}
+		} 
+	}
+	/**
+	 * 返回当前的歌词缩放比例
+	 * @return
+	 */
+	public float getmCurScalingFactor() {
+		return mCurScalingFactor;
+	}
+	
+	private OnSeekToListener onSeekToListener;
+	public void setOnSeekToListener(OnSeekToListener onSeekToListener) {
+		this.onSeekToListener = onSeekToListener;
+	}
+
+	public interface OnSeekToListener{
+		void onSeekTo(int progress);
+	}
+
+	private OnLrcClickListener onLrcClickListener;
+	public void setOnLrcClickListener(OnLrcClickListener onLrcClickListener) {
+		this.onLrcClickListener = onLrcClickListener;
+	}
+
+	public interface OnLrcClickListener{
+		void onClick();
+	}
+	public void log(Object o){
+		Log.d("LrcView", o+"");
+	}
+}

+ 271 - 0
app_modular/appmusic/src/main/java/com/usoftchina/pay/MainMusicActivity.java

@@ -0,0 +1,271 @@
+package com.usoftchina.pay;
+
+import android.media.MediaPlayer;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.core.utils.StatusBarUtil;
+import com.lg.lrcview_master.DefaultLrcParser;
+import com.lg.lrcview_master.LrcRow;
+import com.lg.lrcview_master.LrcView.OnLrcClickListener;
+import com.lg.lrcview_master.LrcView.OnSeekToListener;
+import com.usoftchina.music.R;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+
+public class MainMusicActivity extends AppCompatActivity {
+	private MediaPlayer mPlayer;
+	/**    控制播放的SeekBar***/
+	
+	private SeekBar mPlayerSeekBar;
+	/**控制歌词字体大小的SeekBar***/
+	private SeekBar mLrcSeekBar;
+	private Button mPlayBtn;
+	private com.lg.lrcview_master.LrcView mLrcView;
+	private	TextView tv_timeStart;
+	private	TextView tv_timeTotal;
+
+	private Toast mPlayerToast;
+	private Toast mLrcToast;
+	private Toolbar toolbar;
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_main_music);
+         
+		
+		initViews();
+		initPlayer();
+		toolbar=findViewById(R.id.commonToolBar);
+		StatusBarUtil.immersive(this, 0x00000000, 0.0f);
+		setSupportActionBar(toolbar);
+		getSupportActionBar().setDisplayShowTitleEnabled(false);
+		StatusBarUtil.setPaddingSmart(this, toolbar);
+
+		toolbar.setNavigationIcon(R.drawable.back_black);
+		toolbar.setNavigationOnClickListener(new OnClickListener() {
+			@Override
+			public void onClick(View view) {
+				onBackPressed();
+			}
+		});
+	}
+	private void initViews() {
+		mLrcView = (com.lg.lrcview_master.LrcView) findViewById(R.id.lrcView);
+		mLrcView.setOnSeekToListener(onSeekToListener);
+		mLrcView.setOnLrcClickListener(onLrcClickListener);
+		tv_timeStart = findViewById(R.id.tv_timeStart);
+		tv_timeTotal=findViewById(R.id.tv_timeTotal);
+		mPlayerSeekBar = (SeekBar) findViewById(R.id.include_player_seekbar);
+		mLrcSeekBar = (SeekBar) findViewById(R.id.include_lrc_seekbar);
+		mLrcSeekBar.setMax(100);
+		//为seekbar设置当前的progress
+		mLrcSeekBar.setOnSeekBarChangeListener(onSeekBarChangeListener);
+		new Handler().postDelayed(new Runnable() {
+			@Override
+			public void run() {
+				float scalingFactor = com.lg.lrcview_master.LrcView.MIN_SCALING_FACTOR + 0*(com.lg.lrcview_master.LrcView.MAX_SCALING_FACTOR- com.lg.lrcview_master.LrcView.MIN_SCALING_FACTOR)/100;
+				mLrcView.setLrcScalingFactor(scalingFactor);
+			}
+		},1000);
+		mPlayBtn = (Button) findViewById(R.id.btnPlay);
+		mPlayerSeekBar.setOnSeekBarChangeListener(onSeekBarChangeListener);
+		mPlayBtn.setOnClickListener(onClickListener);
+		//getCommonToolBar().setBackgroundResource(R.color.transparent);
+		
+	}
+
+	@Override
+	protected void onResume() {
+		super.onResume();
+	    
+	}
+
+	private void initPlayer() {
+		mPlayer = MediaPlayer.create(this, R.raw.yingtang);
+		mPlayer.setOnCompletionListener(onCompletionListener);
+	}
+	OnCompletionListener onCompletionListener = new OnCompletionListener() {
+		
+		@Override
+		public void onCompletion(MediaPlayer mp) {
+			mPlayBtn.setText("play");
+			mPlayBtn.setSelected(false);
+			mLrcView.reset();
+			handler.removeMessages(0);
+			mPlayerSeekBar.setProgress(0);
+		}
+	};
+	OnLrcClickListener onLrcClickListener = new OnLrcClickListener() {
+
+		@Override
+		public void onClick() {
+			//Toast.makeText(getApplicationContext(), "歌词被点击啦", Toast.LENGTH_SHORT).show();
+		}
+	};
+	OnSeekToListener onSeekToListener = new OnSeekToListener() {
+
+		@Override
+		public void onSeekTo(int progress) {
+			mPlayer.seekTo(progress);
+			
+		}
+	};
+	Handler handler = new Handler(){
+		public void handleMessage(android.os.Message msg) {
+			mPlayerSeekBar.setMax(mPlayer.getDuration());
+			mPlayerSeekBar.setProgress(mPlayer.getCurrentPosition());
+			handler.sendEmptyMessageDelayed(0, 100);
+		};
+	};
+	OnClickListener onClickListener = new OnClickListener() {
+
+		@Override
+		public void onClick(View v) {
+			if(v == mPlayBtn){
+				if("play".equals(mPlayBtn.getText())){
+					mPlayer.start();
+					mLrcView.setLrcRows(getLrcRows());
+					handler.sendEmptyMessage(0);
+					mPlayBtn.setText("暂停");
+					mPlayBtn.setSelected(true);
+				}else{
+
+					if(mPlayer.isPlaying()){
+						mPlayer.pause();
+						mPlayBtn.setText("播放");
+						mPlayBtn.setSelected(false);
+					}else{
+						mPlayBtn.setSelected(true);
+						mPlayer.start();
+						mPlayBtn.setText("暂停");
+					}
+				}
+			}
+		}
+	};
+
+	OnSeekBarChangeListener onSeekBarChangeListener = new OnSeekBarChangeListener() {
+
+		@Override
+		public void onStopTrackingTouch(SeekBar seekBar) {
+			if(seekBar == mPlayerSeekBar){
+				mPlayer.seekTo(seekBar.getProgress());
+				handler.sendEmptyMessageDelayed(0, 100);
+			}
+		}
+
+		@Override
+		public void onStartTrackingTouch(SeekBar seekBar) {
+			if(seekBar == mPlayerSeekBar){
+				handler.removeMessages(0);
+			}
+		}
+
+		@Override
+		public void onProgressChanged(SeekBar seekBar, int progress,
+				boolean fromUser) {
+			if(seekBar == mPlayerSeekBar){
+				mLrcView.seekTo(progress, true,fromUser);
+//				Log.d("timeStr",mLrcView.getmLrcRows().get(0).getTime()+"");
+				Log.d("timeStrA",progress+"");
+				tv_timeStart.setText(formatTimeFromProgress(progress));
+				tv_timeTotal.setText(formatTimeFromProgress(mPlayer.getDuration()));
+				if(fromUser){
+					
+					showPlayerToast(formatTimeFromProgress(progress));
+				}
+			}else if(seekBar == mLrcSeekBar){
+				float scalingFactor = com.lg.lrcview_master.LrcView.MIN_SCALING_FACTOR + progress*(com.lg.lrcview_master.LrcView.MAX_SCALING_FACTOR- com.lg.lrcview_master.LrcView.MIN_SCALING_FACTOR)/100;
+				mLrcView.setLrcScalingFactor(scalingFactor);
+				showLrcToast((int)(scalingFactor*100)+"%");
+			}
+		}
+
+	};
+	/**
+	 * 将播放进度的毫米数转换成时间格式
+	 * 如 3000 --> 00:03 
+	 * @param progress
+	 * @return
+	 */
+	private String formatTimeFromProgress(int progress){
+		//总的秒数 
+		int msecTotal = progress/1000;
+		int min = msecTotal/60;
+		int msec = msecTotal%60;
+		String minStr = min < 10 ? "0"+min:""+min;
+		String msecStr = msec < 10 ? "0"+msec:""+msec;
+		return minStr+":"+msecStr;
+	}
+	/**
+	 * 获取歌词List集合
+	 * @return
+	 */
+	private List<LrcRow> getLrcRows(){
+		List<LrcRow> rows = null;
+		InputStream is = getResources().openRawResource(R.raw.yingtanglrc);
+		BufferedReader br = new BufferedReader(new InputStreamReader(is));
+		String line ;
+		StringBuffer sb = new StringBuffer();
+		try {
+			while((line = br.readLine()) != null){
+				sb.append(line+"\n");
+			}
+			System.out.println(sb.toString());
+			rows = DefaultLrcParser.getIstance().getLrcRows(sb.toString());
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		return rows;
+	}
+
+	private TextView mPlayerToastTv;
+	private void showPlayerToast(String text){
+		if(mPlayerToast == null){
+			mPlayerToast = new Toast(this);
+			mPlayerToastTv = (TextView) LayoutInflater.from(this).inflate(R.layout.toast, null);
+			mPlayerToast.setView(mPlayerToastTv);
+			mPlayerToast.setDuration(Toast.LENGTH_SHORT);
+		}
+		mPlayerToastTv.setText(text);
+		mPlayerToast.show();
+	}
+	private TextView mLrcToastTv;
+	private void showLrcToast(String text){
+		if(mLrcToast == null){
+			mLrcToast = new Toast(this);
+			mLrcToastTv = (TextView) LayoutInflater.from(this).inflate(R.layout.toast, null);
+			mLrcToast.setView(mLrcToastTv);
+			mLrcToast.setDuration(Toast.LENGTH_SHORT);
+		}
+		mLrcToastTv.setText(text);
+		mLrcToast.show();
+	}
+	
+	@Override
+	protected void onDestroy() {
+		super.onDestroy();
+		handler.removeMessages(0);
+		mPlayer.stop();
+		mPlayer.release();
+		mPlayer = null;
+		mLrcView.reset();
+	}
+}