Android 에 서 는 TextView 를 사용 하여 경 동 타 오 바 오의 각종 카운트다운 효 과 를 높 게 모방 합 니 다.

오늘 여러분 께 가 져 온 것 은 TextView 하나만 사용 하여 고 모조 경 동,타 오 바 오,유품 회 등 각종 전자상거래 앱 의 활동 카운트다운 을 실현 하 는 것 입 니 다.최근 에 회사 에서 야근 을 하 느 라 정리 할 시간 이 없어 서 오늘 모처럼 쉬 었 습 니 다.이 걸 여러분 께 공유 하고 싶 습 니 다.같이 공부 하고 후속 복습 만 하고 싶 습 니 다.왜 TextView 하나 로 이 루어 질 생각 을 했 을까요?최근 에 회사 에서 최 적 화 된 작업 을 하고 있 기 때문에 그 중에서 카운트다운 스타일 이 있 습 니 다.원래 개 발 된 이 컨트롤 의 동료 들 은 여러 개의 TextView 를 사용 하여 연결 되 었 고 실현 하 는 코드 가 너무 많 습 니 다.그래서 이 프로젝트 매니저 는 소 홍 이 는 당신 에 게 우수 화 를 맡 기 고 일정한 확장 성 을 확보 해 야 하기 때문에 그 때 는 어 리 석 었 습 니 다.어디서부터 최적화 해 야 할 지 모르겠다.그 다음 에 저 는 경 동 을 살 펴 보 았 습 니 다.배 고 프 세 요?유 품 회 는 각 앱 의 카운트다운 을 기다 리 고 개발 자 들 사이 에서 등급 별 화면 을 열 어 보 니 그들 은 모두 하나의 View 를 가지 고 여러 개의 TextView 를 사용 하지 않 았 다 는 공통점 이 있 습 니 다.하나의 TextView 만 사용 하 는 것 이 여러 개의 TextView 를 사용 하 는 것 보다 실현 하 는 장점 을 모두 가 알 고 있 을 것 이 라 고 믿 습 니 다.다음은 몇 개의 화면 을 보면 알 수 있 습 니 다.


이 를 보고 자 연 스 럽 게 사용자 정의 뷰 가 떠 올 랐 다.네,사용자 정의 View 는 이러한 효 과 를 실현 할 수 있 습 니 다.하지만 오늘 은 사용자 정의 뷰 로 하지 않 습 니 다.하나의 TextView 로 이 루어 집 니 다.
프로젝트 매니저 가 이번 최적화 코드 에 확장 성 을 요구 하기 때문이다.그래서 이번 코드 의 디자인 은 대상 을 대상 으로 하 는 지식 을 더 했다.자신의 디자인 과 구조 에 대한 사고 가 있다.
이번 demo 의 디자인 방향:
1.카운트다운 의 기본 클래스 를 작성 하여 가장 일반적 이 고 기본 적 인 카운트다운 을 실현 하 는 기능 으로 스타일 이 없습니다.이 기본 클래스 가 Countdown Timer 클래스 를 계승 하고 이 기본 클래스 에서
TextView 의 대상 을 저장 하고 카운트다운 할 때마다 데 이 터 를 TextView 에 표시 한 다음 getmDateTv()방법 을 발표 하여 TextView 대상 을 되 돌려 주면 됩 니 다.그리고 이 TextView 대상 을 가 져 와 인터페이스의 레이아웃 을 표시 하면 됩 니 다.매우 편리 하 다.
2.그리고 서로 다른 스타일 의 카운트다운 은 서로 다른 하위 클래스 를 만들어 서 가장 일반적인 카운트다운 기 류 를 계승 하면 됩 니 다.그리고 그 중의 설정 데이터 와 스타일 을 설정 하 는 두 가지 방법 을 다시 쓰 면 됩 니 다.그리고 가장 일반적인 카운트다운 에 서로 다른 스타일 을 추가 할 수 있 습 니 다.다음 에 새로운 카운트다운 스타일 을 확장 하려 면 다른 종류의 코드 를 바 꿀 필요 가 없습니다.일반적인 카운트다운 파생 클래스 를 만들어 서 두 가지 방법 을 다시 쓰 면 확장 성 이 더욱 유연 해 집 니 다.
3.그 다음 에 하나의 TimerUtils 관리 류 를 통 해 부담 류 와 아버지 류 의 압력 을 집중 적 으로 받 고 서브 류 와 아버지 류 가 필요 로 하 는 기능 을 TimerUtils 류 에 분담 하도록 한다.또한 이 TimerUtils 관리 류 는 클 라 이언 트 와 유일 하 게 접촉 하 는 유형 이다.예 를 들 어 카운트다운 대상 을 얻 고 카운트다운 을 받 는 TextView 대상 은 모두 이런 관리 류 를 통 해 분배 된다.클 라 이언 트 가 카운트다운 의 기본 클래스 와 하위 클래스 와 직접 접촉 하 는 것 을 피한다.그래서 류 의 포장 성과 숨겨 진 성 을 나타 낸다.
다음은 이 데모 가 디자인 한 간단 한 UML 클래스 를 볼 수 있 습 니 다.

