7 Commits d2ce08bac1 ... 362c80a945

Author SHA1 Message Date
  LAPTOP-K69FCNBP\crius 362c80a945 Merge branch 'master' of http://116.62.119.248:10082/cheng_zq/EffectDemo into lwz_ 2 years ago
  LAPTOP-K69FCNBP\crius 5d3f2556d1 Merge branch 'master' of http://116.62.119.248:10082/cheng_zq/EffectDemo into lwz_ 2 years ago
  czq 34325f622c 单词泛红控件修改 2 years ago
  czq 28e092e151 Merge branch 'master' into czq 2 years ago
  czq 232e59a8f6 单词泛红控件修改 2 years ago
  czq 18e71e20ee 调用单词泛红接口 2 years ago
  czq d26b6c45e5 Rename .java to .kt 2 years ago

+ 1 - 9
.idea/misc.xml

@@ -25,15 +25,7 @@
         <entry key="..\:/Progect/gitee/EffectDemo/app/src/main/res/layout/activity_view.xml" value="0.25" />
         <entry key="..\:/Progect/gitee/EffectDemo/app/src/main/res/layout/activity_web.xml" value="0.1816123188405797" />
         <entry key="..\:/Progect/gitee/EffectDemo/app/src/main/res/layout/demo_activity.xml" value="0.18020833333333333" />
-        <entry key="..\:/work/mozhi/qiqu/EffectDemo/app/src/main/res/drawable/check_box_bg.xml" value="0.289" />
-        <entry key="..\:/work/mozhi/qiqu/EffectDemo/app/src/main/res/drawable/drag_hint_bg.xml" value="0.222" />
-        <entry key="..\:/work/mozhi/qiqu/EffectDemo/app/src/main/res/drawable/drag_success_bg.xml" value="0.222" />
-        <entry key="..\:/work/mozhi/qiqu/EffectDemo/app/src/main/res/drawable/edit_bg.xml" value="0.289" />
-        <entry key="..\:/work/mozhi/qiqu/EffectDemo/app/src/main/res/drawable/role_bg.xml" value="0.2205" />
-        <entry key="..\:/work/mozhi/qiqu/EffectDemo/app/src/main/res/drawable/role_border_yellow_bg.xml" value="0.2205" />
-        <entry key="..\:/work/mozhi/qiqu/EffectDemo/app/src/main/res/layout/activity_drag_select.xml" value="0.5028571428571429" />
-        <entry key="..\:/work/mozhi/qiqu/EffectDemo/app/src/main/res/layout/activity_role_play.xml" value="0.22" />
-        <entry key="..\:/work/mozhi/qiqu/EffectDemo/app/src/main/res/layout/item_role.xml" value="0.18333333333333332" />
+        <entry key="..\:/Progect/gitee/EffectDemo/app/src/main/res/layout/item_word_sound.xml" value="0.10190217391304347" />
       </map>
     </option>
   </component>

+ 1 - 0
app/build.gradle

@@ -173,4 +173,5 @@ dependencies {
     implementation 'io.reactivex.rxjava2:rxjava:2.2.8'
     implementation 'com.zhy:okhttputils:2.6.2'
     implementation 'com.squareup.okhttp3:okhttp:4.2.2'
+    implementation 'com.hyman:flowlayout-lib:1.1.2'
 }

+ 7 - 6
app/src/main/AndroidManifest.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
-    package="com.xunao.effectdemo">
+    package="com.xunao.effectdemo" >
 
     <uses-sdk tools:overrideLibrary="com.qmuiteam.qmui" />
 
@@ -31,8 +31,8 @@
         android:roundIcon="@mipmap/ic_launcher_round"
         android:supportsRtl="true"
         android:theme="@style/AppTheme"
-        android:usesCleartextTraffic="true">
-        <activity android:name=".activity.MainActivity">
+        android:usesCleartextTraffic="true" >
+        <activity android:name=".activity.MainActivity" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
 
