这是一个自定义的倒计时控件,具有3D上下翻页翻转效果。最近项目中需要做一个倒计时控件,需要和iOS端的效果保持一样。大致效果是这样的,如下图所示:

由于暂时还不会怎么样制作gif动态图,所以想看具体效果的,可以在下面的源码中下载运行查看。

废话不说了,开干吧。那么是怎么实现呢?我们首先得找到3D翻页的效果,这个效果我是参考的一个github项目,https://github.com/emilsjolander/android-FlipView。

其次,倒计时的逻辑,这个不难,最后是自定义的View了。

下面是动画的效果

1.动画的效果

(1).这里的动画效果是由Scroller类来实现的。

public void startScroll (int startX, int startY, int dx, int dy, int duration)

(2).翻页效果
           主要分为三部分

|___绘制控件翻转页面的上半部分:

 canvas.clipRect(mTopRect);

|___绘制控件翻转页面的下半部分:

canvas.clipRect(mBottomRect);

|___绘制控件中间的翻页部分:这里利用的是camera类的方法,

camera.rotateX()//看意思就明白表示沿X轴翻转,这是翻转效果的核心方法。
camera.clipRect(mTopRect,mBottom) //根据当前翻转的度数(0~180度),决定画布裁剪部分。
camera.getMatrix(mMatrix) //设置matrix矩阵的值,对中间页进行变形,达到翻页的视觉效果。
//然后通过矩阵变换,绘制视图和控件
mMatrix.preScale(0.25f, 0.25f);
mMatrix.postScale(4.0f, 4.0f);
mMatrix.preTranslate(-getWidth() / 2, -getHeight() / 2);
mMatrix.postTranslate(getWidth() / 2, getHeight() / 2);
canvas.concat(mMatrix)
drawChild();

其中,控件中间的黑线,也是自定义的一个TextView,因为原生的TextView没有设置文字上画黑线的方法,有画线的方法,但是是跟着字体的颜色变化的,所以不符合需求,需要自定义一下,设置绘画的颜色。

不说了,上代码

clock_view_activity.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:customs="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#3B96FD"android:gravity="center_horizontal"android:orientation="vertical" ><com.example.timeticker.MyClockViewandroid:id="@+id/clockView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="14dp"android:background="@mipmap/tcd_timer_bg"customs:dayTextBackground="@drawable/time_bg"customs:dayTextColor="#ffffff"customs:hourTextBackground="@drawable/time_bg"customs:hourTextColor="#ffffff"customs:minTextBackground="@drawable/time_bg"customs:minTextColor="#ffffff"customs:secTextBackground="@drawable/time_bg"customs:secTextColor="#ffffff" ></com.example.timeticker.MyClockView><Buttonandroid:id="@+id/button1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="倒计时" /></LinearLayout>

attrs.xml 自定义的属性

<?xml version="1.0" encoding="utf-8"?>
<resources><declare-styleable name="MyClock"><attr name="dayTextSize" format="dimension" /><attr name="hourTextSize" format="dimension" /><attr name="minTextSize" format="dimension" /><attr name="secTextSize" format="dimension" /><attr name="dayTextColor" format="color" /><attr name="hourTextColor" format="color" /><attr name="minTextColor" format="color" /><attr name="secTextColor" format="color" /><attr name="dayTextBackground" format="reference|color" /><attr name="hourTextBackground" format="reference|color" /><attr name="minTextBackground" format="reference|color" /><attr name="secTextBackground" format="reference|color" /></declare-styleable>
</resources>

ids.xml 因为用到的是动态布局,为了能找到控件,得为每个控件设置一个id

<?xml version="1.0" encoding="utf-8"?>
<resources><item name="dayTextView" type="id" /><item name="hourTextView" type="id" /><item name="minTextView" type="id" /><item name="secTextView" type="id" />
</resources>

time_bg.xml 控件的样式

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" ><corners android:radius="3dp" /><!-- 实心 即填充颜色 --><solid android:color="#0B315C" /><!-- 按钮文字和边缘距离(内边距) --><paddingandroid:bottom="3dp"android:left="6dp"android:right="6dp"android:top="3dp" /></shape>

clock_view_bg.xml 控件外框的样式

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" ><corners android:radius="10dp" /><!-- 实心 即填充颜色 --><solid android:color="#00000000" /><strokeandroid:width="2dp"android:color="#2F80E9" /><!-- 按钮文字和边缘距离(内边距) --><paddingandroid:bottom="5dp"android:left="5dp"android:right="5dp"android:top="5dp" /></shape>