이상 의 사고방식 분석 을 통 해 이번 데모 의 실현 에 어떤 지식 이 필요 한 지 살 펴 보 겠 습 니 다.
1.Countdown Timer 류 의 용법.
2.SpannableString 의 용법.
3.MikyuCountdown Timer 의 패키지.
4.사용자 정의 MikyuBackgroundSpan 의 실현.
1.상기 분석 을 통 해 우 리 는 먼저 Countdown Timer 에 관 한 지식 을 복습 해 야 한다.Countdown Timer 는 우리 가 볼 수 있 는 간단 한 유형 으로 그 소스 코드 의 용법 을 자 연 스 럽 게 알 수 있다.
Countdown Timer 는 추상 적 인 유형 이다.

// 
// Source code recreated from a .class file by IntelliJ IDEA 
// (powered by Fernflower decompiler) 
// 
package android.os; 
public abstract class CountDownTimer { 
public CountDownTimer(long millisInFuture, long countDownInterval) { 
throw new RuntimeException("Stub!"); 
} 
public final synchronized void cancel() { 
throw new RuntimeException("Stub!"); 
} 
public final synchronized CountDownTimer start() { 
throw new RuntimeException("Stub!"); 
} 
public abstract void onTick(long var1); 
public abstract void onFinish(); 
}
카운트다운 의 총 시간 이 millisFuture 인 것 을 볼 수 있 습 니 다.countDownInterVal 과 의 간격 은 기본적으로 1000 ms 이기 때문에 데 이 터 는 구조 기 를 통 해 초기 화 된 다음 에 리 셋 방법 인 onTick 을 다시 써 야 합 니 다.그 중의 한 매개 변 수 는 해당 하 는 걸음 마다 남 은 시간 밀리초 입 니 다.그리고 우 리 는 onTick 방법 에서 1000 ms 시간 밀리초 간격 으로 시간 을 포맷 하면 해당 시간 형식의 카운트다운 을 얻 을 수 있 습 니 다.이것 이 바로 가장 기본 적 인 카운트다운 스타일 입 니 다.포맷 초읽기 형식 은 apache 의 common lang 패키지 의 Duration Format Utils 클래스 의 format Duration 을 사용 합 니 다.시간 형식 을 입력 하면 자동 으로 초읽기 를 해당 하 는 mTimePattern 스타일 로 변환 합 니 다(HH:mm:ss 또는 dd 일 HH 시 mm 분 ss 초).
2.SpannableString 에 관 한 용법 을 복습 합 니 다.
Android 에서 EditText 는 텍스트 를 편집 하 는 데 사 용 됩 니 다.TextView 는 텍스트 를 표시 하 는 데 사 용 됩 니 다.그러나 가끔 은 텍스트 에 대한 스타일 설정 이 필요 합 니 다.Android 는 지정 한 텍스트 를 처리 하기 위해 SpannableString 클래스 를 제공 합 니 다.
1)ForegroundColorSpan 텍스트 색상
private void setForegroundColorSpan() {
SpannableString spanString=new SpannableString("전경 색");
ForegroundColorSpan span = new ForegroundColorSpan(Color.BLUE);
spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.append(spanString);
}
2)배경 ColorSpan 텍스트 배경 색
private void setBackgroundColorSpan() {
SpannableString spanString=new SpannableString("배경 색");
BackgroundColorSpan span = new BackgroundColorSpan(Color.YELLOW);
spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
tv.append(spanString);
}
3)스타일 스 판 글꼴 스타일:굵 은 몸,기울 임 꼴 등

private void setStyleSpan() { 
SpannableString spanString = new SpannableString("    "); 
StyleSpan span = new StyleSpan(Typeface.BOLD_ITALIC); 
spanString.setSpan(span, 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
tv.append(spanString); 
}
4)상대 크기

private void setRelativeFontSpan() { 
SpannableString spanString = new SpannableString("      "); 
spanString.setSpan(new RelativeSizeSpan(2.5f), 0, 6,Spannable.SPAN_INCLUSIVE_EXCLUSIVE); 
tv.append(spanString); 
}
5)TypefaceSpan 텍스트 글꼴

private void setTypefaceSpan() { 
SpannableString spanString = new SpannableString("    "); 
spanString.setSpan(new TypefaceSpan("monospace"), 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
tv.append(spanText); 
}
6)URLSpan 텍스트 하이퍼링크

private void addUrlSpan() { 
SpannableString spanString = new SpannableString("   "); 
URLSpan span = new URLSpan("http://www.baidu.com"); 
spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
tv.append(spanString); 
}
7)ImageSpan 이미지

private void addImageSpan() { 
SpannableString spanString = new SpannableString(" "); 
Drawable d = getResources().getDrawable(R.drawable.ic_launcher); 
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight()); 
ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BASELINE); 
spanString.setSpan(span, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
tv.append(spanString); 
}
8)Clickable Span 텍스트 에 클릭 이벤트 가 있 음

private TextView textView; 
textView = (TextView)this.findViewById(R.id.textView); 
String text = "  Activity"; 
SpannableString spannableString = new SpannableString(text); 
spannableString.setSpan(new ClickableSpan() { 
@Override 
public void onClick(View widget) { 
Intent intent = new Intent(Main.this,OtherActivity.class); 
startActivity(intent); 
} 
//       text             
}, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 
textView.setText(spannableString); 
textView.setMovementMethod(LinkMovementMethod.getInstance());
9)언 더 라인 스 판 밑줄

