Android自定义动态天气卡片


一个卡片控件,输入不同天气类型,显示不同场景。
一图胜千言,先看图吧
在这里插入图片描述

实现效果

因为此控件是根据需求实现的,所以一共实现了6种场景

  1. 白天 && 晴天,显示时有个太阳升起动画;
  2. 白天 && 下雨,白天场景动态下雨;
  3. 白天 && 下雪,白天场景动态下雪;
  4. 夜晚 && 晴天,夜晚场景,随机时间、位置产生流星;
  5. 夜晚 && 下雨,夜晚场景动态下雨;
  6. 夜晚 && 下雪,夜晚场景动态下雪;

拆分动态场景

1.太阳升起,可拆分为X轴和Y轴的变化。
2.流星,可用Random随机生成流星位置。
3.下雨,关键在于控制雨滴的个数,保证屏幕上雨滴总数变化不大,间隔时间内生成的雨滴总数要大致相同
4.下雪,比下雨多了一个参数,就是雪花的大小,在生成雪花位置之后用随机函数生成大小即可

代码实现

1.太阳升起。核心代码

float sun= 0;//太阳位置
float sunSize=0;//太阳Bitmap的大小(边长)//可在设置数据时初始化
	/**太阳升起动画*/
private void startSunAnimation(){
      ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(this,"sun",0,1);
      objectAnimator.setInterpolator(new DecelerateInterpolator());//减速插值器
      objectAnimator.setDuration(2500);//动画执行时间
      objectAnimator.start();
 }
 /**绘制太阳位置*/
 private void drawSun(Canvas canvas) {
       float half = sunSize / 2;//太阳图片的一半长度
       float lastheight = measuredHeight - half;//总高度减去图片一半,即太阳中心最终所在的位置
       //左边距
       float left = sunX + sunPath * sun;//sunX太阳初始位置,这里是控件长度的1/3,sunPath太阳起点到终点的总长度
       //顶部边距
       float top = lastheight * (1-sun);
       //计算绘制太阳的矩形
       RectF rectF = new RectF(left, top,left+sunSize, top +sunSize);
       //在计算和的矩形绘制太阳
       canvas.drawBitmap(taiyangBitmap,null,rectF,paint);
 }
 
public void setSun(float sun) {
        this.sun = sun;
        invalidate();
}

上面只列出核心代码,完整代码会传到GitHub

2.流星,核心代码

    //启动流星
     private void startMyAnimatio(){
            animator = ObjectAnimator.ofInt(this,"lx",0,DensityUtils.dipTopx(getContext(),65)+55);
            animator.setDuration(1500);
            animator.setInterpolator(new LinearInterpolator());
            animator.setRepeatCount(ValueAnimator.INFINITE);
            animator.setStartDelay(2000);
            animator.start();
    }
    /**流星动画设置函数,暂定同时只能存在一个流星*/
    public void setLx(int lx) {
        this.lx = lx;
        if(liuxingList.size()==0 || lx>measuredHeight+51){
            liuxingList.clear();
            if(getRandomPoint()>0.98f){//概率模拟不定时产生流星
                liuxingList.add(new WeatherBean(getRandomX()));
            }
        }else {
            invalidate();
        }

    }
	//绘制流星
    private void drawLX(Canvas canvas) {
        if(lxBitmap!=null){
           for(int i=0;i<liuxingList.size();i++){
               WeatherBean weatherBean = liuxingList.get(i);
               Rect rect = new Rect(weatherBean.x-lx-48,lx-55,weatherBean.x-lx,lx);//48是图片长度,55是图片高度,这里图省事就写死了
               canvas.drawBitmap(lxBitmap,null,rect,paint);
          }
       }
    }

3.下雨

