日落日出动画效果

      开通博客的初衷是为了督促自己记录,打开主页,惭愧啊。最近在学习的过程中,发现之前所掌握的内容又忘得一干二净。所以啊,记录真的很重。久未提笔,瞬间感觉小学的500字作文都要很困难。写作,记录脚步,锻炼思维,坚持吧!

     准备工作之余开发一款金融相关App,哈哈,刚好切合自身知识和爱好。如果你打开手机里金融类应用,会发现它们都有一个特点,就是很多图、线条,很直观的向用户展示指数、涨跌等信息。所以,这篇文章就通过自定义“日落日出动画”效果复习一下自定义View的知识点,let go!

思路:

  • 绘制日落时间到日出时间的圆弧
  • 通过当前时间与总时间的比,计算出需要动态画弧的角度
  • 通过属性动画获取当前角度,并通过角度计算出当前点的坐标
  • 实时绘制
效果图:
               
ok,直接上代码了!
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="SunAnimationView">
        <attr name="circle_color" format="color"></attr>
        <attr name="font_color" format="color"></attr>
        <attr name="font_size" format="dimension"></attr>
        <attr name="circle_radius" format="integer"></attr>
        <attr name="current_color" format="color"></attr>
    </declare-styleable>
</resources>

布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.sunanimation.MainActivity">

    <LinearLayout
        android:gravity="center"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <EditText
            android:id="@+id/time_et"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:hint="Set time here"/>

        <Button
            android:id="@+id/set_bt"
            android:layout_marginLeft="20dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Begin" />
    </LinearLayout>

    <com.example.sunanimation.SunView
        android:id="@+id/sun"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:circle_color = "#00BFFF"
        app:font_color = "#00BFFF"
        app:font_size = "20sp"
        app:circle_radius = "400"
        app:current_color = "#F5DEB3"/>
</LinearLayout>

MainActivity

package com.example.sunanimation;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private EditText mET;
    private Button mBegin;
    private SunView mSunView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mET = (EditText) findViewById(R.id.time_et);
        mBegin = (Button) findViewById(R.id.set_bt);
        mSunView = (SunView) findViewById(R.id.sun);
        mBegin.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.set_bt:
                String time = String.valueOf(mET.getText());
                mSunView.setTime(time);
                break;
        }
    }
}

自定义SunView

package com.example.sunanimation;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;

/**
 * Created by 阿正 on 2017/9/14 0014.
 */

public class SunView extends View {
    private int mCircleColor;
    private int mFontColor;
    private int mFontSize;
    private int mCricleRadius;
    private int mCurrentCricleColor;

    private Paint mPaint;
    private RectF mRectF;
    private WindowManager wm;
    private int mWidth;
    private int mTop;

    private float mCurrentTime;//当前时间
    private float mAngle;
    private final static String START_TIME = "06:00";//日出时间
    private final static String END_TIME = "20:00";//日落时间
    private final static String  TAG = "SunView";

    private Bitmap mBitmap;
    private float mPositionX;
    private float mPositionY;
    private final static float mIconRadius = 20;

    public SunView(Context context) {
        this(context,null);
    }