private void addUnderLineSpan() { 
SpannableString spanString = new SpannableString("   "); 
UnderlineSpan span = new UnderlineSpan(); 
spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
tv.append(spanString); 
}
10) StrikethroughSpan
삭제 선

private void addStrikeSpan() { 
SpannableString spanString = new SpannableString("   "); 
StrikethroughSpan span = new StrikethroughSpan(); 
spanString.setSpan(span, 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
tv.append(spanString); 
}
11) SuggestionSpan
자리 차지 문자 에 해당 하 다
12) MaskFilterSpan
퍼 지(BlurMaskFilter),부조(EmbossMaskFilter)와 같은 수식 효과
13) RasterizerSpan
회절 격자 효과
14) AbsoluteSizeSpan
절대 크기(텍스트 글꼴)

private void setAbsoluteFontSpan() { 
SpannableString spannableString = new SpannableString("40   "); 
AbsoluteSizeSpan absoluteSizeSpan = new AbsoluteSizeSpan(40); 
spannableString.setSpan(absoluteSizeSpan, 0, 5, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 
editText.append(spannableString); 
}
15)DynamicDrawableSpan 은 텍스트 기선 이나 아래쪽 을 기반 으로 그림 을 설정 합 니 다.
16) TextAppearanceSpan
텍스트 외모(글꼴,크기,스타일,색상 포함)

private void setTextAppearanceSpan() { 
SpannableString spanString = new SpannableString("    "); 
TextAppearanceSpan textAppearanceSpan = new TextAppearanceSpan(this, android.R.style.TextAppearance_Medium); 
spanString.setSpan(textAppearanceSpan, 0, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); 
tv.append(spanString); 
}
자,이상 의 복습 지식 포 인 트 를 통 해 이제 우 리 는 데모 의 실현 을 진정 으로 시작 할 수 있 습 니 다.그리고 우 리 는 한 걸음 한 걸음 우리 의 카운트다운 을 포장 할 수 있 습 니 다.
1.MikyuCountdown Timer 기본 클래스 를 작성 하여 Countdown Timer 클래스 를 계승 하고 initSpanData 와 setBackgroundSpan 방법 을 발표 하여 다른 스타일 의 카운트다운 하위 클래스 에 사용 하면 가장 기본 적 인 카운트다운 기능 을 실현 할 수 있 습 니 다.

package com.mikyou.countdowntimer.bean; 
import android.content.Context; 
import android.os.CountDownTimer; 
import android.text.style.ForegroundColorSpan; 
import android.widget.TextView; 
import com.mikyou.countdowntimer.myview.MikyouBackgroundSpan; 
import com.mikyou.countdowntimer.utils.TimerUtils; 
import org.apache.commons.lang.time.DurationFormatUtils; 
import java.util.ArrayList; 
import java.util.List; 
/** 
* Created by mikyou on 16-10-22. 
*/ 
public class MikyouCountDownTimer extends CountDownTimer{ 
private Context mContext;//         
protected TextView mDateTv;//  TextView      
private long mGapTime;//                  
private long mCount = 1000;//          1000    1s    
private String mTimePattern = "HH:mm:ss";//timePattern           : HH:mm:ss HH mm ss  dd HH mm ss  
private String mTimeStr; 
protected List<MikyouBackgroundSpan> mBackSpanList; 
protected List<ForegroundColorSpan> mTextColorSpanList; 
private int mDrawableId; 
private boolean flag = false;//    flag,         Span      
protected String[] numbers;//                   , , ,     
protected char[] nonNumbers;//    , , ,      (" "," "," "," "  ":") 
//           ,    ,    ,         
private int mSpanPaddingLeft,mSpanPaddingRight,mSpanPaddingTop,mSpanPaddingBottom; 
private int mSpanTextSize; 
private int mSpanTextColor; 
protected int mGapSpanColor; 
public MikyouCountDownTimer(Context mContext, long mGapTime, String mTimePattern,int mDrawableId) { 
this(mContext,mGapTime,1000,mTimePattern,mDrawableId); 
} 
public MikyouCountDownTimer(Context mContext, long mGapTime, int mCount, String mTimePattern,int mDrawableId) { 
super(mGapTime,mCount); 
this.mContext = mContext; 
this.mGapTime = mGapTime;//       
this.mCount = mCount;//        ,   1000 
this.mDrawableId= mDrawableId;//       drawable id 
this.mTimePattern = mTimePattern;//     : HH:mm:ss  dd HH mm ss   
mBackSpanList = new ArrayList<>(); 
mTextColorSpanList = new ArrayList<>(); 
mDateTv = new TextView(mContext,null); 
} 
//              ,     ,             
public MikyouCountDownTimer setTimerTextSize(int textSize){ 
this.mSpanTextSize = textSize; 
return this; 
} 
public MikyouCountDownTimer setTimerPadding(int left,int top,int right,int bottom){ 
this.mSpanPaddingLeft = left; 
this.mSpanPaddingBottom = bottom; 
this.mSpanPaddingRight = right; 
this.mSpanPaddingTop = top; 
return this; 
} 
public MikyouCountDownTimer setTimerTextColor(int color){ 
this.mSpanTextColor = color; 
return this; 
} 
public MikyouCountDownTimer setTimerGapColor(int color){ 
this.mGapSpanColor = color; 
return this; 
} 
//      Span   ,           
public void setBackgroundSpan(String timeStr) { 
if (!flag){ 
initSpanData(timeStr); 
flag = true; 
} 
mDateTv.setText(timeStr); 
} 
//      Span   ,           
public void initSpanData(String timeStr) { 
numbers = TimerUtils.getNumInTimerStr(timeStr); 
nonNumbers = TimerUtils.getNonNumInTimerStr(timeStr); 
} 
protected void initBackSpanStyle(MikyouBackgroundSpan mBackSpan) { 
mBackSpan.setTimerPadding(mSpanPaddingLeft,mSpanPaddingTop,mSpanPaddingRight,mSpanPaddingBottom); 
mBackSpan.setTimerTextColor(mSpanTextColor); 
mBackSpan.setTimerTextSize(mSpanTextSize); 
} 
@Override 
public void onTick(long l) { 
if (l > 0) { 
mTimeStr = DurationFormatUtils.formatDuration(l, mTimePattern); 
//  apache  common lang  DurationFormatUtils   formatDuration,     
//                    mTimePattern   (HH:mm:ss dd HH mm ss ) 
setBackgroundSpan(mTimeStr); 
} 
} 
@Override 
public void onFinish() { 
mDateTv.setText("     "); 
} 
//          TextView    
public TextView getmDateTv() { 
startTimer(); 
return mDateTv; 
} 
public void cancelTimer(){ 
this.cancel(); 
} 
public void startTimer(){ 
this.start(); 
} 
public String getmTimeStr() { 
return mTimeStr; 
} 
}
TimerUtils 류 는 서로 다른 카운트다운 형식 을 저장 하 는 데 사 용 됩 니 다.예 를 들 어 HH:mm:ss,HH 시 mm 분 ss 초,dd 천 HH 시 mm 분 ss 초 등 입 니 다.이제 간단 한 기본 스타일 을 살 펴 볼 수 있 습 니 다.