@@ -77,7 +77,7 @@
             android:name=".receiver.MyService"
             android:enabled="true"
             android:exported="false"
-            android:process=":pushcore">
+            android:process=":pushcore" >
             <intent-filter>
                 <action android:name="cn.jiguang.user.service.action" />
             </intent-filter>
@@ -86,7 +86,7 @@
         <receiver
             android:name=".receiver.PushMessageReceiver"
             android:enabled="true"
-            android:exported="false">
+            android:exported="false" >
             <intent-filter>
                 <action android:name="cn.jpush.android.intent.RECEIVE_MESSAGE" />
 
@@ -98,7 +98,7 @@
             android:name="cn.jiguang.union.ads.service.JAdFileProvider"
             android:authorities="${applicationId}.JAdFileProvider"
             android:exported="false"
-            android:grantUriPermissions="true">
+            android:grantUriPermissions="true" >
             <meta-data
                 android:name="android.support.FILE_PROVIDER_PATHS"
                 android:resource="@xml/jpush_file_paths" />
@@ -144,6 +144,7 @@
         <activity
             android:name=".activity.DragActivity"
             android:screenOrientation="landscape" />
+        <activity android:name=".activity.NewSongLyricActivity"/>
     </application>
 
 </manifest>

+ 23 - 0
app/src/main/java/com/xunao/effectdemo/activity/MapChallengeActivity.java

@@ -58,6 +58,10 @@ public class MapChallengeActivity extends Activity {
             startActivity(intent);
         });
         btnMap5 = findViewById(R.id.btn_map_5);
+        btnMap5.setOnClickListener(v->{
+            intent = new Intent(MapChallengeActivity.this, NewSongLyricActivity.class);
+            startActivity(intent);
+        });
         btnMap6 = findViewById(R.id.btn_map_6);
         btnMap6.setOnClickListener(v -> {
             intent = new Intent(MapChallengeActivity.this, RolePlayActivity.class);
@@ -83,4 +87,23 @@ public class MapChallengeActivity extends Activity {
         });
     }
 
+    void getMap(){
+        Map<String, String> params = new HashMap<>();
+        params.put("member_id",member_id);
+        params.put("token",token);
+        params.put("student_id",student_id);
+        params.put("maps_id",maps_id);
+        ApiHttpClient.get(ApiUrl.getMap,params, new CSMHttpCallback() {
+            @Override
+            protected void onSuccess(String jsonStr) {
+
+            }
+
+            @Override
+            protected void onFail(String msg) {
+
+            }
+        });
+    }
+
 }

+ 267 - 0
app/src/main/java/com/xunao/effectdemo/activity/NewSongLyricActivity.java

