欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

wpf 模拟抖音很火的罗盘时钟,附源码,下载就能跑

程序员文章站 2023-10-17 09:20:30
wpf 模拟抖音很火的罗盘时钟,附源码 前端时间突然发现,抖音火了个壁纸,就是黑底蕾丝~~~ 错错错,黑底白字的罗盘时钟! 作为程序员的我,也觉得很新颖,所以想空了研究下,这不,空下来了就用wpf,写个属于.net自己的罗盘时钟,目前只实现了时分秒,农历日期等逻辑都是一样的,所以就略了,有兴趣的朋友 ......

wpf 模拟抖音很火的罗盘时钟,附源码

  前端时间突然发现,抖音火了个壁纸,就是黑底蕾丝~~~  错错错,黑底白字的罗盘时钟

  作为程序员的我,也觉得很新颖,所以想空了研究下,这不,空下来了就用wpf,写个属于.net自己的罗盘时钟,目前只实现了时分秒,农历日期等逻辑都是一样的,所以就略了,有兴趣的朋友,可以继续深入!

  最开始想直接弄成成exe,方便拷贝,到处运行使用的,但是考虑到,万一有网友朋友们需要,所以我还是把封成一个dll,需要的地方添加引用即可!

  为了弄这个,还恶补了下,高中还是初中的知识,sin30,cos60,呵呵,正弦余弦,所以不明白的朋友们需要先了解清楚这个,因为罗盘是旋转,需要用到计算这个值!

  不废话了,先上图看下效果!

 

wpf 模拟抖音很火的罗盘时钟,附源码,下载就能跑

 

 

wpf 模拟抖音很火的罗盘时钟,附源码,下载就能跑

  

   ok,整体效果就是这样了,中间是鄙人的名称缩写,抖音上是很潦草的,我就随便啦,占个位置,不然显得很空洞!

  下面说说代码

 

wpf 模拟抖音很火的罗盘时钟,附源码,下载就能跑

 

  主要是,romeclockcontrollibrary,这个是对控件的封装,上面那个启动程序只是一个容器,或者说是调用者,当然,如果要达到我这个效果,实现圆形的窗口透明的朋友们,可以看下借鉴!

 

<usercontrol x:class="romeclockcontrollibrary.romeclockcontrol"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:romeclockcontrollibrary"
             mc:ignorable="d" 
             d:designheight="450" 
             d:designwidth="800"
             >
    <border x:name="bor"
            background="#000000"
            >
        <grid x:name="grid" >
        </grid>
    </border>
</usercontrol>

  

  上面是前端代码,有点基础的都应该看得懂,没什么可说的

using system;
using system.collections.generic;
using system.diagnostics;
using system.linq;
using system.text;
using system.threading;
using system.threading.tasks;
using system.windows;
using system.windows.controls;
using system.windows.data;
using system.windows.documents;
using system.windows.input;
using system.windows.media;
using system.windows.media.animation;
using system.windows.media.imaging;
using system.windows.navigation;
using system.windows.shapes;

namespace romeclockcontrollibrary
{
    /// <summary>
    /// 罗马时钟
    /// </summary>
    public partial class romeclockcontrol : usercontrol, idisposable
    {
        public romeclockcontrol()
        {
            initializecomponent();
        }

        /// <summary>
        /// x轴的中心位置
        /// </summary>
        private double centerpixtox => this.actualwidth / 2;

        /// <summary>
        /// y轴的中心位置
        /// </summary>
        private double centerpixtoy => this.actualheight / 2;

        /// <summary>
        /// 秒
        /// </summary>
        private canvas canvashour = null;

        /// <summary>
        /// 分
        /// </summary>
        private canvas canvasminute = null;

        /// <summary>
        /// 时
        /// </summary>
        private canvas canvassecond = null;

        /// <summary>
        /// ui更新线程
        /// </summary>
        private thread thread = null;

        /// <summary>
        /// 缓存时的显示控件
        /// </summary>
        private textblock blockhour = null;

        /// <summary>
        /// 缓存分的显示控件
        /// </summary>
        private textblock blockminute = null;

        /// <summary>
        /// 缓存秒的显示控件
        /// </summary>
        private textblock blocksecond = null;

        /// <summary>
        /// 添加控件
        /// </summary>
        private void add(addtype type)
        {
            var offset = 0;//偏移量
            var count = 0;//总量
            var str = string.empty;
            var time = 0;
            double angletime = 0;
            canvas canvas = new canvas();
            canvas.tag = type;

            switch (type)
            {
                case addtype.hour:
                    offset = 95;
                    count = 24;
                    str = "时";
                    canvashour = canvas;
                    time = datetime.now.hour;
                    break;
                case addtype.minute:
                    offset = 60;
                    count = 60;
                    str = "分";
                    canvasminute = canvas;
                    time = datetime.now.minute;
                    break;
                case addtype.second:
                    offset = 30;
                    count = 60;
                    str = "秒";
                    canvassecond = canvas;
                    time = datetime.now.second;
                    break;
                default:
                    return;
            }

            var angle = 360 / count;//角度
            var x = centerpixtox - offset;//起始位置
            var y = centerpixtoy - offset;

            for (int i = 0; i < count; i++)
            {
                textblock t = new textblock();
                if (i <= 9)
                {
                    t.text = $"0{i}{str}";
                }
                else
                {
                    t.text = $"{i}{str}";
                }
                t.tag = i;
                t.foreground = new solidcolorbrush((color)colorconverter.convertfromstring("#7d7d7d"));
                canvas.children.add(t);

                var sinv = math.sin((90 - angle * i) * (math.pi / 180));
                var cosv = math.cos((90 - angle * i) * (math.pi / 180));
                var a = centerpixtoy - y * sinv;
                var b = centerpixtox + y * cosv;
                canvas.setleft(t, b);
                canvas.settop(t, a);

                //设置角度
                rotatetransform r = new rotatetransform();
                r.angle = angle * i - 90;
                t.rendertransform = r;

                if (i == time)
                {
                    angletime = 360 - r.angle;
                    //更新样式
                    t.foreground = new solidcolorbrush(colors.white);
                    switch (type)
                    {
                        case addtype.hour:
                            blockhour = t;
                            break;
                        case addtype.minute:
                            blockminute = t;
                            break;
                        case addtype.second:
                            blocksecond = t;
                            break;
                    }
                }
            }
            grid.children.add(canvas);

            //获取当前时间,旋转对应的角度
            rotatetransform rtf = new rotatetransform();
            rtf.centerx = centerpixtox;
            rtf.centery = centerpixtoy;
            rtf.angle = angletime;
            canvas.rendertransform = rtf;
        }