2.MikyuBackgroundSpan 을 사용자 정의 하여 ImageSpan 을 계승 합 니 다.이 종 류 는 카운트다운 하 는 TextView 에 스타일 을 추가 하 는 것 이 매우 중요 합 니 다.왜 TextView 를 사용 하여 이 루어 질 수 있 습 니까?
또 하나의 강력 한 종 류 는 바로 SpannableString 류 라 는 것 을 잊 지 마 세 요.이 종 류 는 문자열 의 모든 문 자 를 설정 할 수 있 는 스타일 이 고 여러 가지 스타일 입 니 다.마지막 으로 TextView 에 setSpan 방법 이 있 으 면 들 어 갈 수 있 습 니 다.
SpannableString 대상 이 설정 을 마 쳤 습 니 다.그런데 왜 스 판 을 사용자 정의 해 야 합 니까?이것 은 왜 안 드 로 이 드 의 그렇게 많은 Span 스타일 중 drawable 대상 파일 을 직접 설정 할 수 있 는 것 이 하나 도 없 는 지 이상 하기 때문에 인터넷 에서 많은 것 을 찾 았 지만 찾 지 못 했 습 니 다.마지막 으로 stackOverFlow 에서 한 외국인 을 찾 아 해결 방법 을 주 었 습 니 다.바로 ImageSpan 을 다시 쓰 면 drawable 파일 을 설정 하면 됩 니 다.

package com.mikyou.countdowntimer.myview; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.Rect; 
import android.graphics.drawable.Drawable; 
import android.text.style.ImageSpan; 
/** 
* Created by mikyou on 16-10-22. 
*/ 
public class MikyouBackgroundSpan extends ImageSpan { 
private Rect mTextBound; 
private int maxHeight = 0; 
private int maxWidth = 0; 
private int mPaddingLeft = 20; 
private int mPaddingRight = 20; 
private int mPaddingTop = 20; 
private int mPaddingBottom = 20; 
private int mTextColor = Color.GREEN; 
private int mTextSize = 50; 
public MikyouBackgroundSpan(Drawable d, int verticalAlignment) { 
super(d, verticalAlignment); 
mTextBound = new Rect(); 
} 
public MikyouBackgroundSpan setTimerTextColor(int mTextColor) { 
this.mTextColor = mTextColor; 
return this; 
} 
public MikyouBackgroundSpan setTimerTextSize(int textSize){ 
this.mTextSize = textSize; 
return this; 
} 
public MikyouBackgroundSpan setTimerPadding(int left,int top,int right,int bottom){ 
this.mPaddingLeft = left; 
this.mPaddingRight = right; 
this.mPaddingBottom = bottom; 
this.mPaddingTop = top; 
return this; 
} 
@Override 
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { 
//           
paint.setTextSize(mTextSize); 
//          ,  mTextBound   
paint.getTextBounds(text.toString(), start, end, mTextBound); 
//            ,    left,top,right,bottom     
maxWidth = maxWidth < mTextBound.width() ? mTextBound.width() : maxWidth; 
maxHeight = maxHeight < mTextBound.height() ? mTextBound.height() : maxHeight; 
//                                ,                 , 
//                                
getDrawable().setBounds(0,0, maxWidth+mPaddingLeft+mPaddingRight,mPaddingTop+mPaddingBottom+maxHeight); 
//       
super.draw(canvas, text, start, end, x, top, y, bottom, paint); 
//        
paint.setColor(mTextColor); 
//        
paint.setTextSize(mTextSize); 
int mGapX = (getDrawable().getBounds().width() - maxWidth)/2; 
int mGapY= (getDrawable().getBounds().height() - maxHeight)/2; 
//       
canvas.drawText(text.subSequence(start, end).toString(), x + mGapX , y - mGapY + maxHeight/3, paint); } 
}
3.스타일 1 의 카운트다운 이 이 루어 집 니 다.스타일 은 예 를 들 어 12 시 36 분 27 초 또는 12 시 36 분 27 초 또는 12 시 36 분 27 초 는 수치 와 시,분,초 또는':'를 분리 한 다음 에 각 수치(12 36 27)와 간격(시 분 초 또는:)을 사용자 정의 하 는 스타일 입 니 다.이 는 수치 블록 에 배경 과 테 두 리 를 추가 하 는 것 을 포함 합 니 다.MikyuCountdown Timer 의 number 배열 에는[12 36 27]이 저장 되 어 있 고 nonumer 배열 에는[시 분 초]또는[:]d 의 간격 문자 가 저장 되 어 있 습 니 다.

