[开源,学习,分享]UWP第三方简书客户端分享

简介

Windows10正式版发布到现在,我利用零零碎碎的一些时间对UWP进行一些学习,也基于这门技术开发了一个第三方的简书App.

基本界面

优酷视频:

http://v.youku.com/v_show/id_XMTM2MjU4MjI4NA==.html

基本功能

  • 客户端采用了UWP的技术,所以支持x86,x64,ARM平台,采用了响应式的布局.对手机进行了部分的优化.
  • 对SQLite和本地存储进行了封装,支持缓存.

缓存支持同步和异步的两种方式,分别实现了两个接口:

internal interface IStorage
{
    void AddItem(string key, object value);
    void UpdateItem(string key, object value);
    bool ContainItem(string key);
    void FlushAll();
    T GetItem<T>(string key) where T : class;
    List<T> GetItems<T>(string key) where T : class;
    bool RemoveItem(string key);
    long GetSize();
}
interface IStorageAsync
{
    Task AddItemAsync(string key, object value);
    Task UpdateItemAsync(string key, object value);
    Task<bool> ContainItemAsync(string key);
    Task FlushAllAsync();
    Task<T> GetItemAsync<T>(string key) where T : class;
    Task<List<T>> GetItemsAsync<T>(string key) where T : class;
    Task<bool> RemoveItemAsync(string key);
    long GetSize();
}

通过Key和Value的方式实现增减删改.

  • 简单的封装了新浪微博的分享图片和文字的功能,可以在Config.cs文件中加入你自己的key和secret.
public async Task<WeiboResult> ShareTextAsync(string text)
{
    if (text == null)
    {
        throw new ArgumentNullException(nameof(text));
    }

    if (string.IsNullOrWhiteSpace(text))
    {
        throw new ArgumentException("Text could not be empty", nameof(text));
    }

    if (!UserInfo.CheckUseable())
    {
        string authorizeCode = await this.GetAuthorizeCodeAsync();
        await this.Authorize(authorizeCode);
    }

    Uri uri = new Uri("https://api.weibo.com/2/statuses/update.json");

    Dictionary<string, string> pairs = new Dictionary<string, string>();
    pairs.Add("access_token", UserInfo.Token);
    pairs.Add("status", text);

    HttpFormUrlEncodedContent content = new HttpFormUrlEncodedContent(pairs);

    using (HttpClient client = new HttpClient())
    {
        HttpResponseMessage response;
        try
        {
            response = await client.PostAsync(uri, content);
        }
        catch (Exception ex)
        {
            throw new Exception("Network error", ex);
        }
        return await response.Content.ReadAsJsonAsync<WeiboResult>();
    }
}

public async Task<WeiboResult> ShareImageAsync(byte[] image, string text)
{
    if (image == null)
    {
        throw new ArgumentNullException(nameof(image));
    }

    if (text == null)
    {
        throw new ArgumentNullException(nameof(text));
    }

    if (string.IsNullOrWhiteSpace(text))
    {
        throw new ArgumentException("Text could not be empty", nameof(text));
    }

    if (!UserInfo.CheckUseable())
    {
        string authorizeCode = await this.GetAuthorizeCodeAsync();
        await this.Authorize(authorizeCode);
    }

    Uri uri = new Uri("https://upload.api.weibo.com/2/statuses/upload.json");

    HttpBufferContent bufferContent = new HttpBufferContent(image.AsBuffer());

    HttpMultipartFormDataContent content = new HttpMultipartFormDataContent();

    content.Add(new HttpStringContent(UserInfo.Token), "access_token");
    content.Add(new HttpStringContent(text), "status");
    content.Add(bufferContent, "pic", "pic.jpg");

    using (HttpClient client = new HttpClient())
    {
        HttpResponseMessage response;
        try
        {
            response = await client.PostAsync(uri, content);
        }
        catch (Exception ex)
        {
            throw new Exception("Network error", ex);
        }
        return await response.Content.ReadAsJsonAsync<WeiboResult>();
    }
}
  • 添加了对异步线程错误的处理和对异步Command的支持.