FlipClockView.java

package com.example.timeticker;import android.content.Context;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.Scroller;
import android.widget.TextView;/**日历3D翻转效果*/
public class FlipClockView extends FrameLayout {private TextView mVisibleTextView;// 可见的private TextView mInvisibleTextView;// 不可见private int layoutWidth;private int layoutHeight;private Scroller mScroller;private Camera mCamera = new Camera();private Matrix mMatrix = new Matrix();private Rect mTopRect = new Rect();private Rect mBottomRect = new Rect();private boolean isUp2Down = true;private Paint mShinePaint = new Paint();private Paint mShadePaint = new Paint();private boolean isFlipping = false;public FlipClockView(Context context) {this(context, null);}public FlipClockView(Context context, AttributeSet attrs) {super(context, attrs, 0);init(context);}public FlipClockView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}public void init(Context context) {mScroller = new Scroller(context, new DecelerateInterpolator());// 减速 // 动画插入器mInvisibleTextView = new MyTextView(context);mInvisibleTextView.setText("0");mInvisibleTextView.setGravity(Gravity.CENTER);mInvisibleTextView.setIncludeFontPadding(false);addView(mInvisibleTextView);mVisibleTextView = new MyTextView(context);mVisibleTextView.setText("0");mVisibleTextView.setGravity(Gravity.CENTER);mVisibleTextView.setIncludeFontPadding(false);addView(mVisibleTextView);mShadePaint.setColor(Color.BLACK);mShadePaint.setStyle(Paint.Style.FILL);mShinePaint.setColor(Color.WHITE);mShinePaint.setStyle(Paint.Style.FILL);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);layoutWidth = MeasureSpec.getSize(widthMeasureSpec);layoutHeight = MeasureSpec.getSize(heightMeasureSpec);setMeasuredDimension(layoutWidth, layoutHeight);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {super.onLayout(changed, left, top, right, bottom);int count = getChildCount();//将两个textView放置进去for (int i = 0; i < count; i++) {View child = getChildAt(i);child.layout(0, 0, layoutWidth, layoutHeight);}mTopRect.top = 0;mTopRect.left = 0;mTopRect.right = getWidth();mTopRect.bottom = getHeight() / 2;mBottomRect.top = getHeight() / 2;mBottomRect.left = 0;mBottomRect.right = getWidth();mBottomRect.bottom = getHeight();}@Overrideprotected void dispatchDraw(Canvas canvas) {super.dispatchDraw(canvas);if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {drawTopHalf(canvas);drawBottomHalf(canvas);drawFlipHalf(canvas);postInvalidate();} else {if (isFlipping) {showViews(canvas);}if (mScroller.isFinished() && !mScroller.computeScrollOffset()) {isFlipping = false;}}}/*** 显示需要显示的数字* * @param canvas*/private void showViews(Canvas canvas) {String current = mVisibleTextView.getText().toString();String past = mInvisibleTextView.getText().toString();// Log.e("需要显示的数字--->",current+ "%%    "+past);mVisibleTextView.setText(past);mInvisibleTextView.setText(current);// 防止切换抖动drawChild(canvas, mVisibleTextView, 0);}/** 画下半部分 */private void drawBottomHalf(Canvas canvas) {canvas.save();canvas.clipRect(mBottomRect);View drawView = !isUp2Down ? mInvisibleTextView : mVisibleTextView;drawChild(canvas, drawView, 0);canvas.restore();}/** 画上半部分 */private void drawTopHalf(Canvas canvas) {canvas.save();canvas.clipRect(mTopRect);View drawView = !isUp2Down ? mVisibleTextView : mInvisibleTextView;drawChild(canvas, drawView, 0);canvas.restore();}/** 画翻页部分 */private void drawFlipHalf(Canvas canvas) {canvas.save();mCamera.save();View view = null;float deg = getDeg();if (deg > 90) {canvas.clipRect(!isUp2Down ? mTopRect : mBottomRect);mCamera.rotateX(!isUp2Down ? deg - 180 : -(deg - 180));view = mInvisibleTextView;} else {canvas.clipRect(!isUp2Down ? mBottomRect : mTopRect);mCamera.rotateX(!isUp2Down ? deg : -deg);view = mVisibleTextView;}mCamera.getMatrix(mMatrix);positionMatrix();canvas.concat(mMatrix);if (view != null) {drawChild(canvas, view, 0);}drawFlippingShadeShine(canvas);mCamera.restore();canvas.restore();}private float getDeg() {return mScroller.getCurrY() * 1.0f / layoutHeight * 180;}/** 绘制翻页时的阳面和阴面 */private void drawFlippingShadeShine(Canvas canvas) {final float degreesFlipped = getDeg();// Log.d(TAG, "deg: " + degreesFlipped);if (degreesFlipped < 90) {final int alpha = getAlpha(degreesFlipped);// Log.d(TAG, "小于90度时的透明度-------------------> " + alpha);mShinePaint.setAlpha(alpha);mShadePaint.setAlpha(alpha);canvas.drawRect(!isUp2Down ? mBottomRect : mTopRect, !isUp2Down ? mShinePaint: mShadePaint);} else {final int alpha = getAlpha(Math.abs(degreesFlipped - 180));// Log.d(TAG, "大于90度时的透明度-------------> " + alpha);mShadePaint.setAlpha(alpha);mShinePaint.setAlpha(alpha);canvas.drawRect(!isUp2Down ? mTopRect : mBottomRect, !isUp2Down ? mShadePaint: mShinePaint);}}private int getAlpha(float degreesFlipped) {return (int) ((degreesFlipped / 90f) * 100);}private void positionMatrix() {mMatrix.preScale(0.25f, 0.25f);mMatrix.postScale(4.0f, 4.0f);mMatrix.preTranslate(-getWidth() / 2, -getHeight() / 2);mMatrix.postTranslate(getWidth() / 2, getHeight() / 2);}/** 初始化隐藏textView显示的值 */private void initTextView() {int visibleValue = Integer.parseInt(mVisibleTextView.getText().toString());//   int invisibleValue = isUp2Down ? visibleValue - 1 : visibleValue + 1;//这里控制是 + 还是 -int invisibleValue = visibleValue - 1;if (invisibleValue < 10) {mInvisibleTextView.setText("0" + invisibleValue);} else {mInvisibleTextView.setText("" + invisibleValue);}}/**** @param isUp2Down*     方向标识 true: 从上往下翻  , false: 从下往上翻*/public void setFlipDirection(boolean isUp2Down) {this.isUp2Down = isUp2Down;}public void smoothFlip() {//Log.e(TAG, "翻动 ");initTextView();isFlipping = true;mScroller.startScroll(0, 0, 0, layoutHeight, 700);postInvalidate();}public TextView getmVisibleTextView() {return mVisibleTextView;}public TextView getmInvisibleTextView() {return mInvisibleTextView;}public boolean isFlipping() {return isFlipping && !mScroller.isFinished()&& mScroller.computeScrollOffset();}/*** 获取当前View值* * @return*/public int getCurrentValue() {return Integer.parseInt(mVisibleTextView.getText().toString());}/*** 设置view的时间值* @param textTime*/public void setClockTime(String textTime) {mVisibleTextView.setText(textTime);}/*** 设置时间数字的背景* @param drawable*/public void setClockBackground(Drawable drawable) {mVisibleTextView.setBackground(drawable);mInvisibleTextView.setBackground(drawable);}/*** 设置时间数字的颜色* @param color*/public void setClockTextColor(int color) {mVisibleTextView.setTextColor(color);mInvisibleTextView.setTextColor(color);}/*** 设置时间数字的大小* @param size*/public void setClockTextSize(float size){mVisibleTextView.setTextSize(size);mInvisibleTextView.setTextSize(size);}}

MyClockView.java

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;public class MyClockView extends RelativeLayout {private float dayTextSize, hourTextSize, minTextSize, secTextSize;private FlipClockView dayTextView, hourTextView, minTextView, secTextView;private TextView dTextView, hTextView, mTextView, sTextView;private LayoutParams dayLayoutParams, hourLayoutParams, minLayoutParams,secLayoutParams;private DownCountTimerListener mDownCountTimerListener;private Handler mHandler;private Runnable mRunnable;private long totalTime = 0;private boolean isRunning = true;private int screenW;private long outNumber=0;//超过的最大计数的时间(秒数)public MyClockView(Context context, AttributeSet attrs) {super(context, attrs);initView(context, attrs);}public MyClockView(Context context) {this(context, null);}public MyClockView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initView(context, attrs);}public void initView(Context context, AttributeSet attrs) {screenW=getScreenWidth(context);TypedArray tArray = context.obtainStyledAttributes(attrs,R.styleable.MyClock);dayTextSize = tArray.getDimension(R.styleable.MyClock_dayTextSize, 26f);hourTextSize = tArray.getDimension(R.styleable.MyClock_hourTextSize,26f);minTextSize = tArray.getDimension(R.styleable.MyClock_minTextSize, 26f);secTextSize = tArray.getDimension(R.styleable.MyClock_secTextSize, 26f);int dayTextColor = tArray.getColor(R.styleable.MyClock_dayTextColor,0xffffff);int hourTextColor = tArray.getColor(R.styleable.MyClock_hourTextColor,0xffffff);int minTextColor = tArray.getColor(R.styleable.MyClock_minTextColor,0xffffff);int secTextColor = tArray.getColor(R.styleable.MyClock_secTextColor,0xffffff);Drawable dayTextBg = tArray.getDrawable(R.styleable.MyClock_dayTextBackground);Drawable hourTextBg = tArray.getDrawable(R.styleable.MyClock_hourTextBackground);Drawable minTextBg = tArray.getDrawable(R.styleable.MyClock_minTextBackground);Drawable secTextBg = tArray.getDrawable(R.styleable.MyClock_secTextBackground);tArray.recycle();dayTextView = new FlipClockView(context);hourTextView = new FlipClockView(context);minTextView = new FlipClockView(context);secTextView = new FlipClockView(context);dayTextView.setId(R.id.dayTextView);hourTextView.setId(R.id.hourTextView);minTextView.setId(R.id.minTextView);secTextView.setId(R.id.secTextView);dTextView = new TextView(context);hTextView = new TextView(context);mTextView = new TextView(context);sTextView = new TextView(context);dTextView.setText("DAYS");hTextView.setText("HOURS");mTextView.setText("MINUTES");sTextView.setText("SECONDS");dTextView.setTextColor(Color.parseColor("#ffffff"));hTextView.setTextColor(Color.parseColor("#ffffff"));mTextView.setTextColor(Color.parseColor("#ffffff"));sTextView.setTextColor(Color.parseColor("#ffffff"));dTextView.setTextSize(10f);hTextView.setTextSize(10f);mTextView.setTextSize(10f);sTextView.setTextSize(10f);dayTextView.setClockBackground(dayTextBg);dayTextView.setClockTextSize(dayTextSize);dayTextView.setClockTextColor(dayTextColor);hourTextView.setClockBackground(hourTextBg);hourTextView.setClockTextSize(dayTextSize);hourTextView.setClockTextColor(hourTextColor);minTextView.setClockBackground(minTextBg);minTextView.setClockTextSize(dayTextSize);minTextView.setClockTextColor(minTextColor);secTextView.setClockBackground(secTextBg);secTextView.setClockTextSize(dayTextSize);secTextView.setClockTextColor(secTextColor);//secTextView.setFlipDirection(false);//Log.e("---->","屏幕的宽"+screenW);int viewWidth=(int)(screenW*0.14);int viewMargin=(int)(screenW*0.05);dTextView.setWidth(viewWidth);dTextView.setGravity(Gravity.CENTER);hTextView.setWidth(viewWidth);hTextView.setGravity(Gravity.CENTER);mTextView.setWidth(viewWidth);mTextView.setGravity(Gravity.CENTER);sTextView.setWidth(viewWidth);sTextView.setGravity(Gravity.CENTER);dayLayoutParams = new LayoutParams(viewWidth,viewWidth);dayLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, TRUE);dayLayoutParams.setMargins(0, 60, 0, 0);addView(dayTextView, dayLayoutParams);LayoutParams dLayoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);dLayoutParams.addRule(RelativeLayout.BELOW, R.id.dayTextView);dLayoutParams.addRule(RelativeLayout.ALIGN_LEFT, R.id.dayTextView);dLayoutParams.setMargins(0, 5, 0, 60);addView(dTextView, dLayoutParams);hourLayoutParams = new LayoutParams(viewWidth,viewWidth);hourLayoutParams.addRule(RelativeLayout.RIGHT_OF, R.id.dayTextView);hourLayoutParams.setMargins(viewMargin, 60, viewMargin, 0);addView(hourTextView, hourLayoutParams);LayoutParams hLayoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);hLayoutParams.addRule(RelativeLayout.ALIGN_LEFT, R.id.hourTextView);hLayoutParams.addRule(RelativeLayout.BELOW, R.id.hourTextView);hLayoutParams.setMargins(0, 5, 0, 0);addView(hTextView, hLayoutParams);minLayoutParams = new LayoutParams(viewWidth,viewWidth);minLayoutParams.setMargins(0, 60, 0, 0);minLayoutParams.addRule(RelativeLayout.RIGHT_OF, R.id.hourTextView);addView(minTextView, minLayoutParams);LayoutParams mLayoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);mLayoutParams.addRule(RelativeLayout.ALIGN_LEFT, R.id.minTextView);mLayoutParams.addRule(RelativeLayout.BELOW, R.id.minTextView);mLayoutParams.setMargins(0, 5, 0, 0);addView(mTextView, mLayoutParams);secLayoutParams = new LayoutParams(viewWidth,viewWidth);secLayoutParams.addRule(RelativeLayout.RIGHT_OF, R.id.minTextView);secLayoutParams.setMargins(viewMargin, 60, 0, 0);addView(secTextView, secLayoutParams);LayoutParams sLayoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);sLayoutParams.addRule(RelativeLayout.ALIGN_LEFT, R.id.secTextView);sLayoutParams.addRule(RelativeLayout.BELOW, R.id.secTextView);sLayoutParams.setMargins(0, 5, 0, 0);addView(sTextView, sLayoutParams);dayTextView.setClockTime("00");hourTextView.setClockTime("00");minTextView.setClockTime("00");secTextView.setClockTime("00");mHandler = new Handler();}public interface DownCountTimerListener {void stopDownCountTimer();}/*** 暂停计时*/public void pauseDownCountTimer() {if (mRunnable != null) {mHandler.removeCallbacks(mRunnable);dayTextView.setClockTime("00");hourTextView.setClockTime("00");minTextView.setClockTime("00");secTextView.setClockTime("00");//   Log.e("暂停计时", "-=-=-=-=-=");}}public void setDownCountTimerListener(DownCountTimerListener listener) {this.mDownCountTimerListener = listener;}/*** 获取设置倒计时的总时间* @return*/public long getDownCountTime() {return totalTime;}/*** 设定需要倒计时的总共时间** @param totalDownCountTimes*/public void setDownCountTime(long totalDownCountTimes) {this.totalTime = totalDownCountTimes;pauseDownCountTimer();}/*** 设定倒计时的时间开始时间和结束时间** @param startTime* @param endTime*/public void setDownCountTime(long startTime, long endTime) {this.totalTime = endTime - startTime;pauseDownCountTimer();}/*** 开始倒计时*/public void startDownCountTimer() {isRunning=true;setTime2Text(getDownCountTime());mRunnable = new Runnable() {@Overridepublic void run() {int i=secTextView.getCurrentValue();// Log.e("sec时间----->",i + "");outNumber--;if (outNumber<=0) {if (i > 0) {secTextView.smoothFlip();} else {int j = getClockMinValue();j--;if (j >= 0 && i == 0) {//Log.e("分钟时间----->", j + "");minTextView.smoothFlip();secTextView.setClockTime("60");secTextView.smoothFlip();} else {int k = getClockHourValue();k--;if (k >= 0 && j < 0 && i == 0) {hourTextView.smoothFlip();minTextView.setClockTime("60");minTextView.smoothFlip();secTextView.setClockTime("60");secTextView.smoothFlip();} else {int d = getClockDayValue();d--;if (d < 0) {// Log.e("时间结束----->", j + "    " + i);isRunning = false;if (null != mDownCountTimerListener) {mDownCountTimerListener.stopDownCountTimer();}} else {Log.e("day----->", d + "    ");secTextView.setClockTime("60");minTextView.setClockTime("60");hourTextView.setClockTime("24");d++;dayTextView.setClockTime("" + d);secTextView.smoothFlip();minTextView.smoothFlip();hourTextView.smoothFlip();dayTextView.smoothFlip();}}}}}if (isRunning) {mHandler.postDelayed(this, 1000);} else {mHandler.removeCallbacks(this);}}};mHandler.postDelayed(mRunnable, 1000);}/*** 获取倒计时剩余的时间,数组的4个元素分别代表剩余的天、时、分、秒* @return*/public String[] getClockRestTime(){String[] restTime=new String[4];restTime[0]=String.valueOf(getClockDayValue());restTime[1]=String.valueOf(getClockHourValue());restTime[2]=String.valueOf(getClockMinValue());restTime[3]=String.valueOf(getClockSecValue());return restTime;}public int getScreenWidth(Context mContext) {return mContext.getResources().getDisplayMetrics().widthPixels;}/*** 根据给定的时间转换为 天、时、分** @param startTime*/private void setTime2Text(long startTime) {int ss = 1000;int mi = ss * 60;int hh = mi * 60;int dd = hh * 24;long day = startTime / dd;long hour = (startTime - day * dd) / hh;long minute = (startTime - day * dd - hour * hh) / mi;long second = (startTime - day * dd - hour * hh - minute * mi) / ss;String strDay = day < 10 ? "0" + day : "" + day; // 天String strHour = hour < 10 ? "0" + hour : "" + hour;// 小时String strMinute = minute < 10 ? "0" + minute : "" + minute;// 分钟String strSecond = second < 10 ? "0" + second : "" + second;// 秒Log.e("时间----》", strDay+"  "+strHour +"  "+strMinute+"  "+strSecond);if (Integer.parseInt(strDay) >= 100) {dayTextView.setClockTime("99");hourTextView.setClockTime("23");minTextView.setClockTime("59");secTextView.getmInvisibleTextView().setText("59");secTextView.getmVisibleTextView().setText("59");outNumber=((startTime)-1000L*60L*60L*24L*100L)/1000L;// Log.e("多余的时间----》",outNumber+"");} else {dayTextView.setClockTime(strDay);hourTextView.setClockTime(strHour);minTextView.setClockTime(strMinute);secTextView.getmVisibleTextView().setText(strSecond);secTextView.getmInvisibleTextView().setText(strSecond);outNumber=0;}}public int getClockDayValue() {return dayTextView.getCurrentValue();}public int getClockHourValue() {return hourTextView.getCurrentValue();}public int getClockMinValue() {return minTextView.getCurrentValue();}public int getClockSecValue(){return secTextView.getCurrentValue();}}
MyTextView.java
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.TextView;public class MyTextView extends TextView {Paint mPaint;public MyTextView(Context context, AttributeSet attrs) {super(context, attrs);initPaint();}public MyTextView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initPaint();}public MyTextView(Context context) {this(context, null);initPaint();}private void initPaint() {mPaint=new Paint(Paint.ANTI_ALIAS_FLAG);mPaint.setStyle(Paint.Style.FILL);mPaint.setColor(Color.BLACK);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawRect(0,getMeasuredHeight()/2-1,getMeasuredWidth(),getMeasuredHeight()/2+1, mPaint);}}
MainActivity.java
MainActivity.java
package com.example.timeticker;import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;public class MainActivity extends AppCompatActivity implements View.OnClickListener, MyClockView.DownCountTimerListener {Button mBtn;private MyClockView myClockView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.clock_view_activity);mBtn = (Button) findViewById(R.id.button1);mBtn.setOnClickListener(this);myClockView = (MyClockView) findViewById(R.id.clockView);myClockView.setDownCountTimerListener(this);}@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.button1:myClockView.setDownCountTime(1000L * 60L + 1000L * 12L);myClockView.startDownCountTimer();break;default:break;}}@Overridepublic void stopDownCountTimer() {Toast.makeText(this,"结束了",Toast.LENGTH_SHORT).show();}
}

