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

    @Override
    public void computeScroll() {
//        Log.d(TAG,"computeScroll");
//        if(!mScroller.isFinished() && mScroller.computeScrollOffset()){
//            lastX = mScroller.getCurrX();
//            lastY = mScroller.getCurrY();
//            scrollTo(lastX,lastY);
//            postInvalidate();
//        }
    }

    @Override
    protected 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;
            }

            if(timesCount < flipTimes){
                timesCount += 1;

                initTextView();
                isFlipping = true;
                mScroller.startScroll(0,0,0,layoutHeight,getAnimDuration(flipTimes - timesCount));
                postInvalidate();
            }else {
                timesCount = 0;
                flipTimes = 0;
                if(null != mFlipOverListener && !isFlipping()){
                    mFlipOverListener.onFLipOver(FlipLayout.this);
                }
            }
        }

    }

    /**显示需要显示的数字
     * @param canvas*/
    private void showViews(Canvas canvas) {
        String current = mVisibleTextView.getText().toString();
        if(mVisibleTextView.getText().toString().length()<2){
            current = "0"+mVisibleTextView.getText().toString();
        }
        String past = mInvisibleTextView.getText().toString();
        if (mInvisibleTextView.getText().toString().length()<2){
            past = "0"+mInvisibleTextView.getText().toString();
        }

        mVisibleTextView.setText(past);
        mInvisibleTextView.setText(current);
        //防止切换抖动
        drawChild(canvas,mVisibleTextView,0);
    }

    /**画下半部分*/
    private void drawBottomHalf(Canvas canvas) {
        canvas.save();

        canvas.clipRect(mBottomRect);
        View drawView = isUp ? mInvisibleTextView : mVisibleTextView;
        drawChild(canvas,drawView,0);

        canvas.restore();
    }

    /**画上半部分*/
    private void drawTopHalf(Canvas canvas) {
        canvas.save();

        canvas.clipRect(mTopRect);
        View drawView = isUp ? 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(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<count; i++){
            View child = getChildAt(i);
            if(null != child){
                child.setBackgroundResource(resId);
            }
        }
    }

    public void setFLipTextSize(float size){
        int count = getChildCount();
        for(int i=0; i<count; i++){
            TextView child = (TextView) getChildAt(i);
            if(null != child){
                child.setTextSize(size);
            }
        }
    }

    public void setFLipTextColor(int color){
        int count = getChildCount();
        for(int i=0; i<count; i++){
            TextView child = (TextView) getChildAt(i);
            if(null != child){
                child.setTextColor(color);
            }
        }
    }


    public boolean isFlipping (){
        return isFlipping && !mScroller.isFinished() && mScroller.computeScrollOffset();
    }

    public int getCurrentValue(){
        return Integer.parseInt(mVisibleTextView.getText().toString());
    }
    //获取时间
    private int getTime(){
        Calendar now = Calendar.getInstance();
        int hour = now.get(Calendar.HOUR_OF_DAY);
        int min = now.get(Calendar.MINUTE);
        int sec = now.get(Calendar.SECOND);
        switch(timetag){
            case "SECOND":
                return sec;
            case "MINUTE":
                return min;
            case "HOUR":
                return hour;

        }
        return 0;
    }
    private int getCouDownTime(int hour,int min,int sec){
        switch(timetag){
            case "SECOND":
                return sec;
            case "MINUTE":
                return min;
            case "HOUR":
                return hour;

        }
        return 0;
    }
}

xml布局:

<com.nxwna.leartime.ui.clock.FlipLayout
    android:id="@+id/flip_1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    myFlip:flipTextColor="#ff5d6b77"
    myFlip:flipTextSize="78dp" />

用法:

先初始化数据

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

字体内容可私聊

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
Android 翻转动画可以通过以下步骤实现: 1. 创建两个布局,一个正面布局和一个背面布局。 2. 在正面布局中添加一个翻转按钮,当用户点击该按钮时触发翻转动画。 3. 在翻转动画的XML文件中定义动画属性。您需要定义旋转轴,旋转角度和动画持续时间等属性。 4. 在Java代码中,使用Animation类的loadAnimation()方法加载动画,并将其应用于正面布局。 5. 为翻转按钮添加一个点击监听器,当用户点击按钮时,使用View类的startAnimation()方法启动动画。 6. 在动画的监听器中,检查当前布局显示的是正面还是背面,然后改变布局的可见性,以显示另一个布局。 以下是一个简单的示例代码,可以让您更好地理解如何实现Android翻转动画。 ``` // 加载动画 Animation animation = AnimationUtils.loadAnimation(this, R.anim.flip_animation); // 应用动画到正面布局 View frontLayout = findViewById(R.id.front_layout); frontLayout.setAnimation(animation); // 为翻转按钮添加点击监听器 Button flipButton = findViewById(R.id.flip_button); flipButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 启动动画 frontLayout.startAnimation(animation); } }); // 监听动画的开始和结束 animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { // 检查当前布局显示的是正面还是背面 if (frontLayout.getVisibility() == View.VISIBLE) { // 如果是正面,隐藏正面显示背面 frontLayout.setVisibility(View.GONE); View backLayout = findViewById(R.id.back_layout); backLayout.setVisibility(View.VISIBLE); } else { // 如果是背面,隐藏背面显示正面 frontLayout.setVisibility(View.VISIBLE); View backLayout = findViewById(R.id.back_layout); backLayout.setVisibility(View.GONE); } } @Override public void onAnimationRepeat(Animation animation) { } }); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_41620230

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值