异步线程的处理我在上一篇《讲讲我在Windows10(uwp)开发中遇到的一些坑》已经说过了.这里说下贴一下异步Command的代码:

public class AsyncCommand : AsyncCommandBase
{
    private readonly Func<Task> command;
    public AsyncCommand(Func<Task> command)
    {
        this.command = command;
    }
    public override bool CanExecute(object parameter)
    {
        return true;
    }
    public override Task ExecuteAsync(object parameter)
    {
        return command();
    }
}
  • 支持下拉刷新和加载更多(但还有Bug).

对于UWP的下拉刷新,我在博客园里看到了几种实现方式:

UWP的一种下拉刷新实现

只贴了一种,因为目前实现下拉刷新的方式都是ListView外部套一个ScrollViewer来实现,这种实现方式有个严重的问题就是:ListView内部也是有一个ScrollViewer,当滑动的时候,会出现ListView内部的ScrollViewer被压缩,这样直接导致了下拉刷新的失败.

我这里思考了另一种方式,就是对ListView内部的ScrollViewer进行操作.

<ScrollViewer Margin="0,0,0,-100" RenderTransformOrigin="0.5,0.5" x:Name="ScrollViewer" AutomationProperties.AccessibilityView="Raw" BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}" IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" TabNavigation="{TemplateBinding TabNavigation}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">
    <ScrollViewer.RenderTransform>
        <CompositeTransform TranslateY="-100" />
    </ScrollViewer.RenderTransform>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Border Height="{TemplateBinding RefreshHeaderHeight}" x:Name="PullToRefreshIndicator" Background="Transparent">
            <Grid HorizontalAlignment="Center">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="auto" />
                    <ColumnDefinition Width="auto" />
                </Grid.ColumnDefinitions>
                <Grid Width="40">
                    <Viewbox x:Name="Arrow" Height="15" VerticalAlignment="Top" Margin="0,4,0,0" RenderTransformOrigin="0.5,0.5">
                        <Viewbox.RenderTransform>
                            <CompositeTransform Rotation="180" />
                        </Viewbox.RenderTransform>
                        <Image Source="ms-appx:///Assets/arrow.png" Width="12" Height="12.9999"/>
                        <!--<Path
            Width="12"
            Height="12.9999"
            Stretch="Fill"
            Fill="{TemplateBinding ArrowColor}"
            Data="M 20.4289,10.4376L 25,15.0087L 23.571,16.4376L 20.0291,12.8957L 20.0291,21.9999L 18.0083,21.9999L 18.0083,12.8583L 14.4289,16.4377L 13,15.0087L 17.5624,10.429L 19.0087,9" />-->
                    </Viewbox>
                </Grid>
                <TextBlock Grid.Column="1" x:Name="PullPart" Text="{TemplateBinding PullPartTemplate}"/>
                <TextBlock Grid.Column="1" Visibility="Collapsed" x:Name="ReleasePart" Text="{TemplateBinding ReleasePartTemplate}"/>
            </Grid>
        </Border>
        <ItemsPresenter FooterTransitions="{TemplateBinding FooterTransitions}" FooterTemplate="{TemplateBinding FooterTemplate}"
            Footer="{TemplateBinding Footer}" HeaderTemplate="{TemplateBinding HeaderTemplate}" Header="{TemplateBinding Header}"
            HeaderTransitions="{TemplateBinding HeaderTransitions}" Padding="{TemplateBinding Padding}" Grid.Row="1"/>
    </Grid>
</ScrollViewer>

对内部的ScrollViewer的压缩进行操作,这样能够比较精准的获取用户的下拉.

同时我已经把这个代码封装成一个单独的控件,你可以从下面的链接获取到源码:

https://github.com/youngytj/uwp_PullToRefreshListview

