Android 사용자 정의 View 의 심 플 한 가사 컨트롤 실전 안내
최근 에는 이전 음악 재생 기 를 재 구성 해 가사,다운로드 기능 등 다양한 기능 을 추가 했다.이 글 은 가사 컨트롤 의 실현 에 대해 이야기 하고 효과 도 를 먼저 올 리 며 불가사리 가 느껴 지면 계속 보 자!
여 기 를 보면 이 컨트롤 에 관심 이 있 을 거 예요.그럼 이 가사 컨트롤 을 실현 하기 위해 무엇 을 해 야 하 는 지 봅 시다!
가사
우선,우 리 는 정상 적 인 가사 형식 이 어떤 지 알 아야 한다.대략 이렇게 생 겼 다.
1[ti:좋아해요]
2[ar:.]
3[al:]
4[by:]
5[offset:0]
6[00:0.10]널 좋아해-G.E.M.덩 쯔 기(젬 탕)
망아지
8[00:0.030]곡:망아지
편곡:Lupo Groinig
10[00:00.50]
11[00:12.65]가랑비 가 바람 을 타고 황혼의 거 리 를 적 셨 다.
12[00:18.61]빗물 을 지우 고 두 눈 을 고향 없 이 쳐다보다
13[00:24.04]외 로 운 저녁 등불 을 바라보다
14[00:26.91]
15[00:27.44]그 슬 픈 기억
16[00:30.52]
17[00:34.12]다시 마음속 에 무수 한 그리움 이 떠오르다
18[00:39.28]
19[00:40.10]잠시 동안 의 웃음 이 여전히 얼굴 에 걸 려 있다.
20[00:45.49]지금 알 수 있 기 를 바 랍 니 다.
21[00:48.23]
22[00:48.95]진심으로 말씀 드 리 겠 습 니 다.
23[00:53.06]
24[00:54.35]너의 그 두 눈 이 마음 에 들 어.
25[00:59.35]
26[01:0.10]웃음소리 가 더 매력적이다
27[01:02.37]
28[01:03.15]더 위로 해 드 리 겠 습 니 다.
29[01:08.56]
30[01:0935]그 귀여운 얼굴
31[01:12.40]손 잡 고 잠꼬대 하기
32[01:14.78]
33[01:15.48]어제 처럼 너 와 나
34[01:20.84]
35[01:26.32]이상 적 인 내 가 얼마나 충동 적 이 었 는 지
36[01:32.45]그녀 와 사랑 하 는 것 이 자 유 롭 지 못 하 다 고 여러 번 원망 한다.
37[01:37.82]지금 이라도 알 수 있 기 를 바 랍 니 다.
38[01:40.40]
39[01:41.25]진심으로 말씀 드 리 겠 습 니 다.
40[01:44.81]
41[01:46.39]너의 그 두 눈 이 마음 에 들 어.
42[01:51.72]
43[01:52.42]웃음소리 가 더 매력적이다
44[01:54.75]
45[01:55.48]조금 만 더 위로 해 주 셨 으 면 좋 겠 습 니 다.
46[02:00.93]
47[02:1.68]그 귀여운 얼굴
48[02:03.99]
49[02:04.73]손 잡 고 잠꼬대 하기
50[02:07.13]
51[02:07.82]어제 처럼 너 와 나
52[02:14.53]
53[02:25.54]밤마다 혼자 다 녀 요.
54[02:29.30]여기저기 서 얼마나 차 가운 지.
55[02:35.40]
56[02:37.83]예전 에는 자기 자신 을 위해 발 버 둥 쳤 다.
57[02:41.62]그녀의 고통 을 몰 랐 다.
58[02:52.02]
59[02:54.11]너의 그 두 눈 이 마음 에 들 어.
60[03:00.13]웃음소리 가 더 매력적이다
61[03:02.38]
62[03:03.14]조금 만 더 위로 해 주 셨 으 면 좋 겠 습 니 다.
63[03:08.77]
64[03:09.33]그 귀여운 얼굴
65[03:11.71]
66[03:12.41]손 잡 고 잠꼬대 하기
67[03:14.61]
68[03:15.45]어제 처럼 너 와 나
위 에서 보 듯 이 이 격식 은 앞 이 시작 시간 이 고 왼쪽 에서 오른쪽으로 일일이 대응 분,초,밀리초,뒤 가 가사 다.그래서 우 리 는 모든 문장의 가사 정 보 를 저장 하기 위해 실체 클래스 를 만들어 야 한다.
1.가사 실체 류 LrcBean
1public class LrcBean {
2 private String lrc;//
3 private long start;//
4 private long end;//
5
6 public String getLrc() {
7 return lrc;
8 }
9
10 public void setLrc(String lrc) {
11 this.lrc = lrc;
12 }
13
14 public long getStart() {
15 return start;
16 }
17
18 public void setStart(long start) {
19 this.start = start;
20 }
21
22 public long getEnd() {
23 return end;
24 }
25
26 public void setEnd(long end) {
27 this.end = end;
28 }
29}
모든 가사,우 리 는 시작 시간,끝 시간 과 가사 라 는 메 시 지 를 필요 로 한다.그러면 의문 이 생 길 까?위 에서 언급 한 가사 양식 은 가사 시작 시간 밖 에 없 는 것 같은 데 끝 날 시간 을 어떻게 알 아 요?사실 매우 간단 하 다.이 가사의 시작 시간 은 바로 이전 가사의 끝 시간 이다.가사 실체 류 가 있 으 면 우 리 는 가 사 를 해석 해 야 한다!2.가사 해석 도구 류 LrcUtil
1public class LrcUtil {
2
3 /**
4 * , LrcBean
5 * @param lrcStr , ,
6 * [ti: ]
7 * [ar:.]
8 * [al:]
9 * [by:]
10 * [offset:0]
11 * [00:00.10] - G.E.M. (Gem Tang)
12 * [00:00.20] :
13 * [00:00.30] :
14 * [00:00.40] :Lupo Groinig
15 * @return
16 */
17 public static List<LrcBean> parseStr2List(String lrcStr){
18 List<LrcBean> res = new ArrayList<>();
19 //
20 String[] subLrc = lrcStr.split("
");
21 // , ,
22 for (int i = 5; i < subLrc.length; i++) {
23 String lineLrc = subLrc[i];
24 //[00:00.10] - G.E.M. (Gem Tang)
25 String min = lineLrc.substring(lineLrc.indexOf("[")+1,lineLrc.indexOf("[")+3);
26 String sec = lineLrc.substring(lineLrc.indexOf(":")+1,lineLrc.indexOf(":")+3);
27 String mills = lineLrc.substring(lineLrc.indexOf(".")+1,lineLrc.indexOf(".")+3);
28 // ,
29 long startTime = getTime(min,sec,mills);
30 //
31 String lrcText = lineLrc.substring(lineLrc.indexOf("]")+1);
32 // ,
33 if(lrcText.equals("")) continue;
34 // , ,
35 // (《 (Passengers)》 ) - G.E.M. (Gem Tang)
36 if (i == 5) {
37 int lineIndex = lrcText.indexOf("-");
38 int first = lrcText.indexOf("(");
39 if(first<lineIndex&&first!=-1){
40 lrcText = lrcText.substring(0,first)+lrcText.substring(lineIndex);
41 }
42 LrcBean lrcBean = new LrcBean();
43 lrcBean.setStart(startTime);
44 lrcBean.setLrc(lrcText);
45 res.add(lrcBean);
46 continue;
47 }
48 //
49 LrcBean lrcBean = new LrcBean();
50 lrcBean.setStart(startTime);
51 lrcBean.setLrc(lrcText);
52 res.add(lrcBean);
53 // , , 100s
54 if(i == subLrc.length-1){
55 res.get(res.size()-1).setEnd(startTime+100000);
56 }else if(res.size()>1){
57 // 1 ,
58 res.get(res.size()-2).setEnd(startTime);
59 }
60
61 }
62 return res;
63 }
64
65 /**
66 *
67 * @param min
68 * @param sec
69 * @param mills
70 * @return
71 */
72 private static long getTime(String min,String sec,String mills){
73 return Long.valueOf(min)*60*1000+Long.valueOf(sec)*1000+Long.valueOf(mills);
74 }
75}
위의 코드 와 주석 이 이 가 사 를 잘 해석 했다 고 믿 습 니 다.주의해 야 할 것 은 위 에서 i=5,즉 가사 가 진정 으로 시 작 된 첫 번 째 문장 에 대해 특수 처 리 를 한 것 입 니 다.i=5 라 는 문장 은 매우 길 수 있 기 때 문 입 니 다.i=5 는'광년 밖'이 라 고 가정 합 니 다.(《우주 여행객(Passengers)》영화 중국 구 주제 곡)-G.E.M.덩 쯔 기(Gem)
탕)'이 가 사 는 우리 가 특별한 처 리 를 하지 않 고 뒤에서 그 릴 때 이 가사 가 화면 크기 를 초과 하여 미관 에 영향 을 미 치 는 것 을 발견 할 수 있 기 때문에 우 리 는 노래 제목 과 가수 만 캡 처 하고 어떤 설명 은 직접 생략 했다.가 사 를 해석 해 봤 습 니 다.다음은 앙코르 입 니 다.-가사 그리 기!
가사
가 사 를 그 리 는 것 은 사용자 정의 View 지식 과 관련 되 기 때문에 사용자 정의 View 를 접 하지 못 한 파트너 는 먼저 자체 보기 의 기초 지식 을 살 펴 봐 야 한다.가사 그리 기의 주요 작업 은 주로 아래 몇 부분 으로 구성 된다.
4.567917.가사 컨트롤 에 사용자 정의 속성 을 설정 하고 구조 방법 에서 사용자 정의 속성 을 가 져 오고 설정 하 는 기본 값4.567917.두 개의 화필 을 초기 화 합 니 다.가 사 는 보통 붓 이 고 가 사 는 하 이 라이트 붓 이다현재 재생 중인 가사의 위 치 를 가 져 옵 니 다4.567917.가 사 를 그리고 현재 가 사 를 재생 하 는 위치 에 따라 어떤 그림 으로 획 을 그 릴 지 결정 한다.
가사
다시 그립 니 다.
1.자체 보기 속성 을 설정 하고 코드 에 기본 값 을 설정 합 니 다.
res 파일 의 values 에 attrs.xml 파일 을 새로 만 든 다음 가사의 사용자 정의 View 속성 을 정의 합 니 다.
1<?xml version="1.0" encoding="utf-8"?>
2<resources>
3 <declare-styleable name="LrcView">
4 <attr name="highLineTextColor" format="color|reference|integer"/>
5 <attr name="lrcTextColor" format="color|reference|integer"/>
6 <attr name="lineSpacing" format="dimension"/>
7 <attr name="textSize" format="dimension"/>
8 </declare-styleable>
9</resources>
가사 색상,가사 하 이 라이트 색상,가사 크기,가사 줄 간격 속성 만 사용자 정의 하여 필요 에 따라 스스로 추가 할 수 있 습 니 다.그리고 자바 코드 에 기본 값 을 설정 합 니 다.
1 private int lrcTextColor;//
2 private int highLineTextColor;//
3 private int width, height;//
4 private int lineSpacing;//
5 private int textSize;//
6
7 public LrcView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
8 super(context, attrs, defStyleAttr);
9 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LrcView);
10 lrcTextColor = ta.getColor(R.styleable.LrcView_lrcTextColor, Color.GRAY);
11 highLineTextColor = ta.getColor(R.styleable.LrcView_highLineTextColor, Color.BLUE);
12 float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
13 float scale = context.getResources().getDisplayMetrics().density;
14 // 16sp
15 textSize = ta.getDimensionPixelSize(R.styleable.LrcView_textSize, (int) (16 * fontScale));
16 // 30dp
17 lineSpacing = ta.getDimensionPixelSize(R.styleable.LrcView_lineSpacing, (int) (30 * scale));
18 //
19 ta.recycle();
20 }
2.붓 두 자루 초기 화
1 private void init() {
2 //
3 dPaint = new Paint();
4 dPaint.setStyle(Paint.Style.FILL);//
5 dPaint.setAntiAlias(true);//
6 dPaint.setColor(lrcTextColor);//
7 dPaint.setTextSize(textSize);//
8 dPaint.setTextAlign(Paint.Align.CENTER);//
9
10 //
11 hPaint = new Paint();
12 hPaint.setStyle(Paint.Style.FILL);
13 hPaint.setAntiAlias(true);
14 hPaint.setColor(highLineTextColor);
15 hPaint.setTextSize(textSize);
16 hPaint.setTextAlign(Paint.Align.CENTER);
17 }
우 리 는 초기 화 하 는 방법 을 구조 방법 에 넣 었 다.그러면 다시 그 릴 때 다시 초기 화 하 는 것 을 피 할 수 있다.또한 우 리 는 init 방법 을 세 번 째 구조 방법 에 만 넣 었 기 때문에 위의 두 가지 구조 방법 은 슈퍼 를 this 로 바 꾸 어야 한다.그러면 어떤 구조 방법 이 든 init 방법 을 실행 할 수 있 도록 보장 할 수 있다.
1 public LrcView(Context context) {
2 this(context, null);
3 }
4
5 public LrcView(Context context, @Nullable AttributeSet attrs) {
6 this(context, attrs, 0);
7 }
8
9 public LrcView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
10 super(context, attrs, defStyleAttr);
11 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.LrcView);
12 ......
13 //
14 ta.recycle();
15 init();
16 }
3.onDraw 방법 반복뒤의 절 차 는 모두 onDraw 방법 에서 실행 되 기 때문에 우 리 는 먼저 onDraw 방법 중의 코드 를 붙 입 니 다.
1 @Override
2 protected void onDraw(Canvas canvas) {
3 super.onDraw(canvas);
4
5 getMeasuredWidthAndHeight();//
6 getCurrentPosition();//
7 drawLrc(canvas);//
8 scrollLrc();//
9 postInvalidateDelayed(100);// 0.1s
10 }
1.컨트롤의 측정 너비 획득
1 private int width, height;//
2 private void getMeasuredWidthAndHeight(){
3 if (width == 0 || height == 0) {
4 width = getMeasuredWidth();
5 height = getMeasuredHeight();
6 }
7 }
왜 컨트롤 의 너비 와 높이 를 얻 으 려 고 합 니까?아래 에서 우 리 는 가 사 를 그 려 야 하기 때문에 가 사 를 그 릴 때 그 려 야 할 위 치 는 컨트롤 의 너비 와 높이 를 사용 해 야 한다.2.현재 가사의 위 치 를 얻는다
1 private List<LrcBean> lrcBeanList;//
2 private int currentPosition;//
3 private MediaPlayer player;//
4
5
6 private void getCurrentPosition() {
7 int curTime = player.getCurrentPosition();
8 // 10 , , 0
9 if (curTime < lrcBeanList.get(0).getStart()||curTime>10*60*1000) {
10 currentPosition = 0;
11 return;
12 } else if (curTime > lrcBeanList.get(lrcBeanList.size() - 1).getStart()) {
13 currentPosition = lrcBeanList.size() - 1;
14 return;
15 }
16 for (int i = 0; i < lrcBeanList.size(); i++) {
17 if (curTime >= lrcBeanList.get(i).getStart() && curTime <= lrcBeanList.get(i).getEnd()) {
18 currentPosition = i;
19 }
20 }
21 }
우 리 는 현재 재생 되 고 있 는 노래 시간 에 따라 가 사 를 옮 겨 다 니 며 집합 하여 현재 재생 되 고 있 는 가사의 위 치 를 판단 한다.세심 한 당신 은 current Position=0 에 curtime>10601000 의 판단 이 있 는 것 을 발견 할 수 있 습 니 다.이 는 실제 사용 에서 플레이어 가 아직 재생 되 지 않 았 을 때 얻 는 curTime 이 매우 크기 때문에 이 판단 이 있 습 니 다(정상 적 인 노래 는 10 분 을 넘 지 않 기 때 문 입 니 다).이 방법 에서 우 리 는 가사 집합 과 재생 기 를 발견 할 수 있 습 니 다.당신 은 곤 혹 스 러 울 수 있 습 니 다.이것 은 아직 값 을 부여 하지 않 았 지 않 습 니까?곤 혹 스 러 운 것 이 옳 기 때문에 우 리 는 외부 에 가사 컨트롤 가사 집합 과 재생 기 를 전달 하 는 외부 방법 을 제공 해 야 한다.
1 // View
2 public LrcView setLrc(String lrc) {
3 lrcBeanList = LrcUtil.parseStr2List(lrc);
4 return this;
5 }
6
7 // mediaPlayer View
8 public LrcView setPlayer(MediaPlayer player) {
9 this.player = player;
10 return this;
11 }
외부 방법 에서 setLrc 의 인 자 는 앞에서 언급 한 표준 가사 형식의 문자열 형식 이 어야 합 니 다.그러면 우 리 는 위의 해석 도구 류 인 LrcUtil 의 해석 방법 을 이용 하여 문자열 을 가사 집합 으로 해석 할 수 있 습 니 다.3.가 사 를 그린다
1 private void drawLrc(Canvas canvas) {
2 for (int i = 0; i < lrcBeanList.size(); i++) {
3 if (currentPosition == i) {//
4 canvas.drawText(lrcBeanList.get(i).getLrc(), width / 2, height / 2 + i * lineSpacing, hPaint);
5 } else {
6 canvas.drawText(lrcBeanList.get(i).getLrc(), width / 2, height / 2 + i * lineSpacing, dPaint);
7 }
8 }
9 }
현재 가사의 위 치 를 알 게 되면 가 사 를 그리 기 쉽다.가 사 를 옮 겨 다 니 며 집합 하고 현재 가사 라면 하 이 라이트 펜 으로 그리고 다른 가 사 는 보통 펜 으로 그린다.여기 서 주의해 야 할 것 은 두 획 의 위치 공식 이 모두 같 고 좌표 위 치 는 x=너비 의 절반,y=높이 의 절반+현재 위치*줄 간격 이다.현재 위치 에 따라 상하 문 가 사 를 그 릴 수 있다.그래서 사실 그 려 진 후에 가 사 는 컨트롤 의 정 중앙 에서 그 려 진 것 을 발견 할 수 있 습 니 다.이것 은 아래 가사 와 동기 화 된 미끄럼 기능 의 조 화 를 편리 하 게 하기 위해 서 입 니 다.4.가사 동시 슬라이딩
1 //
2 private void scrollLrc() {
3 //
4 long startTime = lrcBeanList.get(currentPosition).getStart();
5 long currentTime = player.getCurrentPosition();
6
7 // , 0.5 ,
8 float y = (currentTime - startTime) > 500 ? currentPosition * lineSpacing : lastPosition * lineSpacing + (currentPosition - lastPosition) * lineSpacing * ((currentTime - startTime) / 500f);
9 scrollTo(0,(int)y);
10 if (getScrollY() == currentPosition * lineSpacing) {
11 lastPosition = currentPosition;
12 }
13 }
신축성 슬라이딩 이 이 루어 지지 않 는 다 면 현재 재생 곡 의 시간 이 현재 위치 가사의 종료 시간 보다 큰 지 판단 한 다음 scrollTo(0,(int)current Position*lineSpacing)슬라이딩 을 하면 됩 니 다.그러나 탄력 적 인 미끄럼 을 실현 하기 위해 우 리 는 한 번 의 미끄럼 을 몇 번 의 작은 미끄럼 으로 나 누 어 한 시간 안에 완성 해 야 한다.그래서 우 리 는 Y 의 값 을 동적 으로 설정 하고 계속 다시 그리 기 때문에 0.5 초 안에 View 의 미끄럼 을 완성 할 수 있다.그러면 가사 가 동시에 탄력 적 으로 미 끄 러 질 수 있다.500 은 사실 0.5s 입 니 다.여기 서 currentTime 과 startTime 의 단 위 는 모두 ms 이기 때 문 입 니 다.
1 float y = (currentTime - startTime) > 500 ? currentPosition * lineSpacing : lastPosition * lineSpacing + (currentPosition - lastPosition) * lineSpacing * ((currentTime - startTime) / 500f);
5.끊임없이 다시 그린다끊임없이 다시 그 려 야만 가사 가 동시에 미 끄 러 지 는 것 을 실현 할 수 있 습 니 다.여 기 는 0.1s 간격 으로 다시 그 릴 수 있 습 니 다.
1postInvalidateDelayed(100);// 0.1s
이게 끝 인 줄 알 아?사실은 아직 없습니다.답 은 다음 에 발표 하 겠 습 니 다!사용
그리고 xml 에서 이 사용자 정의 View 를 인용 합 니 다.
LrcView 앞의 이름 은 이러한 종류의 전체 패키지 이름 을 만 들 수 있 습 니 다.
1 <com.example.library.view.LrcView
2 android:id="@+id/lrcView"
3 android:layout_width="match_parent"
4 android:layout_height="match_parent"
5 app:lineSpacing="40dp"
6 app:textSize="18sp"
7 app:lrcTextColor="@color/colorPrimary"
8 app:highLineTextColor="@color/highTextColor"
9 />
자바 코드 에서 이 사용자 정의 View 에 표준 가사 문자열 과 재생 기 를 입력 합 니 다.
1lrcView.setLrc(lrc).setPlayer(player);
클릭 하여 실행 하고 자신의 성 과 를 기대 합 니 다.그 다음 에 당신 은 멍 한 얼굴 을 할 것 입 니 다.what?왜 공백 이 야,아무것도 없어!사실 이때 위 가사 가 그 려 진 절 차 를 다시 정리 하면 문제점 을 발견 할 수 있다.우선 사용자 정의 View 컨트롤 이 레이아웃 에 인 용 될 때 onDraw 방법 을 먼저 실행 합 니 다.따라서 setLrc 와 setPlayer 방법 을 호출 하면 onDraw 방법 을 다시 호출 하지 않 습 니 다.가사 문자열 과 재생 기 를 입력 하지 않 은 것 과 같 기 때문에 당연히 공백 이 표 시 됩 니 다.해결 방법:방금 사용자 정의 View 가사 컨트롤 에 onDraw 를 호출 하 는 외부 방법 을 추가 하 였 습 니 다.마침 이 invalidate()는 onDraw 방법 을 다시 호출 할 수 있 습 니 다.
1 public LrcView draw() {
2 currentPosition = 0;
3 lastPosition = 0;
4 invalidate();
5 return this;
6 }
그리고 우 리 는 메 인 코드 에서 setLrc 와 setPlayer 를 호출 한 후에 draw 방법 을 호출 해 야 합 니 다.
1lrcView.setLrc(lrc).setPlayer(player).draw();
이렇게 해서 우리 의 절약 풍 가사 컨트롤 이 큰 성 과 를 거 두 었 다.총결산
안 드 로 이 드 사용자 정의 View 의 심 플 한 가사 컨트롤 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 안 드 로 이 드 심 플 한 가사 컨트롤 내용 은 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 찾 아 보 세 요.앞으로 많은 응원 부탁드립니다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.