• android翻转效果时钟


    效果如下:

     

     功能类:

    import android.content.Context;
    import android.content.res.TypedArray;
    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.Typeface;
    import android.util.AttributeSet;
    import android.util.Log;
    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;
    
    import com.nxwna.leartime.R;
    
    import java.util.Calendar;
    
    
    public class FlipLayout extends FrameLayout  {
        private TextView mVisibleTextView;//可见的
        private TextView mInvisibleTextView;//不可见
    
    
        private int layoutWidth;
        private int layoutHeight;
        private Scroller mScroller;
        private String TAG = "FlipLayout";
        private String timetag;//根据时间标记获取时间
        private Camera mCamera = new Camera();
        private Matrix mMatrix = new Matrix();
        private Rect mTopRect = new Rect();
        private Rect mBottomRect = new Rect();
        private boolean isUp = true;
        private Paint mminutenePaint = new Paint();
        private Paint mShadePaint = new Paint();
        private boolean isFlipping = false;
        private boolean isCountDown = false;
        private int maxNumber; //设置显示的最大值
        private int flipTimes = 0;
        private int timesCount = 0;
    
        private FlipOverListener mFlipOverListener;
    
        public FlipLayout(Context context) {
            super(context, null);
        }
    
        public FlipLayout(Context context, AttributeSet attrs) {
            super(context, attrs, 0);
    
            TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.FlipLayout);
    
            int resId = array.getResourceId(R.styleable.FlipLayout_flipTextBackground,-1);
            int color = Color.WHITE;
            if(-1 == resId){
                color = array.getColor(R.styleable.FlipLayout_flipTextBackground, Color.WHITE);
            }
            float size = array.getDimension(R.styleable.FlipLayout_flipTextSize,36);
            size = px2dip(context,size);
            int textColor = array.getColor(R.styleable.FlipLayout_flipTextColor, Color.BLACK);
    
            array.recycle();
            init(context,resId,color,size,textColor);
        }
    
        private void init(Context context, int resId, int color, float size, int textColor) {
            mScroller = new Scroller(context,new DecelerateInterpolator());//减速 动画插入器
            Typeface tf = Typeface.createFromAsset(context.getAssets(), "fonts/Aura.otf");
            mInvisibleTextView = new TextView(context);
            mInvisibleTextView.setTextSize(size);
            mInvisibleTextView.setText("00");
            mInvisibleTextView.setGravity(Gravity.CENTER);
            mInvisibleTextView.setIncludeFontPadding(false);
            mInvisibleTextView.setTextColor(textColor);
            mInvisibleTextView.setTypeface(tf);
            if(resId == -1){
                mInvisibleTextView.setBackgroundColor(color);
            }else {
                mInvisibleTextView.setBackgroundResource(resId);
            }
            addView(mInvisibleTextView);
    
            mVisibleTextView = new TextView(context);
            mVisibleTextView.setTextSize(size);
            mVisibleTextView.setText("00");
            mVisibleTextView.setGravity(Gravity.CENTER);
            mVisibleTextView.setIncludeFontPadding(false);
            mVisibleTextView.setTextColor(textColor);
            mVisibleTextView.setTypeface(tf);
            if(resId == -1){
                mVisibleTextView.setBackgroundColor(color);
            }else {
                mVisibleTextView.setBackgroundResource(resId);
            }
    
            addView(mVisibleTextView);
    
            mShadePaint.setColor(Color.BLACK);
            mShadePaint.setStyle(Paint.Style.FILL);
            mminutenePaint.setColor(Color.WHITE);
            mminutenePaint.setStyle(Paint.Style.FILL);
        }
    
        public FlipLayout(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
    
        public static float px2dip(Context context, float pxValue){
            final float scale = context.getResources().getDisplayMetrics().density;
            return pxValue / scale +0.5f;
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            layoutWidth = MeasureSpec.getSize(widthMeasureSpec);
            layoutHeight = MeasureSpec.getSize(heightMeasureSpec);
    
            setMeasuredDimension(layoutWidth,layoutHeight);
        }
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
            int count  = getChildCount();
            for(int i=0; i 90){
                canvas.clipRect(isUp ? mTopRect : mBottomRect);
                mCamera.rotateX(isUp ? deg - 180 : -(deg - 180));
                view = mInvisibleTextView;
            }else {
                canvas.clipRect(isUp ? mBottomRect : mTopRect);
                mCamera.rotateX(isUp ? deg : -deg);
                view = mVisibleTextView ;
            }
    
            mCamera.getMatrix(mMatrix);
            positionMatrix();
            canvas.concat(mMatrix);
    
            if(view != null){
                drawChild(canvas,view,0);
            }
    
            drawFlippingShademinutene(canvas);
    
            mCamera.restore();
            canvas.restore();
        }
    
        private float getDeg() {
            return mScroller.getCurrY() * 1.0f / layoutHeight * 180;
        }
    
        /**绘制翻页时的阳面和阴面*/
        private void drawFlippingShademinutene(Canvas canvas) {
            final float degreesFlipped = getDeg();
            Log.d(TAG,"deg: " + degreesFlipped);
            if (degreesFlipped < 90) {
                final int alpha = getAlpha(degreesFlipped);
                Log.d(TAG,"小于90度时的透明度-------------------> " + alpha);
                mminutenePaint.setAlpha(alpha);
                mShadePaint.setAlpha(alpha);
                canvas.drawRect(isUp ? mBottomRect : mTopRect, isUp ? mminutenePaint : mShadePaint);
            } else {
                final int alpha = getAlpha(Math.abs(degreesFlipped - 180));
                Log.d(TAG,"大于90度时的透明度-------------> " + alpha);
                mShadePaint.setAlpha(alpha);
                mminutenePaint.setAlpha(alpha);
                canvas.drawRect(isUp ? mTopRect : mBottomRect, isUp ? mShadePaint : mminutenePaint);
            }
        }
    
        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 initCountTextView(int count) {
    
            int visibleValue = count;
            int invisibleValue = isUp ? visibleValue - 1 : visibleValue;
    
            if(invisibleValue < 0){
                invisibleValue += maxNumber;
            }
    
            if(invisibleValue >= maxNumber){
                invisibleValue -= maxNumber;
            }
            String value = String.valueOf(invisibleValue);
            if(value.length()<2){
                value = "0" +value;
            }
            mInvisibleTextView.setText(value);
        }
        /**初始化隐藏textView显示的值*/
        private void initTextView() {
    
            int visibleValue = getTime();
            int invisibleValue = isUp ? visibleValue - 1 : visibleValue;
    
            if(invisibleValue < 0){
                invisibleValue += maxNumber;
            }
    
            if(invisibleValue >= maxNumber){
                invisibleValue -= maxNumber;
            }
            String value = String.valueOf(invisibleValue);
            if(value.length()<2){
                value = "0" +value;
            }
            mInvisibleTextView.setText(value);
        }
        /**初始化隐藏textView显示的值*/
        private void initCoDownTextView(int count) {
    
            int visibleValue = count;
            String value = String.valueOf(visibleValue);
            if(value.length()<2){
                value = "0" +value;
            }
            mInvisibleTextView.setText(value);
        }
        /**根据传入的次数计算动画的时间
         * 控制翻页速度
         * */
        private int getAnimDuration(int times) {
    //        Log.e(TAG,"计算用的次数: " + times);
            if(times <= 0){
                times = 1;
            }
            int animDuration = 500 - (500-100)/9 * times;
    //        Log.e(TAG, "animDuration: " + animDuration);
            return animDuration;
        }
    
        public static interface FlipOverListener{
            /**
             * 翻页完成回调
             * @param flipLayout    当前翻页的控件
             */
            void onFLipOver(FlipLayout flipLayout);
        }
    
        //----------API-------------
        /**
         * 带动画翻动计时器
         * 需要翻动几次
         * @param value 需要翻动的次数
         * @param isMinus  方向标识 true: 往上翻 - , false: 往下翻 +
         */
        public void smoothCountFlip(int value,int maxnumber,String timeTAG, boolean isMinus,int count){
    //        Log.e(TAG,"翻动的次数: " + value);
            timetag = timeTAG;
            maxNumber = maxnumber;
            if(value <= 0){
                //回调接口
                if(null != mFlipOverListener){
                    mFlipOverListener.onFLipOver(FlipLayout.this);
                }
                return;
            }
            flipTimes = value;
            this.isUp = isMinus;
    
            initCountTextView(count);
            isFlipping = true;
            mScroller.startScroll(0,0,0,layoutHeight,getAnimDuration(flipTimes - timesCount));
            timesCount = 1;
            postInvalidate();
        }
        /**
         * 带动画翻动倒计时
         * 需要翻动几次
         * @param value 需要翻动的次数
         * @param isMinus  方向标识 true: 往上翻 - , false: 往下翻 +
         */
        public void smoothDownFlip(int value,int maxnumber,String timeTAG, boolean isMinus,int count){
    //        Log.e(TAG,"翻动的次数: " + value);
            timetag = timeTAG;
            maxNumber = maxnumber;
            if(value <= 0){
                //回调接口
                if(null != mFlipOverListener){
                    mFlipOverListener.onFLipOver(FlipLayout.this);
                }
                return;
            }
            flipTimes = value;
            this.isUp = isMinus;
    
            initCoDownTextView(count);
            isFlipping = true;
            mScroller.startScroll(0,0,0,layoutHeight,getAnimDuration(flipTimes - timesCount));
            timesCount = 1;
            postInvalidate();
        }
    
    
    
        /**
         * 带动画翻动
         * 需要翻动几次
         * @param value 需要翻动的次数
         * @param isMinus  方向标识 true: 往上翻 - , false: 往下翻 +
         */
        public void smoothFlip(int value,int maxnumber,String timeTAG, boolean isMinus){
    //        Log.e(TAG,"翻动的次数: " + value);
            timetag = timeTAG;
            maxNumber = maxnumber;
            if(value <= 0){
                //回调接口
                if(null != mFlipOverListener){
                    mFlipOverListener.onFLipOver(FlipLayout.this);
                }
                return;
            }
            flipTimes = value;
            this.isUp = isMinus;
    
            initTextView();
            isFlipping = true;
            mScroller.startScroll(0,0,0,layoutHeight,getAnimDuration(flipTimes - timesCount));
            timesCount = 1;
            postInvalidate();
        }
    
        /**
         * 不带动画翻动
         * @param value
         */
        public void flip(int value,int maxnumber,String timeTAG){
            timetag = timeTAG;
            maxNumber = maxnumber;
            String text = String.valueOf(value);
            if(text.length()<2){
                text="0"+text;
            }
            mVisibleTextView.setText(text);
    //        if(null != mFlipOverListener){
    //            mFlipOverListener.onFLipOver(FlipLayout.this,timesCount);
    //        }
        }
    
        public void addFlipOverListener(FlipOverListener flipOverListener){
            this.mFlipOverListener = flipOverListener;
        }
    
        public TextView getmVisibleTextView() {
            return mVisibleTextView;
        }
    
        public TextView getmInvisibleTextView() {
            return mInvisibleTextView;
        }
    
        public boolean isUp() {
            return isUp;
        }
    
        public int getTimesCount() {
            return timesCount;
        }
    
        /**
         *
         * @param resId 图片资源id
         */
        public void setFlipTextBackground(int resId){
            int count = getChildCount();
            for(int i=0; i 
    

    xml布局:

    
    

    用法:

    先初始化数据

    flip_1.flip(hourTime, 24, TimeTAG.hour)
    flip_2.flip(minTime, 60, TimeTAG.min)
    flip_3.flip(secondTime, 60, TimeTAG.sec)
    
    private var oldHour: Int = 0
    private var oldminute: Int = 0
    private var oldsecond: Int = 0

    计时功能

    fun doCountDown(time: Long) {
        val hour1: Int = TimeUtils.getHours(time / 1000).toInt()
        val minute1: Int = TimeUtils.getMins(time / 1000).toInt()
        val second1: Int = TimeUtils.getSeconds(time / 1000).toInt()
        val hour = oldHour - hour1
        val minute = oldminute - minute1
        val second = oldsecond - second1
        oldHour = hour1
        oldminute = minute1
        oldsecond = second1
        if (hour >= 1 || hour == -23) {
            flip_1.smoothDownFlip(1, 24, TimeTAG.hour, false, hour1)
        }
        if (minute >= 1 || minute == -59) {
            flip_2.smoothDownFlip(1, 60, TimeTAG.min, false, minute1)
        }
        if (second >= 1 || second == -59) {
            flip_3.smoothDownFlip(1, 60, TimeTAG.sec, false, second1)
        } 
    }

    字体内容可私聊

  • 相关阅读:
    性能测试常见故障和解决思路
    java.awt.HeadlessException
    苹果 AR/VR 头显售价 12000 元起,网友:“买来能干啥?”
    New的原理
    Supervised Contrastive Pre-training for Mammographic Triage Screening Model
    低代码与无代码平台的选型建议
    项目中拖拽元素,可以使用html的draggable属性,当然也可以用第三方插件interact
    【竞技宝】DOTA2-梦幻联赛S22:AR命悬一线 XG确定晋级淘汰赛
    马士兵老师JVM调优(修订版)
    MATLAB循环类型
  • 原文地址:https://blog.csdn.net/qq_41620230/article/details/126783191