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

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

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

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

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

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

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

   

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

  下面说说代码

 

 

  主要是,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!

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

 

下载地址,附源码 ==》 点击我前往

 

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

 

 

  

posted @ 2019-05-10 18:22  吃奶嘴的路飞  阅读(6466)  评论(1编辑  收藏  举报