使用方式只要在xaml里添加如下代码即可使用:

<local:PullToRefreshListView x:Name="lv"
        PullPartTemplate="Pull" ReleasePartTemplate="Release"
        RefreshContent="lv_RefreshContent" MoreContent="lv_MoreContent"/>

PullPartTemplate和ReleasePartTemplate分别是下拉和释放时候的文字.然后后面是更新和加载更多时候的事件.

  • 使用了MVVMLight,所有的界面都以嵌入的方式放入MainPage中.

MainPage里面通过ContentControl的来绑定内容

<ContentControl Content="{Binding CurrentViewModel}" ContentTemplate="{Binding Path=CurrentTemplate}"
                            HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"/>

View和ViewModel的绑定放在了App.xaml

<Application.Resources>
    <ResourceDictionary>
        <vm:ViewModelLocator x:Key="Locator"/>
        <DataTemplate x:Key="HomeViewModel">
            <view:HomeView/>
        </DataTemplate>
        ...
</Application.Resources>

这里有个注意的地方就是View只是作为一个资源的方式存在,当MainPage中发生页面转换时,会将ViewModel的名字作为一个Key(所以类名必须是Key)来寻找View.

public static class DataTemplateSelector
{
    public static DataTemplate GetTemplate(ViewModelBase param)
    {
        Type t = param.GetType();
        if(!views.ContainsKey(t.Name))
        {
            views.Add(t.Name, App.Current.Resources[t.Name] as DataTemplate);
        }

        return views[t.Name];
    }
}

开源地址

没有上传到市场,因为我这边网络一直上载不了包,如果网络环境好了以后再考虑上传,下面是Github的源码地址:

Github

写在最后

并不是很看好微软这种实现跨平台.除了目前UWP这门技术的不成熟,包括很多的缺失,诸如异步线程的处理问题,缺少对移动端的滑动的支持(不像android一样可以从底层开始实现一个行云流水般的手势操作,还有就是ScrollViewer依然存在之前的问题.),还有就是对于微软的这种跨平台的方式,我支持这种看法--因为硬件设备和运行环境的不同带来的用户体验的不同,才是跨平台最大的障碍!这一障碍,不是任何一个“技术”或“技术提供商”可以解决的!.总体来说,因为是全新的平台,相应的开源组件比较少,上手还需要一些时间来熟悉这个平台,平台的不足之处也需要自己从无到有.

这个客户端其实还有很多不好的地方,比如对于异步线程启动关闭的控制不足,缺少log,缺少对于缓存的系统的管理,还有导航系统的不足,不同网络的环境下的客户端优化的问题.但是我认为仅仅作为一个研究学习的项目,已经足够了.如果你喜欢或者支持这样的项目,帮忙点个推荐吧.

以上,说完.谢谢.

时间: 2024-11-20 13:11:02

[开源,学习,分享]UWP第三方简书客户端分享的相关文章

微信----分享(第三方平台的授权分享待完善)

参考SDK-----详情百度网盘 链接:https://pan.baidu.com/s/1ejSw4A5Vi6knL8T9qVQnCQ 提取码:h8wl 微信文档 :https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115 备注:第三方平台跟[非]第三方平台实现的思路有所区别 一.[非]第三方平台 实际流程: ①.在公众号设置js安全域名 ②.参考sdk,根据appId跟appsecret分别获取access_token.

抽空通过简书网学习了一下console,感觉高大上!

抽空看了一下简书中关于console的文章,为了便于自己今后查看,自己写了一遍!原文地址:http://www.jianshu.com/p/f961e1a03a56 测试代码在最下面 1.console.log(); console.debug()与console.info()与console.log一样 (a,b,c); 可接受多个参数,中间用逗号分开,默认输出完最后输出换行符 如果第一个参数是格式字符串(使用了格式占位符),后面的参数对应前面的占位符进行输出 占位符为一下五种%d/%i %s

仿简书分享:UIActivityViewController系统原生分享