package com.mikyou.countdowntimer.bean; 
import android.content.Context; 
import android.text.SpannableString; 
import android.text.method.LinkMovementMethod; 
import android.text.style.ForegroundColorSpan; 
import android.text.style.ImageSpan; 
import com.mikyou.countdowntimer.myview.MikyouBackgroundSpan; 
import com.mikyou.countdowntimer.utils.TimerUtils; 
/** 
* Created by mikyou on 16-10-22. 
*/ 
public class JDCountDownTimer extends MikyouCountDownTimer { 
private SpannableString mSpan; 
private Context mContext; 
private int mDrawableId; 
public JDCountDownTimer(Context mContext, long mGapTime, String mTimePattern,int mDrawableId) { 
super(mContext, mGapTime, mTimePattern,mDrawableId); 
this.mContext = mContext; 
this.mDrawableId = mDrawableId; 
} 
/** 
*      initSpanData   
*   number              MikyouBackgroundSpan   
*     MikyouBackgroundSpan               ,  ,      ,               
*   nonNumber         ForegroundColorSpan   
*                      ,      ForegroundColorSpan       
*           ,setmGapSpanColor                   
*            Span,          。 
* */ 
@Override 
public void initSpanData(String timeStr) { 
super.initSpanData(timeStr); 
for (int i = 0; i<numbers.length;i++){ 
MikyouBackgroundSpan mBackSpan = new MikyouBackgroundSpan(mContext.getDrawable(mDrawableId), ImageSpan.ALIGN_BOTTOM); 
initBackSpanStyle(mBackSpan); 
mBackSpanList.add(mBackSpan); 
} 
for (int i= 0; i<nonNumbers.length;i++){ 
ForegroundColorSpan mGapSpan = new ForegroundColorSpan(mGapSpanColor); 
mTextColorSpanList.add(mGapSpan); 
} 
} 
/**      setBackgroundSpan   
*       Span            start,end   
*      start end             
* mGapLen = 1,          , 
*   :12 36 27  " "," "," "      
*       Span  ,      Span, 
*               Span start  :start = i*numbers[i].length() + i*mGapLen; 
* end = start + numbers[i].length(); 
* */ 
@Override 
public void setBackgroundSpan(String timeStr) { 
super.setBackgroundSpan(timeStr); 
int mGapLen = 1; 
mSpan = new SpannableString(timeStr); 
for (int i = 0;i<mBackSpanList.size();i++){ 
int start = i*numbers[i].length() + i*mGapLen; 
int end = start + numbers[i].length(); 
TimerUtils.setContentSpan(mSpan,mBackSpanList.get(i),start,end); 
if (i < mTextColorSpanList.size()){//        12:36:27    ,        2        ,       
TimerUtils.setContentSpan(mSpan,mTextColorSpanList.get(i),end,end + mGapLen); 
} 
} 
mDateTv.setMovementMethod(LinkMovementMethod.getInstance());//          ,                  
mDateTv.setText(mSpan); 
} 
}
4.스타일 2 의 카운트다운 이 이 루어 집 니 다.스타일 2 는 스타일 1 과 다 릅 니 다.예 를 들 어 12 시 36 분 27 초 또는 12:36:27 은 모든 수치 와 시,분,초 또는":"분리 한 다음 에 각 수치(1,2,3,6,27)와 간격(시 분 초 또는:)을 사용자 정의 하 는 스타일 입 니 다.이 는 수치 블록 에 배경 과 테 두 리 를 추가 하 는 것 을 포함 합 니 다.MikyuCountdown Timer 의 vipNumber 배열 에는[1,2,3,6,27]이 저장 되 어 있 고,vipnonNumer 배열 에는[시 분 초]또는[:]d 의 간격 문자 가 저장 되 어 있 습 니 다.