@@ -0,0 +1,267 @@
+package com.xunao.effectdemo.activity;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.graphics.Color;
+import android.media.MediaPlayer;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.xunao.effectdemo.R;
+import com.xunao.effectdemo.bean.MediaBean;
+import com.xunao.effectdemo.bean.WordTimeBean;
+import com.xunao.effectdemo.net.ApiHttpClient;
+import com.xunao.effectdemo.net.ApiUrl;
+import com.xunao.effectdemo.net.CSMHttpCallback;
+import com.xunao.effectdemo.view.SongLyricTextView;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import com.xunao.effectdemo.bean.MediaBean.ResultBean.ListBean.*;
+import com.zhy.view.flowlayout.FlowLayout;
+import com.zhy.view.flowlayout.TagAdapter;
+import com.zhy.view.flowlayout.TagFlowLayout;
+
+/**
+ * author : 程中强
+ * e-mail : 740479946@qq.com
+ * date : 2022/9/2214:43
+ * desc :
+ * version: 1.0
+ */
+public class NewSongLyricActivity extends Activity {
+
+	private SongLyricTextView textView;
+	private Button start,stop;
+	private MediaPlayer mediaPlayer;
+	private String TAG = "NewSongLyricActivity";
+	private TagFlowLayout flowLayout;
+
+	private String lyric = "你发如雪\n" +
+			"凄美了离别\n" +
+			"我焚香感动了谁\n" +
+			"邀明月让回忆皎洁\n" +
+			"爱在月光下完美\n" +
+			"你发如雪\n" +
+			"纷飞了眼泪\n" +
+			"我等待苍老了谁\n" +
+			"红尘醉微醺的岁月\n" +
+			"我用无悔\n" +
+			"刻永世爱你的碑";
+
+	private String token = "MWIzYmVmOTdiYzI5Y2UwM2ZiOThlMTI3YjRmYWJlNzA=";
+	private String member_id = "61128";
+	private String steps_id = "48671";
+	private String student_id = "180721";
+	private String[] lyricList;
+	private List<StepsLyricjsonBean> wordList = new ArrayList<>();
+	private List<String> list = new ArrayList<>();
+	private List<String> timeList = new ArrayList<>();
+	private List<WordTimeBean> beanList = new ArrayList<>();
+	private WordTimeBean timeBean,currBean;
+
+	@Override
+	protected void onCreate(@Nullable Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_songe);
+		init();
+	}
+
+	void init(){
+		textView = findViewById(R.id.text);
+		start = findViewById(R.id.start);
+		stop = findViewById(R.id.end);
+		start.setOnClickListener(v->{
+			if(mediaPlayer.isPlaying()){
+				mediaPlayer.seekTo(0);
+			}else{
+				mediaPlayer.start();
+			}
+			startPlay();
+		});
+		stop.setOnClickListener(v->{
+			mediaPlayer.pause();
+//			textView.stopPlay();
+			handler.removeCallbacks(runnable);
+		});
+		mediaPlayer = new MediaPlayer();
+		flowLayout = findViewById(R.id.tab_flowlayout);
+		getMedia();
+//		setFlowData();
+	}
+
+	void getMedia(){
+		Map<String, String> params = new HashMap<>();
+		params.put("member_id",member_id);
+		params.put("token",token);
+		params.put("student_id",student_id);
+		params.put("steps_id",steps_id);
+		ApiHttpClient.get(ApiUrl.getMapsStepsMedias,params, new CSMHttpCallback() {
+			@Override
+			protected void onSuccess(String jsonStr) {
+				MediaBean mediaBean = MediaBean.parse(jsonStr);
+				wordList = mediaBean.getResult().getList().getSteps_lyricjson();
+				setWord(wordList);
+
+				mediaPlayer.setOnPreparedListener(mp -> Log.i(TAG,"onPrepared:准备完成"));
+				mediaPlayer.setOnCompletionListener(mp -> Log.i(TAG,"OnCompletion:播放完成"));
+				try {
+					mediaPlayer.setDataSource(mediaBean.getResult().getList().getSteps_mp3url());
+					mediaPlayer.prepareAsync();// 开始在后台缓冲音频文件并返回
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+
+			@Override
+			protected void onFail(String msg) {
+
+			}
+		});
+	}
+
+	private void setWord(List<StepsLyricjsonBean> wordList){
+		String msg = "";
+		list.clear();
+		for (StepsLyricjsonBean bean:wordList) {
+
+			for (int i = 0; i < bean.getWord().size(); i++) {
+				String w = bean.getWord().get(i).replaceAll("<i>","\n    ");
+				if (w.contains("\n"))Log.e("MyTag","长度"+w.length());
+				list.add(w);
+				timeList.add(bean.getWordtims().get(i));
+
+				timeBean = new WordTimeBean();
+				timeBean.setStartTime(Integer.parseInt(bean.getStarttime()));
+				timeBean.setEndTime(Integer.parseInt(bean.getEndtime()));
+				timeBean.setWord(w);
+				timeBean.setTime(Integer.parseInt(bean.getWordtims().get(i)));
+				beanList.add(timeBean);
+
+				msg+=w;
+			}
+		}
+		textView.setText(msg);
+		setFlowData();
+	}
+	private int num = 0;
+	private int canTime = 0;
+	private int normal = 0;
+	private Handler handler = new Handler(){
+		@SuppressLint("HandlerLeak")
+		@Override
+		public void handleMessage(@NonNull Message msg) {
+			super.handleMessage(msg);
+			switch (msg.what){
+				case 1001:
+					if (currBean==null){timeBean = beanList.get(num);}
+//					Log.e("MyTag","当前:"+timeBean.toString()+"   "+time);
+					if (timeBean.getStartTime()+canTime > time&& timeBean.getStartTime() + canTime-time   <100){
+						num++;
+						if (num==beanList.size()){
+							num = 0;
+						}
+						if (timeBean.getTime()+timeBean.getStartTime()+canTime == timeBean.getEndTime()){
+							canTime =0;
+//							normal = startIndex;
+//							textView.startNormalLine(
+//									0,
+//									startIndex);
+						}else{
+							canTime +=timeBean.getTime();
+						}
+
+						textView.startPlayLine(
+								startIndex,
+								startIndex + timeBean.getWord().length(), // 因为有个换行符,所以 + 1
+								1);
+						startIndex += timeBean.getWord().length();
+						timeBean = beanList.get(num);
+					}
+					break;
+			}
+		}
+	};
+	int startIndex = 0;
+	long delayTime = 0L;
+
+	void startPlay(){
+//		String[] lyricList = lyric.split("\n");
+		handler.post(runnable);
+	}
+
+
+	Timer timer;
+	int time = 0;
+	private Runnable runnable = new Runnable() {
+		@Override
+		public void run() {
+			timer=new Timer();
+			timer.schedule(new TimerTask() {
+				@Override
+				public void run() {
+					//定义一个消息传过去
+					Message msg=new Message();
+					msg.what=1001;
+					handler.sendMessage(msg);
+					time+=50;
+				}
+			},0,50); //延时0毫秒开始计时,每隔1秒计时一
+			//次
+		}
+	};
+
+	@Override
+	protected void onDestroy() {
+		super.onDestroy();
+		mediaPlayer.stop();
+	}
+
+	/**
+	 * 给流式布局设置值
+	 */
+	private void setFlowData() {
+
+		flowLayout.setAdapter(new TagAdapter<String>(list) {
+			@Override
+			public View getView(FlowLayout parent, int position, String s) {
+
+				LayoutInflater inflater = LayoutInflater.from(getApplication());
+				TextView textView = (TextView) inflater.inflate(R.layout.item_word_sound, flowLayout, false);
+
+				textView.setText(s);
+				return textView;
+			}
+			//当选中的时候
+			@Override
+			public void onSelected(int position, View view) {
+				super.onSelected(position, view);
+				TextView textView = (TextView) view;
+				textView.setTextColor(Color.parseColor("#FFFFFF"));
+			}
+
+			//当没选中的时候
+			@Override
+			public void unSelected(int position, View view) {
+				super.unSelected(position, view);
+				TextView textView = (TextView) view;
+				textView.setTextColor(Color.parseColor("#000000"));
+			}
+		});
+	}
+}

+ 29 - 0
app/src/main/java/com/xunao/effectdemo/activity/SongLyricActivity.kt

@@ -1,8 +1,13 @@
 package com.xunao.effectdemo.activity
 
 import android.os.Bundle
+import android.util.Log
 import androidx.appcompat.app.AppCompatActivity
 import com.xunao.effectdemo.R
+import com.xunao.effectdemo.bean.MediaBean
+import com.xunao.effectdemo.net.ApiHttpClient
+import com.xunao.effectdemo.net.ApiUrl
+import com.xunao.effectdemo.net.CSMHttpCallback
 import kotlinx.android.synthetic.main.activity_songe.*
 import kotlin.math.min
 
@@ -27,6 +32,11 @@ class SongLyricActivity : AppCompatActivity() {
             "我用无悔\n" +
             "刻永世爱你的碑"
 
+    private val token = "MWIzYmVmOTdiYzI5Y2UwM2ZiOThlMTI3YjRmYWJlNzA="
+    private val member_id = "61128"
+    private val steps_id = "48671";
+    private val student_id = "180721"
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_songe)
@@ -65,6 +75,25 @@ class SongLyricActivity : AppCompatActivity() {
             text.stopPlay()
         }
 
+        getMedia()
+    }
 
