iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >Android中使用TextView实现高仿京东淘宝各种倒计时效果
  • 208
分享到

Android中使用TextView实现高仿京东淘宝各种倒计时效果

倒计时淘宝Android 2022-06-06 07:06:01 208人浏览 泡泡鱼
摘要

今天给大家带来的是仅仅使用一个TextView实现一个高仿京东、淘宝、唯品会等各种电商APP的活动倒计时。最近公司一直加班也没来得及时间去整理,今天难得休息想把这个分享给大家,

今天给大家带来的是仅仅使用一个TextView实现一个高仿京东、淘宝、唯品会等各种电商APP的活动倒计时。最近公司一直加班也没来得及时间去整理,今天难得休息想把这个分享给大家,只求共同学习,以及自己后续的复习。为什么会想到使用一个TextView来实现呢?因为最近公司在做一些优化的工作,其中就有一个倒计时样式,原来开发的这个控件的同事使用了多个TextView拼接在一起的,实现的代码冗余比较大,故此项目经理就说:小宏这个就交给你来优化了,并且还要保证有一定的扩展性,当时就懵逼了。不知道从何处开始优化。然后我就查看京东,饿了么,唯品会等各个APP的倒计时,并在开发者中打开层级界面显示,发现他们都有一个共同的特点就是一个View,没有使用多个TextView来拼接。相信大家都知道仅仅使用一个TextView比使用多个TextView拼接去实现的优势吧,下面不妨来看看几个界面就知道了。


看到这个,大家心里自然就想到了自定义View来实现吧。对,自定义View确实可以实现这样的效果。但是今天我们不采用自定义View来做。而是使用一个TextView来实现。

由于项目经理要求此次优化的代码具有可扩展性。所以此次代码的设计加了一些面向对象的知识。有一些自己的设计和架构的思路。

此次demo的设计思路:

          1、编写一个倒计时的基类作为实现最普通和最基本的倒计时的功能,没有任何样式,让这个基类去继承CountDownTimer类,并且在该基类中

保存一个TextView的对象,并且把每次倒计时的数据,显示在TextView中,然后公布一个getmDateTv()方法返回一个TextView对象即可。然后只要拿到这个TextView对象显示界面的布局中即可。非常方便。

          2、然后不同样式的倒计时,只需要编写不同的子类去继承最普通的倒计时基类即可,然后重写其中的设置数据和设置样式的两个方法即可,然后就能给最普通的倒计时添加不同的样式。下次如果需要扩展新的倒计时样式,不需要改变其他类的代码,只需编写一个普通倒计时的派生类重写两个方法即可,使得可扩展性更灵活。

          3、然后通过一个TimerUtils管理类,去集中承担子类和父类压力,让子类和父类所需实现功能分担到TimerUtils类中,并且该TimerUtils管理类是与客户端唯一打交道的类,比如获得倒计时对象以及获得倒计时的TextView对象都通过这个管理类分配,避免客户端直接与倒计时的基类和子类打交道。从而使得类的封装性和隐藏性得到体现。

下面可以看下这个Demo设计的简单的UML类图:


通过以上思路分析下面我们就看看此次Demo的实现需要用到哪些知识点.

 1、CountDownTimer类的用法。

    2、SpannableString的用法。

    3、MikyouCountDownTimer的封装。

    4、自定义MikyouBackgroundSpan的实现。

一、通过以上的分析我们首先得复习一下有关CountDownTimer的知识,CountDownTimer是一个很简单的类我们可以看下的它的源码,它的用法自然就知道了。

CountDownTimer是一个抽象类。


// 
// 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间隔步长默认是1000ms,所以数据都是通过其构造器进行初始化,然后需要去重写一个回调方法onTick,里面的一个参数就是每隔相应的步长后剩余的时间毫秒数。然后我们只需要在onTick方法中将每隔1000ms时间毫秒数进行时间格式化即可得到相应时间格式的倒计时这就是实现了最基本倒计时样式。格式化倒计时格式采用的是apache中的common的lang包中DurationFORMatUtils类中的formatDuration,通过传入一个时间格式就会自动将倒计时转换成相应的mTimePattern的样式(HH:mm:ss或dd天HH时mm分ss秒).

二、复习一下有关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) BackgroundColorSpan 文本背景色

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) StyleSpan 字体样式:粗体、斜体等


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) RelativeSizeSpan 相对大小


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) ClickableSpan 文本有点击事件


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) UnderlineSpan 下划线


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); 
}