package com.mikyou.countdowntimer.bean; 
import android.content.Context; 
import android.text.SpannableString; 
import android.text.method.LinkMovementMethod; 
import android.text.style.ForegroundColorSpan; 
import android.text.style.ImageSpan; 
import com.mikyou.countdowntimer.myview.MikyouBackgroundSpan; 
import com.mikyou.countdowntimer.utils.TimerUtils; 
import java.util.ArrayList; 
import java.util.List; 
/** 
* Created by mikyou on 16-10-22. 
*/ 
public class VIPCountDownTimer extends MikyouCountDownTimer { 
private SpannableString mSpan; 
private Context mContext; 
private int mDrawableId; 
private List<MikyouBackgroundSpan> mSpanList; 
private String[] vipNumbers; 
private char[] vipNonNumbers; 
public VIPCountDownTimer(Context mContext, long mGapTime, String mTimePattern,int mDrawableId) { 
super(mContext, mGapTime, mTimePattern,mDrawableId); 
this.mContext = mContext; 
this.mDrawableId = mDrawableId; 
mSpanList = new ArrayList<>(); 
} 
/**      setBackgroundSpan   
*       Span            start,end   
*      start end            ,                     
* mGapLen = 1,          , 
*   :12 36 27  " "," "," "      
*       Span  ,      Span, 
*               Span start  :start = i*numbers[i].length() + i*mGapLen; 
* end = start + numbers[i].length(); 
* */ 
@Override 
public void setBackgroundSpan(String timeStr) { 
int mGapLen = 1; 
mSpan = new SpannableString(timeStr); 
initSpanData(timeStr); 
int start = 0 ; 
int count =0; 
for (int i=0;i<vipNumbers.length;i++){ 
for (int j=start;j<start + vipNumbers[i].toCharArray().length;j++,count++){ 
TimerUtils.setContentSpan(mSpan,mSpanList.get(count),j,j+mGapLen); 
} 
//              ,              start   
start = start + vipNumbers[i].toCharArray().length; 
if (i < nonNumbers.length){ 
TimerUtils.setContentSpan(mSpan,mTextColorSpanList.get(i),start,start+mGapLen); 
start = start +mGapLen;//                      start   
} 
} 
mDateTv.setMovementMethod(LinkMovementMethod.getInstance()); 
mDateTv.setText(mSpan); 
} 
/** 
*      initSpanData   
*   number              MikyouBackgroundSpan   
*     MikyouBackgroundSpan               ,  ,      ,               
*   nonNumber         ForegroundColorSpan   
*                      ,      ForegroundColorSpan       
*           ,setmGapSpanColor                   
*            Span,          。 
* */ 
@Override 
public void initSpanData(String timeStr) { 
super.initSpanData(timeStr); 
vipNumbers = TimerUtils.getNumInTimerStr(timeStr);//              ,      
vipNonNumbers = TimerUtils.getNonNumInTimerStr(timeStr);//        ,       
for (int i=0;i<vipNumbers.length;i++){ 
for (int j=0;j<vipNumbers[i].toCharArray().length;j++){//                          ,         
MikyouBackgroundSpan mSpan = new MikyouBackgroundSpan(mContext.getDrawable(mDrawableId), ImageSpan.ALIGN_BOTTOM); 
initBackSpanStyle(mSpan); 
mSpanList.add(mSpan); 
} 
} 
for (int i= 0; i<vipNonNumbers.length;i++){ 
ForegroundColorSpan mGapSpan = new ForegroundColorSpan(mGapSpanColor); 
mTextColorSpanList.add(mGapSpan); 
} 
} 
}
4.TimerUtils 관리 류 는 주로 서로 다른 스타일 의 카운트다운 대상 을 클 라 이언 트 에 게 제공 하기 때문에 이런 유형 은 클 라 이언 트 와 직접 관 계 를 맺 고 카운트다운 서브 클래스 와 기본 클래스 가 외부 에 대한 숨겨 진 부분 에 대해 포장 성 을 나타 낸다.