PS.上面的效果,可能在某些手机上翻转时的效果会出现闪烁的现象,是因为手机的硬件加速功能开启了的原因,为此。你需要在初始化view的时候关闭硬件加速。

myClockView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

还有,有些手机上适配效果不好,可以在布局文件里添加padding的属性,保证控件都在所包裹的父布局中。

好了,上面应该比较清楚了,有不清楚的,可以留言,欢迎探讨。
喜欢本文的,点个赞。

点击下载Demo

Android自定义控件之3D上下翻页效果的倒计时控件相关推荐

  1. html表格翻页简单,利用jQuery实现一个简单的表格上下翻页效果

    前言 本文主要介绍的是利用jQuery实现一个简单的表格上下翻页效果,注:实现原理与轮播图相似.下面话不多说,来看看详细的 实现方法吧. html: 日期参与团购场次团购结果当前状态 02.08 第一 ...

  2. html 上下翻页效果代码,原生js实现可以带上下翻页的翻页功能(代码)

    本篇文章给大家带来的内容是关于原生js实现可以带上下翻页的翻页功能(代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 翻页功能在渲染数据时经常用到,下面是使用原生JS去实现的一个 ...

  3. html5页面上下翻页特效,h5实现垂直上下翻页效果

    这两天比较有时间就自己简单的研究了一下现在比较流行的结婚请柬h5的制作方法. 简单的编写了一下代码如下: html部分 请柬标题 Lorem ipsum dolor sit amet, consect ...

  4. 在PHP当中制作隔行换色的效果以及制作上下翻页的效果!

    首先说明隔行换色的效果,需要用到tr:nth_child(odd);或者括号里的值是even,odd是从第一行开始隔一行,even是从第二行开始: 具体代码如下图案所示: 1 <style> ...

  5. android 辅助功能 翻页,Android利用悬浮按钮实现翻页效果

    今天给大家分享下自己用悬浮按钮点击实现翻页效果的例子. 首先,一个按钮要实现悬浮,就要用到系统顶级窗口相关的WindowManager,WindowManager.LayoutParams.那么在An ...

  6. 手机qq浏览器怎么设置上下翻页按钮 手机qq浏览器设置上下翻页按钮的方法

    1.打开qq浏览器,点击右下角"我的". 手机qq浏览器怎么设置上下翻页按钮?手机qq浏览器设置上下翻页按钮的方法[多图] 2.点击右上角设置图标. 手机qq浏览器怎么设置上下翻页 ...

  7. HTML5手机页面触屏滑动上下翻页特效

    和手机桌面管理的翻页特效一样,这个是html5实现上下翻页 下载地址: http://www.webkfa.com/one328/w1026.html

  8. CentOs上下翻页

    在windows上虚拟机中安装的CentOS,在命令窗口输入某个命令后,显示的内容较多,但是我想看前面几行的内容,可以使用下面的按键进行上下翻页的操作: 向上翻页查看 Shift + PgUp 向下翻 ...

  9. 一级计算机ppt切换效果怎么做,PPT翻页效果、倒计时怎么做?一分钟变电脑大神...

    原标题:PPT翻页效果.倒计时怎么做?一分钟变电脑大神 很多人在问小编PPT翻页效果.倒计时效果怎么做?翻页效果.倒计时效果能让PPT变得生动有趣,而且操作过程十分简单,一起来看看吧! 一.PPT翻页 ...

最新文章

  1. bigdecimal比较是否相等_java基础教程之字符串的介绍,比较重要的一个知识点【四】...
  2. tomcat不能多次startup.sh,异常时直接,分析logs目录下的日志。
  3. 每日一题:leetcode190.颠倒二进制位
  4. 没有bug队——加贝——Python 练习实例 33,34
  5. 教育|关于本科生科研的一些想法和建议
  6. Linux下TCP循环接收数据的方式
  7. linux uuid挂载磁盘_linux-开机自动挂载磁盘简介
  8. BSC(币安智能链)主网链部署
  9. 大漠插件常见问题汇总
  10. svn 报 系统找不到指定路径
  11. 电脑主板线路连接图解_主板接线图解
  12. 通过nginx搭建一个基于http-flv的直播流媒体服务器
  13. 稳定的IP地址查询接口
  14. c语言什么意思 app 视频 新闻,开发新闻资讯APP需要哪些功能?
  15. win2012故障转移mysql集群_Windows 2012 系统搭建高可用故障转移集群
  16. java 商城 商品查询_Javaweb网上商城项目实战(17)实现商品详情查询
  17. 雅思等出国留学成绩要求一知半解?戳这里
  18. 51nod 2455 花园
  19. Django实现用户注册登录,表单提交后跳转网页(学习笔记)
  20. 人民大学:2016经济将深度下滑 货币政策应适度宽松

热门文章

  1. 主题酒店api,携程酒店信息查询
  2. 一阶电路暂态响应的结果分析。_【每日电路赏析】过流保护电路
  3. 如何安装 mac El Capitan 系统
  4. 秋季养生保健常识大全
  5. Android开发--调用系统邮件
  6. IEEE SCI期刊、会议模板下载
  7. iOS 仿QQ录音以及振幅动画实现
  8. 节奏对于游戏配音的重要性
  9. 报价、订货、付款方式、通关、保险、提单、结汇等问题解析
  10. 视频网站如何选择视频服务器呢?