        /// <summary>
        /// 渲染时钟
        /// </summary>
        public void show()
        {
            dispose();
            //设置圆角
            bor.cornerradius = new cornerradius(this.actualwidth / 2);

            add(addtype.hour);
            add(addtype.minute);
            add(addtype.second);

            addname();

            thread = new thread(new threadstart(threadmethod));
            thread.isbackground = true;
            thread.start();
        }

        /// <summary>
        /// 生成名称
        /// </summary>
        private void addname()
        {
            textblock tb = new textblock();
            tb.text = "xl";
            tb.foreground = new solidcolorbrush(colors.white);
            tb.fontsize = 60;
            tb.fontfamily = new fontfamily("华文琥珀");
            tb.horizontalalignment = horizontalalignment.center;
            tb.verticalalignment = verticalalignment.center;
            grid.children.add(tb);
        }

        /// <summary>
        /// ui更新线程
        /// </summary>
        private void threadmethod()
        {
            while (true)
            {
                dispatcher.invoke(() =>
                {
                    var s = datetime.now.second;
                    var m = datetime.now.minute;
                    var h = datetime.now.hour;

                    //处理时
                    if (m == 0 && (int)blockhour.tag != h)
                    {
                        setui(canvashour, h);
                    }
                    //处理分
                    if (s == 0 && (int)blockminute.tag != m)
                    {
                        setui(canvasminute, m);
                    }
                    //处理秒
                    setui(canvassecond, s);
                });
                thread.sleep(1000);
            }
        }

        /// <summary>
        /// 更新ui
        /// </summary>
        /// <param name="can"></param>
        /// <param name="tag"></param>
        /// <param name="color"></param>
        private void setui(canvas can, int tag)
        {
            var type = (addtype)can.tag;
            foreach (textblock item in can.children)
            {
                if ((int)item.tag == tag)
                {
                    debug.writeline(item.text);

                    var fr = item.rendertransform as rotatetransform;
                    var angle = 360 - fr.angle;
                    var rtf = can.rendertransform as rotatetransform;
                    doubleanimation db = null;
                    if (type == addtype.minute)
                    {
                        angle -= 360;
                        db = new doubleanimation(angle, new duration(timespan.fromseconds(1)));
                        db.completed += dbminute_completed;
                        blockminute = item;
                    }
                    else if (type == addtype.hour)
                    {
                        angle += 360;
                        db = new doubleanimation(angle, new duration(timespan.fromseconds(1.5)));
                        db.completed += dbhour_completed;
                        blockhour = item;
                    }
                    else
                    {
                        db = new doubleanimation(angle, new duration(timespan.fromseconds(0.25)));
                        db.completed += dbsecond_completed;
                        blocksecond = item;
                    }
                    rtf.beginanimation(rotatetransform.angleproperty, db);

                }
                else
                {
                    item.foreground = new solidcolorbrush((color)colorconverter.convertfromstring("#7d7d7d"));
                }
            }
        }

        /// <summary>
        /// 秒 动画完成时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dbsecond_completed(object sender, eventargs e)
        {
            blocksecond.foreground = new solidcolorbrush(colors.white);
        }

        /// <summary>
        /// 时 动画完成时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dbhour_completed(object sender, eventargs e)
        {
            var fr = canvashour.rendertransform as rotatetransform;
            var angle = fr.angle - 360;
            fr = null;
            rotatetransform rtf = new rotatetransform();
            rtf.centerx = centerpixtox;
            rtf.centery = centerpixtoy;
            rtf.angle = angle;
            canvashour.rendertransform = rtf;
            debug.writeline(rtf.angle);
            blockhour.foreground = new solidcolorbrush(colors.white);
        }

        /// <summary>
        /// 分 动画完成时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dbminute_completed(object sender, eventargs e)
        {
            var fr = canvasminute.rendertransform as rotatetransform;
            var angle = fr.angle + 360;
            fr = null;
            rotatetransform rtf = new rotatetransform();
            rtf.centerx = centerpixtox;
            rtf.centery = centerpixtoy;
            rtf.angle = angle;
            canvasminute.rendertransform = rtf;
            debug.writeline(rtf.angle);
            blockminute.foreground = new solidcolorbrush(colors.white);
        }

        /// <summary>
        /// 释放
        /// </summary>
        public void dispose()
        {
            thread?.abort();
            grid.children.clear();
        }
    }

    /// <summary>
    /// 添加类型
    /// </summary>
    public enum addtype
    {
        hour,
        minute,
        second
    }
}

  

  上面是后端逻辑,这才是重点,调用者通过show,调用显示的;在show里面会开启一个后台处理线程,来实现获取当前时间,并计算需要旋转的角度,最后采用动画更新到ui!

  整个流程就是这样,有疑问的朋友,欢迎留言!

 

下载地址,附源码 ==》 

 

支持原创,转载请标明出处,谢谢!