做商城类APP时经常会遇到抢购倒计时的功能,之前做小区宝iOS的时候也有类似的功能,想着参考iOS做的思路,自定义一个Cell,在Cell中每秒刷新一下控件的文本值,但使用xamarin.forms实现时,自定义cell的方式并不可行,小伙伴上周给发了一个倒计时功能的demo:https://github.com/jsuarezruiz/MyTripCountdown,demo是如下图实现的是一个时间的倒计时效果,需要将一个倒计时的功能放在列表中,实现多个倒计时的效果, 看了源码也一直没思路,昨天也是没思路报着试一试的心态动手操作了下,没想到成功了,还是非常有成就感的。

一、定义计时器

xamarin.forms提供了Device.StartTimer来实现定时任务,每隔一秒需要触发事件改变剩余时间。这里定义了两个Action,Completed是在倒计时结束时触发,Ticked是每秒触发一次。RemainTime是剩余时间timespan,EndDate为结束时间。

using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;

namespace TimeCountDown
{
    public class CountDown : BindableObject
    {
        TimeSpan _remainTime;

        public event Action Completed;

        public event Action Ticked;

        public DateTime EndDate { get; set; }

        public TimeSpan RemainTime
        {
            get { return _remainTime; }

            private set
            {
                _remainTime = value;
                OnPropertyChanged();
            }
        }

        )
        {
            Device.StartTimer(TimeSpan.FromSeconds(seconds), () =>
            {
                RemainTime = (EndDate - DateTime.Now);

                ;

                if (ticked)
                {
                    Ticked?.Invoke();
                }
                else
                {
                    Completed?.Invoke();
                }

                return ticked;
            });
        }
    }
}

二、设置BaseViewModel

这里创建了一个BaseViewModel,并有2个方法,LoadAsync()、UnloadAsync(),而且继承了ExtendedBindableObject。

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace TimeCountDown
{
    public abstract class BaseViewModel : ExtendedBindableObject
    {
        public virtual Task LoadAsync()
        {
            return Task.CompletedTask;
        }

        public virtual Task UnloadAsync()
        {
            return Task.CompletedTask;
        }
    }
}

在ExtendedBindableObject中扩展了BindableObject,增加了SetProperty方法,SetProperty方法使用ref引用改变属性的值。

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
using Xamarin.Forms;

namespace TimeCountDown
{
    public class ExtendedBindableObject : BindableObject
    {
        protected bool SetProperty<T>(ref T backingStore, T value, [CallerMemberName]string propertyName = "")
        {
            if (EqualityComparer<T>.Default.Equals(backingStore, value))
            {
                return false;
            }

            backingStore = value;
            OnPropertyChanged(propertyName);

            return true;
        }
    }
}

三、设置ViewModel

新建继承BaseViewModel的类CountDownViewModel,在CountDownViewModel中定义了倒计时类CountDown,当CountDownViewModel调用构造函数时实例化倒计时CountDown,EndDate通过时间戳获得,之后调用LoadAsync()方法,启动计时器,并为计时器绑定具体Actio,在Ticked的Action中每秒定时刷新绑定到界面的数值。

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace TimeCountDown
{
    public class CountDownViewModel : BaseViewModel
    {
        public long Tick { get; set; }

        private string _countDownTitle;

        public string CountDownTitle
        {
            get => _countDownTitle;
            set => SetProperty(ref _countDownTitle, value);
        }

        private CountDown _countDown;

        public CountDownViewModel(long ticks)
        {
            Tick = ticks;
            _countDown = new CountDown() { EndDate = DateTime.Now.Add(new TimeSpan(ticks)) };
            LoadAsync();

        }
        public override Task LoadAsync()
        {
            _countDown.Start();
            _countDown.Ticked += OnCountdownTicked;
            _countDown.Completed += OnCountdownCompleted;
            return base.LoadAsync();
        }

        public override Task UnloadAsync()
        {
            _countDown.Ticked -= OnCountdownTicked;
            _countDown.Completed -= OnCountdownCompleted;
            return base.UnloadAsync();
        }

        void OnCountdownTicked()
        {
            CountDownTitle = string.Format("{0}:{1}:{2}后开抢", _countDown.RemainTime.Hours, _countDown.RemainTime.Minutes, _countDown.RemainTime.Seconds);
        }

        void OnCountdownCompleted()
        {
            CountDownTitle = "抢购进行中";
            UnloadAsync();
        }
    }
}

四、测试

在MainPage中设置了一个ListView,ViewCell模板中设置了一个Label,Text值绑定了CountDownTitle。在MainPage的构造方法中设置listview的ItemsSource。

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:TimeCountDown"
             x:Class="TimeCountDown.MainPage">
    <StackLayout>
        <ListView x:Name="listView"  VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Label Text=" TextColor="Black" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"></Label>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>
        public MainPage()
        {
            InitializeComponent();
            List<CountDownViewModel> countDownVMs = new List<CountDownViewModel>() {
                ),
                ),
                ),
                ),
            };
            listView.ItemsSource = countDownVMs;
        }

效果图如下:

xamarin.forms之实现ListView列表倒计时的更多相关文章

  1. Xamarin.Forms中的ListView的ItemTrapped事件与ItemSelected事件的区别

    今天对Xamarin.Forms中的ListView的两个事件(ItemTrapped和ItemSelected)做了小小的研究,发现有以下几点区别: 1.ItemTrapped事件会优先被触发. 2 ...

  2. A Xamarin.Forms Infinite Scrolling ListView

    from:http://www.codenutz.com/lac09-xamarin-forms-infinite-scrolling-listview/ The last few months ha ...

  3. Xamarin自定义布局系列——ListView的一个自定义实现ItemsControl(横向列表)

    在以前写UWP程序的时候,了解到在ListView或者ListBox这类的列表空间中,有一个叫做ItemsPannel的属性,它是所有列表中子元素实际的容器,如果要让列表进行横向排列,只需要在Xaml ...

  4. Xamarin.Forms: 无限滚动的ListView(懒加载方式)

    说明 在本博客中,学习如何在Xamarin.Forms应用程序中设计一个可扩展的无限滚动的ListView.这个无限滚动函数在默认的Xamarin.Forms不存在,因此我们需要为此添加插件.在这里我 ...

  5. Xamarin.Forms 简介

    An Introduction to Xamarin.Forms 来源:http://developer.xamarin.com/guides/cross-platform/xamarin-forms ...

  6. 老司机学新平台 - Xamarin Forms开发框架之MvvmCross插件精选

    在前两篇老司机学Xamarin系列中,简单介绍了Xamarin开发环境的搭建以及Prism和MvvmCross这两个开发框架.不同的框架,往往不仅仅使用不同的架构风格,同时社区活跃度不同,各种功能模块 ...

  7. Xamarin.Forms入门-使用 Xamarin.Forms 来创建跨平台的用户界面

    Xamarin.Forms 是一个跨平台的.基于原生控件的UI工具包,开发人员可以轻松的创建适用于 Android,iOS 以及 Windows Phone的用户界面.Xamarin.Forms 通过 ...

  8. 张高兴的 Xamarin.Forms 开发笔记:为 Android 与 iOS 引入 UWP 风格的汉堡菜单 ( MasterDetailPage )

    所谓 UWP 样式的汉堡菜单,我曾在"张高兴的 UWP 开发笔记:汉堡菜单进阶"里说过,也就是使用 Segoe MDL2 Assets 字体作为左侧 Icon,并且左侧使用填充颜色 ...

  9. xamarin.forms之page

    最近在使用xamarin.forms做APP开发,之前做过ios的应用,虽然没做过安卓,但之前也有一点了解,什么四大组件五大布局啥的,微软的xamarin.forms的文档也挺详细的,基本都是复制粘贴 ...

随机推荐

  1. java内存结构

    Java的内存结构 JVM的内存结构主要有三大块:堆.方法区和栈.堆内存是JVM中最大的一块,由年轻代和老年代组成,而年轻代内存又被分为三部分,Eden空间.FromSurvivor空间和ToSurv ...

  2. ios开发中的深拷贝和浅拷贝

    这是一个老生常谈的话题,面试中也经常被问到,下面总结一下自己的一些心得. 一句话总结: 浅拷贝就是指针拷贝: 深拷贝是对象本身的拷贝: 下面一张抽象的图可以直观的表述出两句话的内涵 其实这里还引申出了 ...

  3. Vue(三十三)国际化解决方案

    摘自:https://blog.csdn.net/qq_41485414/article/details/81093999 (1)第一种方式:中英文两套页面 优点:技术含量最低 缺点:占内存,响应慢, ...

  4. Hive 本地调试方法

    关键词:hive, debug 本地调试(local debug) Hive 可分为 exec (hive-exec,主要对应源码里的ql目录) 和 metastore 两部分,其中exec对外有两种 ...

  5. Reveal : Xcode辅助界面调试工具

    Reveal简介: Reveal是一款iOS界面调试工具,辅助Xcode进行界面调试,使用它可以在iOS开发的时候动态的查看和修改应用程序的界面. 软件下载 首先去官网下载Reveal,下载地址:ht ...

  6. 机器学习(七)EM算法、GMM

    一.GMM算法 EM算法实在是难以介绍清楚,因此我们用EM算法的一个特例GMM算法作为引入. 1.GMM算法问题描述 GMM模型称为混合高斯分布,顾名思义,它是由几组分别符合不同参数的高斯分布的数据混 ...

  7. 微信小程序开发---自定义组件

    开发者可以将页面内的功能模块抽象成自定义组件,以便在不同的页面中重复使用:也可以将复杂的页面拆分成多个低耦合的模块,有助于代码维护.自定义组件在使用时与基础组件非常相似. 创建自定义组件 类似于页面, ...

  8. 反调试——jmp到那个地址

    目录 1.前言 2.原理讲解 3.代码实现 前言 这节的反调试是通过构造代码来干扰正常的分析.反调试参考CrypMic勒索病毒 原理讲解 在逆向分析汇编代码时,一般都是通过汇编指令call或jmp跳到 ...

  9. 详解封装微信小程序组件及小程序坑(附带解决方案)

    一.序 上一篇介绍了如何从零开发微信小程序,博客园审核变智障了,每次代码都不算篇幅,好好滴一篇原创,不到3分钟从首页移出来了.这篇介绍一下组件封装和我的踩坑历程. 二.封装微信小程序可复用组件 首先模 ...

  10. js 压缩

    听到同事说没找到压缩js文件的,说软件压缩貌似有点问题,我自己就用nodejs练手般写了压缩文件的. 主要的思路就是,先通过前端上传js文件,然后服务器接收,然后引用uglifyjs 压缩,再返回文件 ...