天天看點

【開源】 天天讀報 - 知乎日報win10版1.文章顯示2.布局3. 微網誌登入4. Popup Message

業餘時間寫的一個知乎日報win10版用戶端,支援收藏,評論,點贊等。

商店位址:https://www.microsoft.com/zh-cn/store/apps/%E5%A4%A9%E5%A4%A9%E8%AF%BB%E6%8A%A5/9nblggh5fx8z。

開源位址:https://github.com/brookshi/UWP_ZhiHuRiBao 歡迎fork/star。

先上圖:

PC版:

【開源】 天天讀報 - 知乎日報win10版1.文章顯示2.布局3. 微網誌登入4. Popup Message

Mobile版:

【開源】 天天讀報 - 知乎日報win10版1.文章顯示2.布局3. 微網誌登入4. Popup Message

磁貼:

【開源】 天天讀報 - 知乎日報win10版1.文章顯示2.布局3. 微網誌登入4. Popup Message

引用的一系列的庫:

陰影:https://github.com/brookshi/XPShadow

網絡:https://github.com/brookshi/XPHttp

清單:https://github.com/brookshi/LLMListView

内部通信:https://github.com/brookshi/LLQNotifier

按鈕:https://github.com/brookshi/XPButton

動畫:https://github.com/brookshi/LLMAnimator

新浪微網誌登入:http://weibowinrtsdk.codeplex.com/

API是通過用Fiddler抓取Android版知乎日報獲得。

這個應用比較有意思的點:

1.文章顯示

文章api擷取的是一串html,自然想到用webview來顯示,不過打開一個文章就用一個webview,占用記憶體比較大。為解決這個問題,開始嘗試将html轉成xaml,用RichTextBox顯示。用的是: https://github.com/stimulant/SocialStream/blob/master/XAMLConverter/HtmlToXamlConverter.cs

可惜不能支援所有html節點,而且image顯示很慢,字型顯示怪異,效果不佳,放棄。

回到webview,既然是多個webview造成記憶體大,那隻用一個webview不就可以了! 嗯,單例模式。

每次打開文章時把這個靜态的webview單例從Parent中移除,再加到目前Page中。

public static class WebViewUtil
    {
        static WebViewUtil()
        {
            _webViewInstance.ScriptNotify += async (s, e) =>
            {
                string data = e.Value;
                if (!string.IsNullOrEmpty(data) && data.StartsWith(Html.NotifyPrex))
                {
                    await Launcher.LaunchUriAsync(new Uri(data.Substring(Html.NotifyPrex.Length)));
                }
            };
        }

        private readonly static object _parentLocker = new object();

        private readonly static List<Panel> _webViewParents = new List<Panel>();

        private readonly static WebView _webViewInstance = new WebView();

        public static void AddWebViewWithBinding(Panel parent, object source, string path)
        {
            Clear();
            RemoveParent();
            _webViewInstance.SetBinding(WebViewExtend.ContentProperty, new Binding() { Source = source, Path = new PropertyPath(path) });
            lock(_parentLocker)
            {
                parent.Children.Add(_webViewInstance);
                if (!_webViewParents.Contains(parent))
                {
                    _webViewParents.Add(parent);
                }
            }
        }

        public static void Clear()
        {
            _webViewInstance.NavigateToString("");
        }

        public static bool IsParent(Panel panel)
        {
            return panel.Children.Contains(_webViewInstance);
        }

        public static bool HasParent { get { return _webViewInstance.Parent is Panel; } }

        public static void RemoveParent()
        {
            lock(_parentLocker)
            {
                _webViewParents.ForEach(panel =>
                {
                    if (panel.Children.Contains(_webViewInstance))
                        panel.Children.Remove(_webViewInstance);
                });
            }
        }
    }
           

2.布局

WinRT支援根據一些條件來顯示不同的布局,最常用的就是AdaptiveTrigger,通過設定MinWindowWidth/MinWindowHeight來顯示/隐藏元素來展示不同的布局。

<VisualState>
                    <VisualState.StateTriggers>
                        <AdaptiveTrigger MinWindowWidth="{Binding Source={StaticResource Config}, Path=MinWidth_UIStatus_ListAndContent}" />
                    </VisualState.StateTriggers>
                    <VisualState.Setters>
                        <Setter Target="StoryContentView.IsPaneOpen" Value="false" />
                        <Setter Target="StoryContentView.DisplayMode" Value="Overlay" />
                    </VisualState.Setters>
                </VisualState>
           

但是有時候條件不單單是Width/Height,還需要其他條件來決定布局,這時可以模仿AdaptiveTrigger建立一個我們自己的StateTrigger。自定義的trigger需要繼承StateTriggerBase,加入其他條件ExtraCondition,通過SizeChanged的事件來觸發Trigger。

public class AdaptiveTriggerExtended : StateTriggerBase
    {
        public double MinWindowWidth
        {
            get { return (double)GetValue(MinWindowWidthProperty); }
            set { SetValue(MinWindowWidthProperty, value); }
        }
        public static readonly DependencyProperty MinWindowWidthProperty =
            DependencyProperty.Register("MinWindowWidth", typeof(double), typeof(AdaptiveTriggerExtended), new PropertyMetadata(0));

        public bool ExtraCondition
        {
            get { return (bool)GetValue(ExtraConditionProperty); }
            set { SetValue(ExtraConditionProperty, value); }
        }
        public static readonly DependencyProperty ExtraConditionProperty =
            DependencyProperty.Register("ExtraCondition", typeof(bool), typeof(AdaptiveTriggerExtended), new PropertyMetadata(true));

        private FrameworkElement _targetElement;
        public FrameworkElement TargetElement
        {
            get { return _targetElement; }
            set
            {
                _targetElement = value;
                _targetElement.SizeChanged += (s, e) => SetActive(ExtraCondition && e.NewSize.Width >= MinWindowWidth);
            }
        }
    }
           

3. 微網誌登入

官方知乎日報登入肯定有自己的AppID和AppSecret,這個不太好找(其實也能找到,把android版日報反編譯,細心點就可以找到),不過發現用我自己從微網誌申請的也可以用。

官方推薦的win8 SDK,在win10也可以用。

【開源】 天天讀報 - 知乎日報win10版1.文章顯示2.布局3. 微網誌登入4. Popup Message

4. Popup Message

Win10裡Toast是把消息發到消息中心,對應用内部提示不是很友好,這裡我用Popup模拟了一下android的toast。

【開源】 天天讀報 - 知乎日報win10版1.文章顯示2.布局3. 微網誌登入4. Popup Message

思路是生成一個包含TextBlock的Popup,把要彈出的消息push到一個queue裡,按順序彈出消息,遇到相同的就跳過。

具體實作代碼這裡就不貼了,可以參考PopupMessage.cs

其他引用的庫如陰影,按鈕,清單等就放到後面再寫。

繼續閱讀