+    fun getMedia(){
+        var params = mapOf("member_id" to member_id,
+            "token" to token,
+            "student_id" to student_id,
+            "steps_id" to steps_id)
+        ApiHttpClient.get(ApiUrl.getMapsStepsMedias,params, object : CSMHttpCallback(){
+            override fun onSuccess(jsonStr: String?) {
+//                TODO("Not yet implemented")
+                Log.e("MyTag","json:"+jsonStr)
+                var mediaBean = MediaBean.parse(jsonStr)
+                text.text = mediaBean.result.list.steps_lyricjson.get(0).word.get(0)
+            }
+
+            override fun onFail(msg: String?) {
+                TODO("Not yet implemented")
+            }
+        })
     }
 }

+ 0 - 61
app/src/main/java/com/xunao/effectdemo/activity/WebActivity.java

@@ -1,61 +0,0 @@
-package com.xunao.effectdemo.activity;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-
-import androidx.annotation.Nullable;
-
-import com.xunao.effectdemo.R;
-
-/**
- * author : 程中强
- * e-mail : 740479946@qq.com
- * date : 2022/8/2917:40
- * desc :
- * version: 1.0
- */
-public class WebActivity extends Activity {
-
-	@Override
-	protected void onCreate(@Nullable Bundle savedInstanceState) {
-		super.onCreate(savedInstanceState);
-		setContentView(R.layout.activity_web);
-
-
-		WebView webview = findViewById(R.id.webview);
-		WebSettings webSettings = webview.getSettings();
-		webSettings.setDomStorageEnabled(true);
-		webSettings.setJavaScriptEnabled(true);
-		webSettings.setBlockNetworkImage(false);
-		webSettings.setBuiltInZoomControls(true);
-		// 覆盖WebView默认使用第三方或系统默认浏览器打开网页的行为,使网页用WebView打开
-		webview.setWebViewClient(new WebViewClient() {
-			@Override
-			public boolean shouldOverrideUrlLoading(WebView view, String url) {
-//                view.loadUrl(url);
-//                return true;
-
-				if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("ftp")) {
-					view.loadUrl(url);
-					return true;
-				} else if (url.startsWith("scheme://")) {
-					// 使用浏览器打开
-					Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
-					startActivity(intent);
-					return true;
-				} else {
-					return false;
-				}
-
-			}
-		});
-
-		webview.loadUrl("http://waibao.kidcastle.org/smallgame/tiaoyitiao/zjreplay.html");
-
-	}
-}