package com.mikyou.countdowntimer.utils; 
import android.content.Context; 
import android.graphics.Color; 
import android.text.SpannableString; 
import android.text.Spanned; 
import android.text.style.ForegroundColorSpan; 
import com.mikyou.countdowntimer.bean.JDCountDownTimer; 
import com.mikyou.countdowntimer.bean.MikyouCountDownTimer; 
import com.mikyou.countdowntimer.bean.VIPCountDownTimer; 
/** 
* Created by mikyou on 16-10-22. 
*/ 
public class TimerUtils { 
public static final int JD_STYLE = 0; 
public static final int VIP_STYLE = 1; 
public static final int DEFAULT_STYLE = 3; 
public static final String TIME_STYLE_ONE = "HH:mm:ss"; 
public static final String TIME_STYLE_TWO = "HH mm ss "; 
public static final String TIME_STYLE_THREE = "dd HH mm ss "; 
public static final String TIME_STYLE_FOUR = "dd HH mm "; 
public static MikyouCountDownTimer getTimer(int style,Context mContext, long mGapTime, String mTimePattern, int mDrawableId){ 
MikyouCountDownTimer mCountDownTimer = null; 
switch (style){ 
case JD_STYLE: 
mCountDownTimer = new JDCountDownTimer(mContext,mGapTime,mTimePattern,mDrawableId); 
break; 
case VIP_STYLE: 
mCountDownTimer = new VIPCountDownTimer(mContext,mGapTime,mTimePattern,mDrawableId); 
break; 
case DEFAULT_STYLE: 
mCountDownTimer = new MikyouCountDownTimer(mContext,mGapTime,mTimePattern,mDrawableId); 
break; 
} 
return mCountDownTimer; 
} 
//                
public static String[] getNumInTimerStr(String mTimerStr){ 
return mTimerStr.split("[^\\d]"); 
} 
//                  ,                 ,           ,              
public static char[] getNonNumInTimerStr(String mTimerStr){ 
return mTimerStr.replaceAll("\\d","").toCharArray(); 
} 
//       
public static ForegroundColorSpan getTextColorSpan(String color){ 
ForegroundColorSpan mSpan = null; 
if (mSpan == null){ 
mSpan = new ForegroundColorSpan(Color.parseColor(color)); 
} 
return mSpan; 
} 
//     Span 
public static void setContentSpan(SpannableString mSpan, Object span, int start, 
int end) { 
mSpan.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 
} 
}
이제 TextView 로 이 루어 진 카운트다운 을 테스트 해 보 겠 습 니 다.
이 카운트다운 을 사용 하 는 것 은 매우 간단 하고 매우 편리 하 며 코드 한 줄 만 있 으 면 경 동과 각종 전자상거래 의 앱 을 모방 하 는 카운트다운 스타일 을 실현 할 수 있다.

