wpf 模擬抖音很火的羅盤時鐘,附源碼,下載就能跑

wpf 模擬抖音很火的羅盤時鐘,附源碼前端

  前端時間忽然發現,抖音火了個壁紙,就是黑底蕾絲~~~  錯錯錯,黑底白字的羅盤時鐘程序員

  做爲程序員的我,也以爲很新穎,因此想空了研究下,這不,空下來了就用wpf,寫個屬於.net本身的羅盤時鐘,目前只實現了時分秒,農曆日期等邏輯都是同樣的,因此就略了,有興趣的朋友,能夠繼續深刻!express

  最開始想直接弄成成exe,方便拷貝,處處運行使用的,可是考慮到,萬一有網友朋友們須要,因此我仍是把封成一個dll,須要的地方添加引用便可!canvas

  爲了弄這個,還惡補了下,高中仍是初中的知識,sin30,cos60,呵呵,正弦餘弦,因此不明白的朋友們須要先了解清楚這個,由於羅盤是旋轉,須要用到計算這個值!後端

  不廢話了,先上圖看下效果!緩存

 

 

 

  

   ok,總體效果就是這樣了,中間是鄙人的名稱縮寫,抖音上是很潦草的,我就隨便啦,佔個位置,否則顯得很空洞!動畫

  下面說說代碼this

 

 

  主要是,RomeClockControlLibrary,這個是對控件的封裝,上面那個啓動程序只是一個容器,或者說是調用者,固然,若是要達到我這個效果,實現圓形的窗口透明的朋友們,能夠看下借鑑!spa

 

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

  

  上面是前端代碼,有點基礎的都應該看得懂,沒什麼可說的.net

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!

  整個流程就是這樣,有疑問的朋友,歡迎留言!

 

下載地址,附源碼 ==》 點擊我前往

 

支持原創,轉載請標明出處,謝謝!

相關文章
相關標籤/搜索