接下来介绍UIActivityViewController: 1. 创建要分享的数据内容,加在一个数组 ActivityItems里. NSString *textToShare = @"我是且行且珍惜_iOS,欢迎关注我!"; UIImage *imageToShare = [UIImage imageNamed:@"wang.png"]; NSURL *urlToShare = [NSURL URLWithString:@"https://github

iOS开发--Bison详解连连支付集成简书

"最近由于公司项目需要集成连连支付,文档写的不是很清楚,遇到了一些坑,因此记录一下,希望能帮到有需要的人." 前面简单的集成没有遇到什么坑,在此整理一下官方的集成文档,具体步骤如下 导入文件 添加头文件引用 设置link标志Target->Build Setting ,Other Linker Flags 设置为 -all_load可能添加-all_load以后和其他库冲突,可以尝试使用 -force_load 单独load库, force_load后面跟的是 lib库的完整路径

[程序猿]推荐17个很有用的在线工具 - 简书

简 首页 专题 发钱啦 注册 登录 简首页 专题 下载手机应用 简书 交流故事,沟通想法 iOS· Android 显示模式 登录 下载简书移动应用 注册 登录 添加关注 作者 郭小力 2016.08.25 12:12 写了8570字,被20人关注,获得了67个喜欢 [程序猿]推荐17个很有用的在线工具 字数1032 阅读188 评论1 喜欢16 收藏文章 分享 1. ExplainShell.com 命令解释 对于Linux用户来说每天都会写各种命令和脚本,那么你可以使用这个网站工具来查看命令

WPF RoutedEvent and HitTest - 简书

原文:WPF RoutedEvent and HitTest - 简书 学习的时候切忌心浮气躁,慢慢的过每一个知识点,不要漏掉任何细节.不然当遇到细节问题的时候,会恼,会闹,会悔不该当初--花一下午调bug最后只改了一个参数有感. 相信很多用过WPF的人都知道WPF中的路由事件.一般看书的话,这个知识点也会在前几章讲到.总的来说,也就是 WPF的控件都存在于一颗Visual tree当中. 事件在控件中的传递,其实也就是事件在Visual tree中的传递 隧道事件从上往下,由树根开始向叶子传播

个人技术博客的选择:CSDN、博客园、简书、知乎专栏还是Github Page?(转)

个人技术博客的选择:CSDN.博客园.简书.知乎专栏还是Github Page? 有很多技术人员在学习到一定程度后发现了写博客的重要性,一方面帮助自己记忆,一方面也能帮助他人解决问题,于是会选择自己开始写博客,之后又发现平台太多不知从何下手,在这里我根据自己写博客的经验比较一下各个平台的优缺点. 这里主要对比CSDN.博客园.简书.知乎专栏.Github Page.个人建站和其他 CSDN 笔者是CSDN的长期用户,也见到了很多不错的CSDN博客 优点 SEO做得好,无论是百度还是google(

jsoup爬虫简书首页数据做个小Demo

昨天LZ去面试,遇到一个大牛,被血虐一番,发现自己基础还是很薄弱,对java一些原理掌握的还是不够稳固,比如java反射注解,知道一点就是说不出来,很尴尬- 生命不止,学习不止啊 之前那个项目 QNews 用的是的第三方的数据平台,所以访问次数会有限制,这就很无奈... 我的博客地址 每天只能请求100次-.但是LZ这个穷屌丝也买不起服务器,所以就上网查,有什么别的方法可以获取数据,意外之间发现了jsoup这个强大的框架,就花了上午时间学习了一下,然后下午做了一个小Demo,功能比较单一,请见谅

集成ShareSdk一键分享和第三方登录

在Mob官网http://mob.com/注册,创建应用,下载SDK,申请APP_key 根据官网开发指南导入SDK到你的项目中: 在assets/ShareSDk.xml中修改你的APP_key package com.loaderman.thirdpartylogindemo; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; im