+ 59 - 0
app/src/main/java/com/xunao/effectdemo/activity/WebActivity.kt

@@ -0,0 +1,59 @@
+package com.xunao.effectdemo.activity
+
+import android.app.Activity
+import android.os.Bundle
+import android.webkit.WebSettings
+import android.webkit.WebViewClient
+import android.content.Intent
+import android.net.Uri
+import android.webkit.WebView
+import com.xunao.effectdemo.R
+import com.xunao.effectdemo.net.ApiHttpClient
+import com.xunao.effectdemo.net.ApiUrl
+import com.xunao.effectdemo.net.CSMHttpCallback
+
+/**
+ * author : 程中强
+ * e-mail : 740479946@qq.com
+ * date : 2022/8/2917:40
+ * desc :
+ * version: 1.0
+ */
+class WebActivity : Activity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.activity_web)
+        val webview = findViewById<WebView>(R.id.webview)
+        val webSettings = webview.settings
+        webSettings.domStorageEnabled = true
+        webSettings.javaScriptEnabled = true
+        webSettings.blockNetworkImage = false
+        webSettings.builtInZoomControls = true
+        // 覆盖WebView默认使用第三方或系统默认浏览器打开网页的行为,使网页用WebView打开
+        webview.webViewClient = object : WebViewClient() {
+            override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
+//                view.loadUrl(url);
+//                return true;
+                return if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("ftp")) {
+                    view.loadUrl(url)
+                    true
+                } else if (url.startsWith("scheme://")) {
+                    // 使用浏览器打开
+                    val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
+                    startActivity(intent)
+                    true
+                } else {
+                    false
+                }
+            }
+        }
+        webview.loadUrl("http://waibao.kidcastle.org/smallgame/tiaoyitiao/zjreplay.html")
+    }
+
+    fun login() {
+        ApiHttpClient.get(ApiUrl.login, object : CSMHttpCallback() {
+            override fun onSuccess(jsonStr: String) {}
+            override fun onFail(msg: String) {}
+        })
+    }
+}