package com.mikyou.countdowntimer; 
import android.graphics.Color; 
import android.os.Bundle; 
import android.support.v7.app.AppCompatActivity; 
import android.view.Gravity; 
import android.widget.LinearLayout; 
import android.widget.TextView; 
import com.mikyou.countdowntimer.utils.TimerUtils; 
public class MainActivity extends AppCompatActivity { 
private LinearLayout parent; 
private int padding =10; 
private int textSize = 40; 
@Override 
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
setContentView(R.layout.activity_main); 
parent = (LinearLayout) findViewById(R.id.parent); 
//                       
/** 
*   +    1:DEFAULT_STYLE <--> TIME_STYLE_ONE = "HH:mm:ss" 
* */ 
TextView tv = TimerUtils.getTimer(TimerUtils.DEFAULT_STYLE,this,120000000,TimerUtils.TIME_STYLE_ONE,0) 
.getmDateTv(); 
parent.addView(tv); 
setmLayoutParams(tv); 
/** 
*   +    2:DEFAULT_STYLE <--> TIME_STYLE_TWO = "HH mm ss " 
* */ 
TextView tv1 = TimerUtils.getTimer(TimerUtils.DEFAULT_STYLE,this,120000000,TimerUtils.TIME_STYLE_TWO,0) 
.getmDateTv(); 
parent.addView(tv1); 
setmLayoutParams(tv1); 
/** 
*   +    3:DEFAULT_STYLE <--> TIME_STYLE_THREE = "dd HH mm ss " 
* */ 
TextView tv2 = TimerUtils.getTimer(TimerUtils.DEFAULT_STYLE,this,120000000,TimerUtils.TIME_STYLE_THREE,0) 
.getmDateTv(); 
parent.addView(tv2); 
setmLayoutParams(tv2); 
/** 
*   +    4:DEFAULT_STYLE <--> TIME_STYLE_FOUR = "dd HH mm " 
* */ 
TextView tv3 = TimerUtils.getTimer(TimerUtils.DEFAULT_STYLE,this,120000000,TimerUtils.TIME_STYLE_FOUR,0) 
.getmDateTv(); 
parent.addView(tv3); 
setmLayoutParams(tv3); 
//      ,                ,                
/** 
*    +    1:JD_STYLE <--> TIME_STYLE_ONE = "HH:mm:ss" 
* */ 
TextView tv4= TimerUtils.getTimer(TimerUtils.JD_STYLE,this,120000000,TimerUtils.TIME_STYLE_ONE,R.drawable.timer_shape) 
.setTimerPadding(10,10,10,10)//      
.setTimerTextColor(Color.BLACK)//       
.setTimerTextSize(40)//       
.setTimerGapColor(Color.BLACK)//        
.getmDateTv();//  TextView   
parent.addView(tv4); 
setmLayoutParams(tv4); 
/** 
*    +    2:JD_STYLE <--> TIME_STYLE_TWO = "HH mm ss " 
* */ 
TextView tv5= TimerUtils.getTimer(TimerUtils.JD_STYLE,this,120000000,TimerUtils.TIME_STYLE_TWO,R.drawable.timer_shape2) 
.setTimerPadding(10,10,10,10) 
.setTimerTextColor(Color.WHITE) 
.setTimerTextSize(40) 
.setTimerGapColor(Color.BLACK) 
.getmDateTv(); 
parent.addView(tv5); 
setmLayoutParams(tv5); 
/** 
*    +    3:JD_STYLE <-->TIME_STYLE_THREE = "dd HH mm ss " 
* */ 
TextView tv6= TimerUtils.getTimer(TimerUtils.JD_STYLE,this,120000000,TimerUtils.TIME_STYLE_THREE,R.drawable.timer_shape2) 
.setTimerPadding(10,10,10,10) 
.setTimerTextColor(Color.YELLOW) 
.setTimerTextSize(40) 
.setTimerGapColor(Color.BLACK) 
.getmDateTv(); 
parent.addView(tv6); 
setmLayoutParams(tv6); 
/** 
*    +    4:JD_STYLE <-->TIME_STYLE_FOUR = "dd HH mm " 
* */ 
TextView tv7= TimerUtils.getTimer(TimerUtils.JD_STYLE,this,120000000,TimerUtils.TIME_STYLE_FOUR,R.drawable.timer_shape2) 
.setTimerPadding(15,15,15,15) 
.setTimerTextColor(Color.BLUE) 
.setTimerTextSize(40) 
.setTimerGapColor(Color.BLACK) 
.getmDateTv(); 
parent.addView(tv7); 
setmLayoutParams(tv7); 
/** 
*    +    1:VIP_STYLE <-->TIME_STYLE_ONE = "HH:mm:ss" 
* */ 
TextView tv8= TimerUtils.getTimer(TimerUtils.VIP_STYLE,this,120000000,TimerUtils.TIME_STYLE_ONE,R.drawable.timer_shape) 
.setTimerPadding(15,15,15,15) 
.setTimerTextColor(Color.BLACK) 
.setTimerTextSize(40) 
.setTimerGapColor(Color.BLACK) 
.getmDateTv(); 
parent.addView(tv8); 
setmLayoutParams(tv8); 
/** 
*    +    2:VIP_STYLE <-->TIME_STYLE_TWO = "HH mm ss " 
* */ 
TextView tv9= TimerUtils.getTimer(TimerUtils.VIP_STYLE,this,120000000,TimerUtils.TIME_STYLE_TWO,R.drawable.timer_shape2) 
.setTimerPadding(15,15,15,15) 
.setTimerTextColor(Color.WHITE) 
.setTimerTextSize(40) 
.setTimerGapColor(Color.BLACK) 
.getmDateTv(); 
parent.addView(tv9); 
setmLayoutParams(tv9); 
/** 
*    +    3:VIP_STYLE <-->TIME_STYLE_THREE = "dd HH mm ss " 
* */ 
TextView tv10= TimerUtils.getTimer(TimerUtils.VIP_STYLE,this,120000000,TimerUtils.TIME_STYLE_THREE,R.drawable.timer_shape2) 
.setTimerPadding(15,15,15,15) 
.setTimerTextColor(Color.YELLOW) 
.setTimerTextSize(40) 
.setTimerGapColor(Color.BLACK) 
.getmDateTv(); 
parent.addView(tv10); 
setmLayoutParams(tv10); 
/** 
*    +    4:VIP_STYLE <-->TIME_STYLE_FOUR = "dd HH mm " 
* */ 
TextView tv11= TimerUtils.getTimer(TimerUtils.VIP_STYLE,this,120000000,TimerUtils.TIME_STYLE_FOUR,R.drawable.timer_shape2) 
.setTimerPadding(15,15,15,15) 
.setTimerTextColor(Color.BLUE) 
.setTimerTextSize(40) 
.setTimerGapColor(Color.BLACK) 
.getmDateTv(); 
parent.addView(tv11); 
setmLayoutParams(tv11); 
} 
private void setmLayoutParams(TextView tv) { 
tv.setGravity(Gravity.CENTER_HORIZONTAL); 
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) tv.getLayoutParams(); 
params.setMargins(20,20,20,20); 
tv.setLayoutParams(params); 
} 
}
drawable 파일 두 개:
테두리 스타일

<?xml version="1.0" encoding="utf-8"?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
android:shape="rectangle" 
> 
<corners android:radius="5px"/> 
<stroke android:color="#88000000" android:width="1dp"/> 
</shape>
배경 과 테두리 스타일

<?xml version="1.0" encoding="utf-8"?> 
<shape xmlns:android="http://schemas.android.com/apk/res/android" 
android:shape="rectangle" 
> 
<corners android:radius="10px"/> 
<solid android:color="#000000"/> 
</shape>
이제 우리 운행 의 성 과 를 보 자.

운행 결 과 를 보면 괜 찮 은 것 같 습 니 다.사실 스타일 은 자신의 창의 와 아 이 디 어 를 많이 볼 수 있 습 니 다.이 카운트다운 패 키 징 이 부족 한 점 이 있다 면 많은 조언 을 해 주 십시오.하지만 지금 은 사용 이 편리 하고 간단 해서 코드 한 줄 로 해결 할 수 있 습 니 다.이 카운트다운 에 사용 되 는 곳 은 꽤 많 습 니 다.여러분 이 필요 하 다 면 자신의 프로젝트 에 직접 도입 할 수 있 습 니 다.
데모 다운로드
위 에서 말 한 것 은 편집장 님 께 서 소개 해 주신 안 드 로 이 드 에서 TextView 를 사용 하여 고 모 경 동 타 오 바 오의 각종 카운트다운 효 과 를 실현 하 는 것 입 니 다.여러분 께 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주세요.편집장 님 께 서 제때에 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!

좋은 웹페이지 즐겨찾기