    public SunView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public SunView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        intView(context, attrs);
    }

    public void setTime(String time){
        mCurrentTime = transTime(time);
        int start = transTime(START_TIME);
        int end = transTime(END_TIME);
        mAngle = (mCurrentTime - start)/ (end - start) * 180;
        Log.d(TAG,"mCurrentTime:" + mCurrentTime + " start:" + start + " end:" + end + " mAngle:" + mAngle);
        startAnimation(0,mAngle,2000);
    }

    private void startAnimation(float startAngle, float currentAngle, int duration) {
        ValueAnimator sunAnimator = ValueAnimator.ofFloat(startAngle, currentAngle);
        sunAnimator.setDuration(duration);
        sunAnimator.setTarget(currentAngle);
        sunAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
        {
            @Override
            public void onAnimationUpdate(ValueAnimator animation)
            {
                //每次要绘制的圆弧角度
                mAngle = (float) animation.getAnimatedValue();
                invalidateView();
            }

        });
        sunAnimator.start();
    }

    private void invalidateView() {
        mPositionX = mWidth / 2 - (float) (mCricleRadius * Math.cos(mAngle * Math.PI / 180)) - mIconRadius;
        mPositionY =  mTop + mCricleRadius - (float) (mCricleRadius * Math.sin(mAngle * Math.PI / 180) + 15);
        Log.d(TAG,"mPositionX:" + mPositionX + " mPositionY" + mPositionY);
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        //画圆
        drawCricle(canvas);
        canvas.save();
        //画文字
        drawText(canvas);
        //画太阳
        drawSun(canvas);
        //画太阳走过的圆弧
        drawOld(canvas);

        super.onDraw(canvas);
    }

    private void drawOld(Canvas canvas) {
        mPaint.setColor(mCurrentCricleColor);
        canvas.drawArc(mRectF,180,mAngle,false,mPaint);
    }

    private void drawSun(Canvas canvas) {
        canvas.drawBitmap(mBitmap,mPositionX,mPositionY,mPaint);
    }

    private void drawText(Canvas canvas) {
        mPaint.setColor(mFontColor);
        mPaint.setTextSize(mFontSize);
        canvas.drawText(START_TIME,mWidth/2 - mCricleRadius,mTop + mCricleRadius + 50,mPaint);
        canvas.drawText(END_TIME,mWidth/2 + mCricleRadius - 150,mTop + mCricleRadius + 50,mPaint);
    }

    private void drawCricle(Canvas canvas) {
        mRectF = new RectF(mWidth/2 - mCricleRadius, mTop, mWidth/2 + mCricleRadius, 2*mCricleRadius + mTop);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setDither(true); //防抖动
        mPaint.setColor(mCircleColor);
        canvas.drawArc(mRectF,180,180,true,mPaint);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, mWidth/2 - mCricleRadius, mTop, mWidth/2 + mCricleRadius, 2*mCricleRadius + mTop);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        mWidth = wm.getDefaultDisplay().getWidth();
        mTop = wm.getDefaultDisplay().getHeight() / 6;
        mPositionX = mWidth/2 - mCricleRadius - mIconRadius;
        mPositionY = mCricleRadius + mTop - mIconRadius;
    }

    private void intView(Context context, AttributeSet attrs) {
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SunAnimationView);
        mCircleColor = array.getColor(R.styleable.SunAnimationView_circle_color,
                getContext().getResources().getColor(R.color.blue));
        mCurrentCricleColor = array.getColor(R.styleable.SunAnimationView_current_color,
                getContext().getResources().getColor(R.color.red));
        mCricleRadius = array.getInteger(R.styleable.SunAnimationView_circle_radius,
                200);
        mFontSize = (int) array.getDimension(R.styleable.SunAnimationView_font_size,20);
        mFontColor = array.getColor(R.styleable.SunAnimationView_font_color,
                getContext().getResources().getColor(R.color.red));
        array.recycle();

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        //压缩图片
        BitmapFactory.Options newOpts =  new  BitmapFactory.Options();
        newOpts.inSampleSize = 3;
        mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.sun,newOpts);
    }

    //将时间转换为分钟
    private int transTime(String time){
        int value = 0;
        if (time == null){
            return value;
        }
        String[] s = time.split(":");
        int hour = Integer.parseInt(s[0]);
        int minute = Integer.parseInt(s[1]);
        value = hour * 60 + minute;
        return value;
    }
}

          以上就是代码实现了。需要说明的是,代码很多地方都可以在优化,比如可以动态设置日落日出时间,对输入时间格式进行错误判断等。由于主要是为了实现效果,这里就偷个懒了。
       另外,参考了 http://blog.csdn.net/zoujian1990520/article/details/77862495 ,感谢!

猜你喜欢

转载自blog.csdn.net/Mr_azheng/article/details/78142246