File diff suppressed because it is too large
+ 27 - 0
app/src/main/java/com/xunao/effectdemo/bean/MediaBean.java


+ 58 - 0
app/src/main/java/com/xunao/effectdemo/bean/WordTimeBean.java

@@ -0,0 +1,58 @@
+package com.xunao.effectdemo.bean;
+
+/**
+ * author : 程中强
+ * e-mail : 740479946@qq.com
+ * date : 2022/9/2314:28
+ * desc :
+ * version: 1.0
+ */
+public class WordTimeBean {
+
+	private String word;
+	private int time;
+	private int startTime;
+	private int endTime;
+
+	public String getWord() {
+		return word;
+	}
+
+	public void setWord(String word) {
+		this.word = word;
+	}
+
+	public int getTime() {
+		return time;
+	}
+
+	public void setTime(int time) {
+		this.time = time;
+	}
+
+	public int getStartTime() {
+		return startTime;
+	}
+
+	public void setStartTime(int startTime) {
+		this.startTime = startTime;
+	}
+
+	public int getEndTime() {
+		return endTime;
+	}
+
+	public void setEndTime(int endTime) {
+		this.endTime = endTime;
+	}
+
+	@Override
+	public String toString() {
+		return "WordTimeBean{" +
+				"word='" + word + '\'' +
+				", time='" + time + '\'' +
+				", startTime='" + startTime + '\'' +
+				", endTime='" + endTime + '\'' +
+				'}';
+	}
+}

+ 0 - 1
app/src/main/java/com/xunao/effectdemo/net/ApiHttpClient.java

@@ -80,7 +80,6 @@ public class ApiHttpClient {
         for (String key:params.keySet()){
             url = (url==null?"":(url+"&"))+key+"="+params.get(key);
         }
-        Log.e("MyTag","路径:"+url);
         return partUrl+"?"+url;
     }
 

+ 4 - 0
app/src/main/java/com/xunao/effectdemo/net/ApiUrl.java

@@ -11,4 +11,8 @@ public class ApiUrl {
 
     public static final String login = url+"Base/Login";
 
+    public static final String getMap = url+"Goover/getMapsResource";
+
+    public static final String  getMapsStepsMedias = url + "Goover/getMapsStepsMedias";
+
 }

+ 61 - 2
app/src/main/java/com/xunao/effectdemo/view/SongLyricTextView.kt

