业余时间写的一个知乎日报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版:
Mobile版:
磁贴:
引用的一系列的库:
阴影: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也可以用。
4. Popup Message
Win10里Toast是把消息发到消息中心,对应用内部提示不是很友好,这里我用Popup模拟了一下android的toast。
思路是生成一个包含TextBlock的Popup,把要弹出的消息push到一个queue里,按顺序弹出消息,遇到相同的就跳过。
具体实现代码这里就不贴了,可以参考PopupMessage.cs
其他引用的库如阴影,按钮,列表等就放到后面再写。