好了,通过以上的复习知识点,现在我们就可以来真正开始demo的实现,然后我们一起来一步一步封装我们的倒计时。

一、编写一个MikyouCountDownTimer基类,让它去继承CountDownTimer类,并且公布出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; 
 
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秒等。现在我们可以来看下简单的基本样式。

二、自定义MikyouBackgroundSpan去继承ImageSpan,这个类非常重要是用于给倒计时的TextView加样式,为什么可以使用一个TextView来实现呢

别忘了还有个很强悍的类就是SpannableString类,这个类就是可以设置一段字符串中的每个字符的样式,很多样式。最后通过TextView中有个setSpan方法即可传入
一个SpannableString对象完成设置。但是为什么需要自定义一个Span呢?这是因为很奇怪为什么android中的那么多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; 
 
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); } 
}

三、样式一的倒计时实现,样式一指的是例如:12时36分27秒或者12:36:27就是将数值和时、分、秒或者":"分隔开,然后去自定义每块数值(12 36 27)和间隔(时 分 秒 或 :)的样式,包括给数值块加背景和边框。在MikyouCountDownTimer中的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; 
 
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; 
} 
 
@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); 
} 
} 
 
@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); 
} 
}

四、样式二的倒计时实现,样式二不同于样式一的是例如:12时36分27秒或者12:36:27就是将每个数值和时、分、秒或者":"分隔开,然后去自定义每块数值(1 2 3 6 2 7)和间隔(时 分 秒 或 :)的样式,包括给数值块加背景和边框。在MikyouCountDownTimer中的vipNumber数组中保存着[1 2 3 6 2 7]而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; 
 
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<>(); 
} 
 
@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); 
} 
 
@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); 
} 
} 
}

四、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; 
 
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实现的倒计时。

使用该倒计时非常简单非常方便只需要一行代码就能实现一个高仿京东和各种电商的APP的倒计时样式。


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); 
//默认样式倒计时每种样式下又对应四种时间的格式 
 
TextView tv = TimerUtils.getTimer(TimerUtils.DEFAULT_STYLE,this,120000000,TimerUtils.TIME_STYLE_ONE,0) 
.getmDateTv(); 
parent.addView(tv); 
setmLayoutParams(tv); 
 
TextView tv1 = TimerUtils.getTimer(TimerUtils.DEFAULT_STYLE,this,120000000,TimerUtils.TIME_STYLE_TWO,0) 
.getmDateTv(); 
parent.addView(tv1); 
setmLayoutParams(tv1); 
 
TextView tv2 = TimerUtils.getTimer(TimerUtils.DEFAULT_STYLE,this,120000000,TimerUtils.TIME_STYLE_THREE,0) 
.getmDateTv(); 
parent.addView(tv2); 
setmLayoutParams(tv2); 
 
TextView tv3 = TimerUtils.getTimer(TimerUtils.DEFAULT_STYLE,this,120000000,TimerUtils.TIME_STYLE_FOUR,0) 
.getmDateTv(); 
parent.addView(tv3); 
setmLayoutParams(tv3); 
//样式一倒计时,就是每块数值和每个间隔分开的样式,每种样式下又对应四种时间的格式 
 
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); 
 
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); 
 
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); 
 
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); 
 
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); 
 
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); 
 
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); 
 
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>

现在就看看我们运行的成果吧。

看看运行结果还不错吧,其实它的样式还可以定义很多种主要看自己的创意和想法了,这个倒计时封装如果还有什么不足之处,请多多提出建议。但是现在使用还是蛮方便和简单的,一行代码就能就能解决。这个倒计时用到的地方还是蛮多的,大家有需要的话可以直接引入到自己的项目中。

Demo下载

以上所述是小编给大家介绍的Android中使用TextView实现高仿京东淘宝各种倒计时效果,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的,在此也非常感谢大家对编程网网站的支持!

您可能感兴趣的文章:Android倒计时的开始与停止 剩余时分秒的展示Android仿Keep运动休息倒计时圆形控件android实现条目倒计时功能Android利用RecyclerView实现列表倒计时效果android自定义倒计时控件示例android实现倒计时功能代码Android实现计时与倒计时的常用方法小结Android实现加载广告图片和倒计时的开屏布局Android 实现闪屏页和右上角的倒计时跳转实例代码Android倒计时控件 Splash界面5秒自动跳转


--结束END--

本文标题: Android中使用TextView实现高仿京东淘宝各种倒计时效果

本文链接: https://www.lsjlt.com/news/23521.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作