@@ -27,7 +27,7 @@ class SongLyricTextView @JvmOverloads constructor(
     /**
      * 文字播放的颜色
      * */
-    private val playColor = Color.parseColor("#fec403")
+    private val playColor = Color.parseColor("#ff0000")
 
     /**
      * 要变色的宽度
@@ -38,8 +38,10 @@ class SongLyricTextView @JvmOverloads constructor(
      * 是否正在播放中
      * */
     private var isPlaying = false
+    private var isNormal = false
 
     private val mPaint = paint
+    private val mPaint2 = paint//原来的颜色
 
     /**
      * 要变色的区域
@@ -106,6 +108,45 @@ class SongLyricTextView @JvmOverloads constructor(
             mPaint.color = playColor
             layout.draw(canvas)
         }
+        if (isNormal) {
+            path.reset()
+            val lineCount = layout.lineCount
+            val content = text.toString()
+            for (i in 0 until lineCount) {
+                // 计算一行文字的宽度
+                val lineWidth = mPaint.measureText(
+                    content.substring(layout.getLineStart(i), layout.getLineEnd(i))
+                )
+
+                if (lineWidth <= consumeWidth) {
+                    // 如果是之前已经变色区域,直接添加到path中
+//                    consumeWidth -= lineWidth
+//                    path.addRect(
+//                        layout.getLineLeft(i),
+//                        layout.getLineTop(i).toFloat(),
+//                        layout.getLineRight(i),
+//                        layout.getLineBottom(i).toFloat(),
+//                        Path.Direction.CCW
+//                    )
+                } else {
+                    // 如果该行正好是要变色的行,直接改变颜色
+                    // 把需要的consumeWidth放入path中
+                    path.addRect(
+                        layout.getLineLeft(i),
+                        layout.getLineTop(i).toFloat(),
+                        layout.getLineLeft(i) + consumeWidth,
+                        layout.getLineBottom(i).toFloat(),
+                        Path.Direction.CCW
+                    )
+                    break
+                }
+            }
+            // 设置需要绘制的区域,并着色
+            canvas.clipPath(path)
+            mPaint.color = normalColor
+            layout.draw(canvas)
+            isNormal = false
+        }
     }
 
     /**
@@ -121,7 +162,24 @@ class SongLyricTextView @JvmOverloads constructor(
         val startWidth = mPaint.measureText(this.text.substring(0, startIndex))
         val endWidth = startWidth + mPaint.measureText(this.text.substring(startIndex, endIndex))
         animator.setFloatValues(startWidth, endWidth)
-        animator.duration = if (duration > 0) duration else 1000
+        animator.duration = if (duration > 0) duration else 10
+        animator.start()
+    }
+
+    /**
+     * 开始播放
+     *
+     * @param startIndex 开始的文字的索引
+     * @param endIndex 结束的文字的索引
+     * @param duration 播放时长
+     * */
+    fun startNormalLine(startIndex: Int, endIndex: Int) {
+        isNormal = true
+        if (startIndex == -1) return
+        val startWidth = mPaint.measureText(this.text.substring(0, startIndex))
+        val endWidth = startWidth + mPaint.measureText(this.text.substring(startIndex, endIndex))
+        animator.setFloatValues(startWidth, endWidth)
+        animator.duration = 0
         animator.start()
     }
 
@@ -130,6 +188,7 @@ class SongLyricTextView @JvmOverloads constructor(
      * */
     fun stopPlay() {
         isPlaying = false
+        isNormal = false
         animator.cancel()
         invalidate()
     }

+ 16 - 3
app/src/main/res/layout/activity_songe.xml

@@ -1,15 +1,16 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:zhy="http://schemas.android.com/tools"
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-
     <com.xunao.effectdemo.view.SongLyricTextView
         android:id="@+id/text"
+
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center"
+        android:layout_height="400dp"
+
         android:lineSpacingExtra="6dp"
         android:text="Hello World!"
         android:textSize="16sp"
@@ -17,6 +18,18 @@
         app:layout_constraintLeft_toLeftOf="parent"
         app:layout_constraintRight_toRightOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
+    <ScrollView
+        android:visibility="gone"
+        android:layout_width="match_parent"
+        android:layout_height="400dp">
+
+
+        <com.zhy.view.flowlayout.TagFlowLayout
+            android:id="@+id/tab_flowlayout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            zhy:max_select="-1"/>
+    </ScrollView>
 
     <Button
         android:id="@+id/start"

+ 8 - 0
app/src/main/res/layout/item_word_sound.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tv_word"
+    android:textSize="16sp"
+    android:textColor="#000"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+</TextView>

Some files were not shown because too many files changed in this diff