Xamarin. Android实现下拉的刷新功能.

下拉刷新功能在安卓和iOS中非常常见,一般实现这样的功能都是直接使用第三方的库,网上能找到很多这样的开源库。然而在Xamarin. Android中要实现一个好用的下拉刷新功能却不是很容易,在网上找了几个Xamarin.Android的下拉刷新控件,都不是很满意,所以想重新绑定一个java写的下拉刷新控件。在网上找了几个这样的开源库,通过对比发现android-pull-to-refresh实现的功能比较多,实现的效果也比较满意。

Android-Pull-To-Refresh项目地址:https://github.com/naver/android-pull-to-refresh

该库包含如下功能点:

  • 支持顶部下拉刷新和顶部上拉刷新(可以同时启用这两个功能)
  • Android2.3以上设备支持滚动
  • 支持以下控件
    • ListView
    • ExpandableListView
    • GridView
    • WebView
    • ScrollView
    • HorizontalScrollView
    • ViewPager
    • 支持检测列表是否滚动到最末尾
    • 支持ListFragment
    • 支持很多自定义选项(1.自定义正在加载界面,可以修改图标和文字 2.支持多个提示图标,平滑滚动时间间隔设置等)

其他详细说明请到该项目的网站查看。

本文主要包含以下五个部分

一、Jar文件的生成

二、PullToRefresh.dll的生成

三、PullToRefresh的使用

四、MvvmCross中使用PullToRefresh

五、总结

 

一、Jar文件的生成

下面开始进行绑定操作,要能够进行绑定,首先需要将java项目编译为jar文件,我是通过fat-jar插件生成pulltorefresh.jar文件的,通过其他方式生成也是可以的。

 

只选中项目的output即可

 

二、PullToRefresh.dll的生成

接下来创建Android Binding项目,将生成的jar文件添加到项目中,生成类型选择embeddedjar,生成的版本选择2.3,由于该项目没有引用其他项目,所以不需要进行其他设置,项目的结构图如下:

 

接下来编译项目,编译时VS给出了如下的错误提示:

error CS0060: Inconsistent accessibility: base class 'Com.Handmark.Pulltorefresh.Library.PullToRefreshListView.InternalListView' is less accessible than class 'Com.Handmark.Pulltorefresh.Library.PullToRefreshListView.InternalListViewSDK9'

error CS0102: The type 'Com.Handmark.Pulltorefresh.Library.PullToRefreshBase' already contains a definition for 'Mode'

error CS0102: The type 'Com.Handmark.Pulltorefresh.Library.PullToRefreshBase' already contains a definition for 'State'

根据错误提示可以看出:

第一个错误是由于子类方法的可访问性比父类的高,双击错误提示可以看到InternalListView类是protected修饰的,而子类InternalListViewSDK9是public修饰,在c#是不允许的,那么我们可以通过metadata.xml配置类型修饰符,使他们的修饰符统一,我这里将InternalListView类的修饰符修改public,代码如下:

<attr  path="/api/package[@name='com.handmark.pulltorefresh.library']/class[@name='PullToRefreshListView.InternalListView']" name="visibility">public</attr>

第二个和第三个错误的提示为已经包含了Mode和State的定义,通过查看java的源代码发现是由以下原因引起的:

PullToRefreshBase类里面定义了两个枚举Mode和State,并且定义了getMode、getState、setMode、setState方法,java里的get和set方法会被转换为c#里的属性,生成的代码如下:

View Code

在C#中,这样的代码是无法通过编译的,因为属性的名称和类型的名称一样,所以必须进行修改才行,我们可以将枚举的名称分别修改为PullToRefreshMode和PullToRefreshState.我们在metadata.xml里添加如下代码:

View Code

再次编译,发现还是报错,一共报了10个错误:

第一个错误是由于访问修饰符不统一造成的,通过添加如下代码可以解决:

View Code

剩下的9个问题都是类似的,未实现某个接口或者抽象类的某个方法,双击其中的错误提示,发现有6个方法都是实现了,但编译的时候还是提示未实现方法。通过查看java源代码与生成的c#代码,找到了原因,java源代码里面有一个泛型类PullToRefreshBase<V entends View>,该类里面有一个抽象的泛型方法protected abstract T createRefreshableView(Context context, AttributeSet attrs);,转换为c#代码后泛型抽象方法的返回值变为了Java.Lang.Object,而实际上应该是生成一个泛型类,然后生成一个泛型抽象方法,可见转换程序还不是太完善。此处的修改方式为:将子类的对应方法的返回值修改为Java.Lang.Object,代码如下:

View Code

剩下3个方法,在生成的C#代码里确实没找到,那就是没进行转换或者转换时报错了,此时我们需要查看对应的java源代码,分别找到报错的方法InternalListView.setEmptyView

InternalExpandableListView.setEmptyView

InternalGridView.setEmptyView

这3个方法里的代码都很简单,都只有一句代码

PullToRefreshListView.this.setEmptyView(emptyView);

PullToRefreshExpandableListView.this.setEmptyView(emptyView);

PullToRefreshGridView.this.setEmptyView(emptyView);

这3句代码都非常类似,都是”ClassName.this.MethodName”,在java里,只有内部类里可以这样写,该代码的作用是访问外部类的实例方法。 由于c#里面没有” ClassName.this.MethodName”的写法,所以猜想可能是这个原因导致了转换失败,那么我们就只有修改java源代码进行测试了。去掉this,换成同等效果的写法,修改方法如下,3个类的修改方法类似,这里就只写一个:

1. 在InternalListView类增加一个PullToRefreshListView类型的字段 _view

2. 在InternalListView类的构造函数添加一个PullToRefreshListView类型的参数view,并在构造函数内部给新增的字段赋值,使用view的值

3. 修改setEmptyView方法的代码,改为_view. setEmptyView(emptyView)

4. 增加一个get方法,返回刚才新增的_view字段

5. 修改引用的代码,传入对应的参数

修改完成后重新导出jar文件,替换为vs项目中的对应jar文件,然后重新编译,编译之后还是报同样的错误,这样就证明我们的猜想不正确,那么到底是什么原因导致转换失败内?我开始试了一些其他方法,都没有成功编译,最后发现InternalListView以及InternalListViewSDK9都是内部类(嵌套到PullToRefreshListView里面的,另外两个两个类也是内部类),就是这个内部类导致了错误,我们把对应的6个内部类(每个类里面2个内部类,一个InternalXXX一个InternalXXXSDK9)改为普通类,再次导出jar,再次编译,编译通过了,我们现在来测试一下绑定的库能否正常工作。

三、PullToRefresh的使用

新建一个测试项目PullToRefresh.Sample,添加相关资源及引用,并将原项目的java代码翻译为c#代码,翻译的时候有以下两个地方需要注意:

1. 实现java接口的类要继承自Java.Lang.Object,否则需要自己实现IJavaObject,而自己实现的IJavaObject很有可能无法正常工作,具体信息可以参考:http://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/working_with_jni/#Implementing_Interfaces

2. C#的内部类是无法直接访问外部类的实例成员的,所以需要对其中的内部类做调整

3. 向集合里添加数据使用mAdapter.Insert方法,直接向List集合添加界面不会显示数据

翻译后的C#代码如下:

View Code

代码调整完成后进行编译,发现编译的时候又报错了,报错信息里很多乱码,不过可以看到几个关键字“OnSmoothScrollFinishedListener”,所以猜想可能是“OnSmoothScrollFinishedListener”这个接口可能有问题,我们返回到java源代码查看。

在java源代码里的“PullToRefreshBase”类里搜索“OnSmoothScrollFinishedListener”,

找到接口的定义:

View Code

我们发现接口是static且是默认的修饰符,我们试一试将修饰符改为public,重新导出jar,再次编译,发现能够通过了,现在我们来看看功能是否正常

运行的时候报错了,提示找不到资源,原来我们绑定java库时忘记打包资源了,我们将资源文件一起打包,然后重新编译.打包资源文件时需要注意以下问题:

  1. jar文件和资源文件都打包到一个zip文件中,zip压缩包的目录结构如下:

    2.详细信息请参考: http://developer.xamarin.com/guides/android/advanced_topics/java_integration_overview/binding_a_java_library_(.jar)/

再次编译并运行,终于正常运行了。

四、MvvmCross中使用PullToRefresh

由于最近在使用Mvvmcross,所以也写一个Mvvmcross的例子,下面以ListView为例,实现一个MvxPullToRefreshListView。代码如下:

View Code

使用MvxPullToRefreshListView的关键代码如下:

FirstViewModel.cs

View Code

FirstView.axml代码如下:

View Code

user_item.xaml的代码如下:

View Code

运行的效果和上面一样,就不上图了。

五、总结

C#要使用java的jar不容易啊,会出现各种各样的问题,感觉比直接在java里使用麻烦很多很多,需要耐心的解决这些问题,并且可能需要修改java代码。不过使用Xamarin的好处是,逻辑代码可以完全重用,并且编写代码的效率比直接用java要高。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值