List<WeatherBean> pointList ;
    private void startMyAnimation() {
            animator = ObjectAnimator.ofInt(this,"dd",0,450);
            animator.setDuration(5000);
            animator.setInterpolator(new LinearInterpolator());
            animator.setRepeatCount(ValueAnimator.INFINITE);
            animator.start();
    }
    public void setDd(int dd) {
        this.dd = dd;
        addAble = (dd%5==0);
        int size=0;
        //每次重新设置DD值 叠加spex的值,达到50移除
        //
        while (size<pointList.size()){
            WeatherBean weatherBean = pointList.get(size);
            weatherBean.spex+=interval;
            if( weatherBean.spex>=50 ){
                pointList.remove(size);
            }else {
                size++;
            }
        }
        invalidate();
    }
    private void initPoint(){
        //循环,给所有spex加1
        //移除大于500的
        if(addAble){
            //循环,给pointList补满30个
            int k = 30 - pointList.size();
            for(int i=0;(i<k && i<3);i++){//每次最多添加3个点
                WeatherBean wb = new WeatherBean();
                wb.x = (int) (getRandomPoint()*measuredWidth);
                pointList.add(wb);
            }
        }
    }
     @Override
    public void draw(Canvas canvas) {
        initPoint();
        //drawBg(canvas);
        //drawPre(canvas);
        drawRain(canvas);
	}
    /**
     * 绘制下雨
     * @param canvas
     */
    private void drawRain(Canvas canvas) {
        for(int i=0;i<pointList.size();i++){
            WeatherBean weatherBean = pointList.get(i);

            float startY = spe*weatherBean.spex;
            float startX = weatherBean.x-startY*0.364f;
            //经三角函数计算得出
            canvas.drawLine(startX,startY,startX-longX,startY+longY,paintLine);
        }
    }
    /**每一个点的实体类*/
    private class WeatherBean{
        int x=0;//X坐标
        float spex=  -longY;//下落速度
        int size;//大小(雪花)
        public WeatherBean() { }
        public WeatherBean(int x) {
            this.x = x;
        }
    }

4.下雪,核心代码

List<WeatherBean> pointList ;

 private void startMyAnimation() {
            animator = ObjectAnimator.ofInt(this,"dd",0,450);
            animator.setDuration(5000);
            animator.setInterpolator(new LinearInterpolator());
            animator.setRepeatCount(ValueAnimator.INFINITE);
            animator.start();
    }
    public void setDd(int dd) {
        this.dd = dd;
        addAble = (dd%5==0);
        int size=0;
        //每次重新设置DD值 叠加spex的值,达到50移除
        //
        while (size<pointList.size()){
            WeatherBean weatherBean = pointList.get(size);
            weatherBean.spex+=interval;
            if( weatherBean.spex>=50 ){
                pointList.remove(size);
            }else {
                size++;
            }
        }
        invalidate();
    }
 @Override
    public void draw(Canvas canvas) {
		initSnowPoint();
        //drawBg(canvas);
        drawSnow(canvas);
	}
    private void initSnowPoint(){
        //循环,给所有spex加1
        //移除大于500的
        if(addAble){
            //循环,给pointList补满30个
            int k = 30 - pointList.size();
            for(int i=0;(i<k && i<1);i++){
                WeatherBean wb = new WeatherBean();
                wb.x = (int) (getRandomPoint()*measuredWidth);
                wb.size = getRandomSize();
                pointList.add(wb);
            }
        }
    }    
        /**
     * 绘制下xue
     * @param canvas
     */
    private void drawSnow(Canvas canvas) {
        for(int i=0;i<pointList.size();i++){
            WeatherBean weatherBean = pointList.get(i);

            float startY = spe*weatherBean.spex;
            float startX = weatherBean.x-startY*0.264f;
            RectF rectF = new RectF(startX,startY,startX+weatherBean.size,startY+weatherBean.size);
            canvas.drawBitmap(snowBitmap,null,rectF,paint);
        }
    }   
        /**每一个点的实体类*/
    private class WeatherBean{
        int x=0;//X坐标
        float spex=  -longY;//下落速度
        int size;//大小(雪花)
        public WeatherBean() { }
        public WeatherBean(int x) {
            this.x = x;
        }
    }

总结

	自己写得控件要及时记录思路,不然过几个月来炒冷饭自己看的都蒙蔽,控件上传后会来更新

项目地址

https://github.com/YsInHZ/WeatherCard

  • 9
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值