首页 文章 精选 留言 我的

精选列表

搜索[网站开发],共10000篇文章
优秀的个人博客,低调大师

iOS开发-多线程NSOperation和NSOperationQueue

上一篇文章稍微提及了一下NSThread的使用,NSThread能直观地控制线程对象,不过需要自己管理线程的生命周期,线程同步,用起来比较繁琐,而且比较容易出错。不过Apple给出了自己的解决方案NSOperation,它本身是抽象基类,因此必须使用它的子类,使用NSOperation子类的方式有NSInvocationOperation和NSBlockOperation两种方式,先补充一下NSThread的用法: NSThread获取当前线程: 1 [ NSThread currentThread] performSelectorInBackground可以更新UI,不建议使用: 1 2 3 4 5 - ( IBAction )update:( id )sender { [ self performSelectorInBackground: @selector (changeImage) withObject: nil ]; } 图片背景更新: 1 2 3 4 -( void )changeImage{ NSLog (@ "线程执行完之后更新图片" ); self .myImageView.image=[UIImage imageNamed:[ NSString stringWithFormat:@ "Thread2.jpg" ]]; } NSInvocationOperation和NSBlockOperation 这两种方式都很简单,其中NSInvocation的调用方式类似于NSThread,NSBlockOperation如果对Block有一点了解就可以,如果不明白的可以参考本人之前的Block文章Object-C-代码块Block回顾,那么接下来的使用方式就很简单: 先来看下NSInvocationOperation的实例化方式: 1 2 3 4 //初始化 NSInvocationOperation *myInvocationOperation= [[ NSInvocationOperation alloc] initWithTarget: self selector: @selector (operationTaskMethod) object: nil ]; //启动 [myInvocationOperation start]; 调用方法: 1 2 3 4 -( void )operationTaskMethod{ NSLog (@ "NSInvocationOperation初始化执行" ); } NSBlockOperation的方式: 1 2 3 4 NSBlockOperation *blockOperation=[ NSBlockOperation blockOperationWithBlock:^{ NSLog (@ "BlockOperation块执行" ); }]; [blockOperation start]; 两种方式很方便,这个时候可以使用NSOperationQueue作为一个队列将线程包含在一起,首先定义一个NSOperationQuene: 1 @property (strong, nonatomic ) NSOperationQueue *myOperationQuene; 这个时候需要调用: 1 2 3 4 5 6 7 8 9 10 11 NSInvocationOperation *myInvocationOperation= [[ NSInvocationOperation alloc] initWithTarget: self selector: @selector (operationTaskMethod) object: nil ]; NSBlockOperation *blockOperation=[ NSBlockOperation blockOperationWithBlock:^{ NSLog (@ "BlockOperation块执行" ); }]; self .myOperationQuene=[[ NSOperationQueue alloc]init]; [ self .myOperationQuene addOperation:myInvocationOperation]; [ self .myOperationQuene addOperation:blockOperation]; 上面最后的结果不确定,线程执行的顺序没法确定,如果想确定的按照顺序执行,需要添加一个依赖: 1 [blockOperation addDependency:myInvocationOperation]; 添加依赖之后的,每次输出的结果一定是这样的: 1 2 2015-02-11 07:56:13.457 ThreadDemo[657:15033] NSInvocationOperation 初始化执行 2015-02-11 07:56:13.457 ThreadDemo[657:15034] BlockOperation块执行 自定义NSOperation 每次一看到自定义,就感觉瞬间有了档次,然后参考一下前人的经验,不过网上的博客有的不好说,那感觉就是我想吃一个鸡腿,却拿到了一个鸡腿堡,需要的不需要的都要自己一起吸收。NSInvocationOperation和NSBlockOperation这两种方式不能满足业务需求,这个时候需要自定义的NSOperation,自定义的有两种分为非并发(NonConcurrent)和并发(Concurrent)两种形式,本文介绍非并发形式。 新建一个继承自NSOperation的MyCustomOperation,然后实现一下main方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 // // MyCustomOperation.h // ThreadDemo // // Created by keso on 15/2/11. // Copyright (c) 2015年 keso. All rights reserved. // #import <Foundation/Foundation.h> @interface MyCustomOperation : NSOperation @property (strong, nonatomic ) NSString *customdata; -( void )initData:( NSString *)data; @end NSOperation对象需要定期地调用isCancelled方法检测操作是否已经被取消,如果返回YES(表示已取消),则立即退出执行回收内存资源。所有NSOperation子类,一般用于代码比较容易终止的地方,在循环的每次迭代过程中,如果每个迭代相对较长可能需要调用多次和没有执行工作之前调用。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 // // MyCustomOperation.m // ThreadDemo // // Created by keso on 15/2/10. // Copyright (c) 2015年 keso. All rights reserved. // #import "MyCustomOperation.h" @implementation MyCustomOperation - ( void )initData:( NSString *)data{ if ( self ==[ super init]) _customdata= data; } - ( void )main { @try { BOOL isDone = NO ; NSLog (@ "循环之前的调用" ); while (![ self isCancelled] && !isDone) { // Do some work and set isDone to YES when finished NSLog (@ "已经运行成功了" ); isDone= YES ; } } @catch (...) { NSLog (@ "出现异常,请检查代码~" ); } } @end 如果需要调用定义的NSOPeration实例化之后Start即可: 1 2 MyCustomOperation *customOperation=[[MyCustomOperation alloc] init]; [customOperation start]; 本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4285102.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

eclipse上Android NDK开发环境搭建

首先要有已集成好Android adt插件的eclipse,如果没有,到http://developer.android.com/sdk/index.html下载已集成ADT的eclipse。 下载Android NDK包http://developer.android.com/tools/sdk/ndk/index.html并解压。 打开eclipse,点击菜单栏 Windows ---> Preferences---> Android ---> NDK 找到上一步解压的NDK,点击OK 保存。 新建一个Android项目ndktest,并在工程下新建jni文件夹。 在编写native函数,例在com.example.ndktest下创建类 myjni。 运行cmd,定位到ndktest根目录下,运行命令javah -classpath bin\classes -d jni com.example.ndktest.myjni 会在jni文件下生成一个h头文件。 如果点开有报错,可以忽略它,可能因为找不到jni.h这个头文件,先不管。 在jni文件夹下编写com_example_ndktest_myjni.c文件实现方法getSum。 在jni文件夹下编写android.mk文件 在package Explorer 里,右键工程 ----> Properties 选择Program ---> OKOK 保存。 libmyjni.so 动态库已生成libs\armeabi文件夹下。 后面附上HTK中工具HCopy的Android 动态库工程的源码,下载导入工程后,确保已经安装好NDK,并修改第9步,第二图中的NDK_Builder的location到你的NDK包下的cmd即可。 上述例子工程源码:http://down.51cto.com/data/1499353 HCopy动态库工程源码:http://down.51cto.com/data/1499346 本文转自 ponpon_ 51CTO博客,原文链接:http://blog.51cto.com/liuxp0827/1438625,如需转载请自行联系原作者

优秀的个人博客,低调大师

【移动开发】Android中各种xml汇总

Android中xml使用十分广泛,这里简单汇总一下,使其更加系统化! 1.arrays.xml 定义数组 1 2 3 4 5 6 7 <resources> <string-array name= "newstitle" > <item>国际</item> <item>国内</item> <item>军事</item> </string-array> </resources> 2.colors.xml 定义颜色 1 2 3 4 5 6 7 8 9 10 11 <resources> <color name= "blue_sky" >#A0C8FF</color> <color name= "vert_manu" >#CCFF00</color> <color name= "black" ># 000000 </color> <color name= "white" >#FFFFFF</color> <color name= "red" >#FF0000</color> <color name= "link_color" >#FF0066CC</color> <color name= "simiple_button_color" >#FFF</color> <color name= "blue" >#0000FF</color> <color name= "grey" >#FFCBD2D8</color> </resources> 3.dimens.xml 定义尺寸 1 2 3 4 5 <resources> <dimen name= "bottom_tab_font_size" >12dp</dimen> <dimen name= "bottom_tab_padding_up" >5dp</dimen> <dimen name= "bottom_tab_padding_drawable" >8dp</dimen> </resources> 4.drawables.xml 定义画布 1 2 3 4 5 6 7 <resources> <item type= "drawable" name= "shader1" >#7f7f7f7f</item> <item type= "drawable" name= "highlight" >#cf7f7f7f</item> <item type= "drawable" name= "barbg" >#ef0a4267</item> <item type= "drawable" name= "trans" ># 00000000 </item> <item type= "drawable" name= "chatdivider" >#ffd6dadc</item> </resources> 5.strings.xml 定义字符串 1 2 3 4 5 <resources> <string name= "app_name" >Beem</string> <string name= "OkButton" >Ok</string> <string name= "ClearButton" >Clear</string> </resources> 6.styles.xml 定义样式 1 2 3 4 5 6 7 8 9 <resources> <style name= "Label" > <item name= "android:textSize" >18sp</item> <item name= "android:textStyle" >bold</item> <item name= "android:typeface" >sans</item> <item name= "android:focusable" > false </item> <item name= "android:padding" >12dip</item> </style> </resources> 7.selector选择(按下效果) phoinix_popumenu_style.xml 1 2 3 4 5 <selector xmlns:android= "http://schemas.android.com/apk/res/android" > <item android:state_focused= "true" android:state_pressed= "true" android:drawable= "@drawable/phoinix_pushmail_btn_selected" /> <item android:state_focused= "false" android:state_pressed= "true" android:drawable= "@drawable/phoinix_pushmail_btn_selected" /> <item android:state_focused= "true" android:drawable= "@drawable/phoinix_small_selected" /> </selector> 8.menu 菜单 1 2 3 4 5 6 7 8 9 10 11 12 13 <menu xmlns:android= "http://schemas.android.com/apk/res/android" > <group> <item android:id= "@+id/chat_menu_contacts_list" android:visible= "true" android:title= "@string/chat_menu_contacts_list" android:icon= "@drawable/ic_menu_friendslist" /> <item android:id= "@+id/chat_menu_change_chat" android:visible= "true" android:title= "@string/chat_menu_change_chat" android:icon= "@drawable/ic_menu_chat_dashboard" /> </group> <item android:id= "@+id/chat_menu_close_chat" android:visible= "true" android:title= "@string/chat_menu_close_chat" android:icon= "@drawable/ic_menu_end_conversation" /> </menu> 8.anim 旋转动画 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 < set xmlns:android= "http://schemas.android.com/apk/res/android" > <rotate android:interpolator= "@android:anim/accelerate_decelerate_interpolator" android:fromDegrees= "0" android:toDegrees= "+360" android:duration= "3000" /> <!-- rotate 旋转动画效果 属性:interpolator 指定一个动画的插入器,用来控制动画的速度变化 fromDegrees 属性为动画起始时物件的角度 toDegrees 属性为动画结束时物件旋转的角度,+代表顺时针 duration 属性为动画持续时间,以毫秒为单位 --> </ set > 以上这些就是android中常用的xml,至于其他的自行查阅喽~ 本文转自zhf651555765 51CTO博客,原文链接:http://blog.51cto.com/smallwoniu/1248892,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android开发应用实例:ListView的应用

该程序完成如下功能:1在ListView中显示多个学生的名字。2点击ListView中的条目,查询并显示该学生的年龄、性别、照片等信息。 效果图: student.java packagecom.lingdududu.listview; publicclassStudent{ publicStringsname; publicStringssex; publicintsage; Student(Stringname,Stringsex,intage){ sname=name; ssex=sex; sage=age; } voidStuedent(Stringname){ sname=name; } publicStringgetName(){ returnsname; } publicStringgetSex(){ returnssex; } publicintgetAge(){ returnsage; } publicStringtoString(){ returnsname; } //这个方法返回学生的姓名,性别,年龄 publicStringgetStuIfo(){ return("姓名:"+sname+"\n性别:"+ssex+"\n年龄:"+sage); } } ListViewActivity.java packagecom.lingdududu.listview; importjava.util.ArrayList; importandroid.app.Activity; importandroid.app.AlertDialog; importandroid.content.DialogInterface; importandroid.os.Bundle; importandroid.view.View; importandroid.widget.AdapterView; importandroid.widget.AdapterView.OnItemClickListener; importandroid.widget.ArrayAdapter; importandroid.widget.ListView; /* *@authorlingdududu *该程序的主要功能是点击ListView的学生姓名,就能弹出对话框 *在对话框里面显示学生的详细信息:图片,姓名,性别,年龄 */ publicclassListViewActivityextendsActivity{ privateListViewlv; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); //学生图片的ID数组 finalint[]stu_pic={ R.drawable.pic1, R.drawable.pic2, R.drawable.pic3, R.drawable.pic4, R.drawable.pic5, R.drawable.pic6}; finalAlertDialog.Builderbuilder=newAlertDialog.Builder(this); lv=(ListView)findViewById(R.id.list); /*生成动态数组,加入数据*/ finalArrayList<Student>students=newArrayList<Student>(); students.add(newStudent("小张","女",21)); students.add(newStudent("小明","男",22)); students.add(newStudent("小王","男",23)); students.add(newStudent("小丽","女",21)); students.add(newStudent("小红","女",22)); students.add(newStudent("小周","男",23)); ArrayAdapter<Student>adapter=newArrayAdapter<Student> (this,//布局文件 android.R.layout.simple_list_item_1,//android.R.layout.simple_list_item_1,系统定义的布局文件 students);//数据来源 //为ListView设置适配器 lv.setAdapter(adapter); lv.setOnItemClickListener(newOnItemClickListener(){ //arg0发生点击动作的AdapterView //arg1在AdapterView中被点击的视图(它是由adapter提供的一个视图) //arg2视图在adapter中的位置 //arg3被点击元素的行id publicvoidonItemClick(AdapterView<?>arg0,Viewarg1,intarg2, longarg3){ //将学生的详细信息在对话框里面显示 builder.setMessage(students.get(arg2).getStuIfo()) //显示学生的图片 .setIcon(stu_pic[arg2]) .setTitle("你好,这是我的详细信息!") .setPositiveButton("确定",newDialogInterface.OnClickListener(){ publicvoidonClick(DialogInterfacedialog,intwhich){ } }); //创建对话框 AlertDialogad=builder.create(); //显示对话框 ad.show(); } }); } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> 附件:http://down.51cto.com/data/2359281 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/716529

优秀的个人博客,低调大师

iOS开发之Runtime常用示例总结

一、构建Runtime测试用例 本篇博客的内容是依托于实例的,所以我们在本篇博客中先构建我们的测试类,Runtime将会对该类进行相关的操作。下方就是本篇博客所涉及Demo的目录,上面的RuntimeKit类是讲Runtime常用的功能进行了简单的封装,而下方的TestClass以及相关的类目就是我们Runtime要操作的对象了。下方会对TestClass以及类目中的内容进行详细介绍。 下方这几个截图就是我们的测试类TestClass的主要部分,因为TestClass是专门用来测试的类,所以其涉及的内容要尽量的全面。TestClass遵循了NSCoding,NSCopying这两个协议,并且为其添加了公有属性、私有属性、私有成员变量、 公有实例方法、私有实例方法、类方法等。这些添加的内容,都将是我们Runtime的操作对象。下方那几个TestClass的类目稍后在使用Runtime时再进行介绍。 二、RuntimeKit的封装 接下来我们就来看看RuntimeKit中的内容,其中对Runtime常用的方法进行了简单的封装。主要是动态的获取类的一些属性和方法的,以及动态方法添加和方法交换的。本部分的干货还是不少的。 1、获取类名 动态的获取类名是比较简单的,使用class_getName(Class)就可以在运行时来获取类的名称。class_getName()函数返回的是一个char类型的指针,也就是C语言的字符串类型,所以我们要将其转换成NSString类型,然后再返回出去。下方的+fetchClassName:方法就是我们封装的获取类名的方法,如下所示: 2、获取成员变量 下方这个+fetchIvarList:这个方法就是我们封装的获取类的成员变量的方法。当然我们在获取成员变量时,可以用ivar_getTypeEncoding()来获取相应成员变量的类型。使用ivar_getName()来获取相应成员变量的名称。下方就是对获取成员变量的功能的封装。返回的是一个数组,数组的元素是一个字典,而字典中存储的就是相应成员变量的名称和类型。 下方就是调用上述方法获取的TestClass类的成员变量。当然在运行时就没有什么私有和公有之分了,只要是成员变量就可以获取到。在OC中的给类添加成员属性其实就是添加了一个成员变量和getter以及setter方法。所以获取的成员列表中肯定带有成员属性,不过成员属性的名称前方添加了下划线来与成员属性进行区分。我们也可以获取成员变量的类型,下方的_var1是NSInteger类型,动态获取到的是q字母,其实是NSInteger的符号。而i就表示int类型,c表示Bool类型,d表示double类型,f则就表示float类型。当然这些基本类型都是由一个字母代替的,如果是引用类型的话,则直接就是一个字符串了,比如NSArray类型就是"@NSArray"。 3.获取成员属性 上面获取的是类的成员变量,那么下方这个+fetchPropertyList:获取的就是成员属性。当然此刻获取的只包括成员属性,也就是那些有setter或者getter方法的成员变量。下方主要是使用了class_copyPropertyList(Class,&count)来获取的属性列表,然后通过for循环通过property_getName()来获取每个属性的名字。当然使用property_getName()获取到的名字依然是C语言的char类型的指针,所以我们还需要将其转换成NSString类型,然后放到数组中一并返回。如下所示: 下方这个截图就是调用上述方法获取的TestClass的所有的属性,当然dynamicAddProperty是我们使用Runtime动态给TestClass添加的,所以也是可以获取到的。当然我们获取到的属性的名称为了与其对应的成员变量进行区分,成员属性的名字前边是没有下划线的。 4、获取类的实例方法 接下来我们就来封装一下获取类的实例方法列表的功能,下方这个+fetchMethodList:就是我们封装的获取类的实例方法列表的函数。在下方函数中,通过class_copyMethodList()方法获取类的实例方法列表,然后通过for循环使用method_getName()来获取每个方法的名称,然后将方法的名称转换成NSString类型,存储到数组中一并返回。具体代码如下所示: 下方这个截图就是上述方法在TestClass上运行的结果,其中打印了TestClass类的所有实例方法,当然其中也必须得包含成员属性的getter和setter方法。当然TestClass类目中的方法也是必须能获取到的。结果如下所示: 5、获取协议列表 下方是获取我们类所遵循协议列表的方法,主要使用了class_copyProtocolList()来获取列表,然后通过for循序使用protocol_getName()来获取协议的名称,最后将其转换成NSString类型放入数组中返回即可。 下方就是我们获取到的TestClass类所遵循的协议列表: 6、动态添加方法实现 下方就是动态的往相应类上添加方法以及实现。下方的+addMethod方法有三个参数,第一个参数是要添加方法的类,第二个参数是方法的SEL,第三个参数则是提供方法实现的SEL。稍后在消息发送和消息转发时会用到下方的方法。下方主要是使用class_getInstanceMethod()和method_getImplementation()这两个方法相结合获取相应SEL的方法实现。下方的IMP其实就是Implementation的方法缩写,获取到相应的方法实现后,然后再调用class_addMethod()方法将IMP与SEL进行绑定即可。具体做法如下所示。 7、方法实现交换 下方就是讲类的两个方法的实现进行交换。如果将MethodA与MethodB的方法实现进行交换的话,调用MethodA时就会执行MethodB的内容,反之亦然。 下方这段代码就是对上述方法的测试。下方是TestClass的一个类目,在该类目中将类目中的方法与TestClass中的方法进行了替换。也就是将method1与method2进行了替换,替换后在method2中调用的method2其实就是调用的method1。在第三方库中,经常会使用该特性,已达到AOP编程的目的。 三、属性关联 属性关联说白了就是在类目中动态的为我们的类添加相应的属性,如果看过之前发布的对Masonry框架源码解析的博客的话,对下方的属性关联并不陌生。在Masonry框架中就利用Runtime的属性关联在UIView的类目中给UIView添加了一个约束数组,用来记录添加在当前View上的所有约束。下方就是在TestClass的类目中通过objc_getAssociatedObject()和objc_setAssociatedObject()两个方法为TestClass类添加了一个dynamicAddProperty属性。上面我们获取到的属性列表中就含有该动态添加的成员属性。 下方就是属性关联的具体代码,如下所示。 四、消息处理与消息转发 在Runtime中不得不提的就是OC的消息处理和消息转发机制。当然网上也有不少相关资料,本篇博客为了完整性,还是要聊一下消息处理与消息转发的。当你调用一个类的方法时,先在本类中的方法缓存列表中进行查询,如果在缓存列表中找到了该方法的实现,就执行,如果找不到就在本类中的方列表中进行查找。在本类方列表中查找到相应的方法实现后就进行调用,如果没找到,就去父类中进行查找。如果在父类中的方法列表中找到了相应方法的实现,那么就执行,否则就执行下方的几步。 当调用一个方法在缓存列表,本类中的方法列表以及父类的方法列表找不到相应的实现时,到程序崩溃阶段中间还会有几步让你来挽救。接下来就来看看这几步该怎么走。 1.消息处理(Resolve Method) 当在相应的类以及父类中找不到类方法实现时会执行+resolveInstanceMethod:这个类方法。该方法如果在类中不被重写的话,默认返回NO。如果返回NO就表明不做任何处理,走下一步。如果返回YES的话,就说明在该方法中对这个找不到实现的方法进行了处理。在该方法中,我们可以为找不到实现的SEL动态的添加一个方法实现,添加完毕后,就会执行我们添加的方法实现。这样,当一个类调用不存在的方法时,就不会崩溃了。具体做法如下所示: 2、消息快速转发 如果不对上述消息进行处理的话,也就是+resolveInstanceMethod:返回NO时,会走下一步消息转发,即-forwardingTargetForSelector:。该方法会返回一个类的对象,这个类的对象有SEL对应的实现,当调用这个找不到的方法时,就会被转发到SecondClass中去进行处理。这也就是所谓的消息转发。当该方法返回self或者nil, 说明不对相应的方法进行转发,那么就该走下一步了。 3.消息常规转发 如果不将消息转发给其他类的对象,那么就只能自己进行处理了。如果上述方法返回self的话,会执行-methodSignatureForSelector:方法来获取方法的参数以及返回数据类型,也就是说该方法获取的是方法的签名并返回。如果上述方法返回nil的话,那么消息转发就结束,程序崩溃,报出找不到相应的方法实现的崩溃信息。 在+resolveInstanceMethod:返回NO时就会执行下方的方法,下方也是讲该方法转发给SecondClass,如下所示: 本文转自zsdnr 51CTO博客,原文链接:http://blog.51cto.com/12942149/1929658,如需转载请自行联系原作者

优秀的个人博客,低调大师

ios开发使用UIWebView显示多种文档

使用UIWebView显示多种文档 除了HTML的内容,UIWebView还可以显示多种类型的文档 包括以下的类型 ·Excel (.xls) ·Keynote (.key.zip) ·Numbers (.numbers.zip) ·Pages (.pages.zip) ·PDF (.pdf) ·Powerpoint (.ppt) ·Word (.doc) ·Rich Text Format (.rtf) ·Rich Text Format Directory (.rtfd.zip) ·Keynote '09 (.key) ·Numbers '09 (.numbers) ·Pages '09 (.pages) 其中的rtfd必须是文档包的格式并且时zip压缩,同时调用时还应该保留文件后缀名rtfd.zip 使用时参照 -(void)loadDocument:(NSString*)documentName inView:(UIWebView*)webView { NSString *path = [[NSBundle mainBundle] pathForResource:documentName ofType:nil]; NSURL *url = [NSURL fileURLWithPath:path]; NSURLRequest *request = [NSURLRequest requestWithURL:url]; [webView loadRequest:request]; } // Calling -loadDocument:inView: [self loadDocument:@"mydocument.rtfd.zip" inView:self.myWebview]; 本文转自 arthurchen 51CTO博客,原文链接:http://blog.51cto.com/arthurchen/801318,如需转载请自行联系原作者

优秀的个人博客,低调大师

iOS开发-搜索栏UISearchBar和UISearchController

iOS中UISearchDisplayController用于搜索,搜索栏的重要性我们就不说了,狼厂就是靠搜索起家的,现在越来越像一匹没有节操的狼,UC浏览器搜索栏现在默认自家的神马搜索,现在不管是社交,O2O还是在线教育等都会有一个搜索栏的实现,不过彼此实现效果是不一样的。iOS中的搜索栏实现起来相对简单一点,网上也有很多参考资料,不过靠谱的不是很多,很多都是iOS 8.0之前的实现,iOS 8.0上的实现貌似很少看到,可以运行,不过会看到searchDisplayController' is deprecated: first deprecated in iOS 8.0警告,看了一些老外的代码,使用了一下UISearchController感觉还是非常不错的。 UISearchBar和UISearchDisplayController 是网上最常见的也算是最简单的,也有使用Searh Bar Search Display Controller的控件的,本文就简单的使用Search Bar和UITableView实现搜索Demo的,最上面的就是搜索栏,之前的就是TableView: 为了实现搜索需要声明委托UISearchBarDelegate,UISearchDisplayDelegate,其中搜索主要使用的就是UISearchDisplayDelegate,具体代码实现过程: 声明字段: 1 2 3 @property (strong, nonatomic ) NSMutableArray *dataList; @property (strong, nonatomic ) NSMutableArray *searchList; 初始化数据: 1 2 3 4 5 self .dataList=[ NSMutableArray arrayWithCapacity:100]; for ( NSInteger i=0; i<100; i++) { [ self .dataList addObject:[ NSString stringWithFormat:@ "%ld-FlyElephant" ,( long )i]]; } 设置区域: 1 2 3 4 //设置区域 -( NSInteger )numberOfSectionsInTableView:(UITableView *)tableView{ return 1; } 设置区域的行数(重点),这个就是使用委托之后需要需要判断是一下是否是需要使用Search之后的视图: 1 2 3 4 5 6 7 -( NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:( NSInteger )section{ if (tableView == self .searchDisplayController.searchResultsTableView) { return [ self .searchList count]; } else { return [ self .dataList count]; } } 同样的返回单元格也有两种情况,一种是初始化数据,一种是过滤之后的数据视图: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath{ static NSString *flag=@ "cellFlag" ; UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:flag]; if (cell== nil ) { cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:flag]; } if (tableView== self .searchDisplayController.searchResultsTableView) { [cell.textLabel setText: self .searchList[indexPath.row]]; } else { [cell.textLabel setText: self .dataList[indexPath.row]]; } return cell; } UISearchBarDelegate中的开始和结束的事件: 1 2 3 4 5 6 7 8 9 - ( BOOL )searchBarShouldBeginEditing:(UISearchBar *)searchBar{ NSLog (@ "搜索Begin" ); return YES ; } - ( BOOL )searchBarShouldEndEditing:(UISearchBar *)searchBar{ NSLog (@ "搜索End" ); return YES ; } 搜索时过滤数据: 1 2 3 4 5 6 7 8 9 10 11 12 - ( BOOL )searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:( NSString *)searchString{ // 谓词的包含语法,之前文章介绍过http://www.cnblogs.com/xiaofeixiang/ NSPredicate *preicate = [ NSPredicate predicateWithFormat:@ "SELF CONTAINS[c] %@" , searchString]; if ( self .searchList!= nil ) { [ self .searchList removeAllObjects]; } //过滤数据 self .searchList= [ NSMutableArray arrayWithArray:[_dataList filteredArrayUsingPredicate:preicate]]; //刷新表格 return YES ; } 最终效果如下: UISearchController实现搜索 UISeachBar通过UISearchDisplayDelegate实现上面的效果是没有问题的,网上也有很多类似的实现效果,不过是警告的,信息如下: 'searchDisplayController' is deprecated: first deprecated in iOS 8.0,这么明显一个警告总不能视而不见吧,在StackOverFlow中发现UISearchDisplayController is deprecatedinIOS8.0, and recommended to use UISearchController instead,也就是说iOS8.0不推荐UISearchDisplayController,也就是不推荐使用UISearchDisplayDelegate,但是可以通过UISearchController实现UISearchResultsUpdating这个委托实现上面的效果; 视图中中需要声明UISearchResultsUpdating: 1 2 3 4 @interface ViewController : UITableViewController<UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate,UISearchResultsUpdating> @end 属性声明: 1 @property ( nonatomic , strong) UISearchController *searchController; 需要自己初始化一下UISearchController: 1 2 3 4 5 6 7 8 9 10 11 _searchController = [[UISearchController alloc] initWithSearchResultsController: nil ]; _searchController.searchResultsUpdater = self ; _searchController.dimsBackgroundDuringPresentation = NO ; _searchController.hidesNavigationBarDuringPresentation = NO ; _searchController.searchBar.frame = CGRectMake( self .searchController.searchBar.frame.origin.x, self .searchController.searchBar.frame.origin.y, self .searchController.searchBar.frame.size.width, 44.0); self .tableView.tableHeaderView = self .searchController.searchBar; 之前是通过判断搜索时候的TableView,不过现在直接使用self.searchController.active进行判断即可,也就是UISearchController的active属性: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 //设置区域的行数 -( NSInteger )tableView:(UITableView *)tableView numberOfRowsInSection:( NSInteger )section{ if ( self .searchController.active) { return [ self .searchList count]; } else { return [ self .dataList count]; } } //返回单元格内容 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath{ static NSString *flag=@ "cellFlag" ; UITableViewCell *cell=[tableView dequeueReusableCellWithIdentifier:flag]; if (cell== nil ) { cell=[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:flag]; } if ( self .searchController.active) { [cell.textLabel setText: self .searchList[indexPath.row]]; } else { [cell.textLabel setText: self .dataList[indexPath.row]]; } return cell; } 具体调用的时候使用的方法也发生了改变,这个时候使用updateSearchResultsForSearchController进行结果过滤: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 -( void )updateSearchResultsForSearchController:(UISearchController *)searchController { NSString *searchString = [ self .searchController.searchBar text]; NSPredicate *preicate = [ NSPredicate predicateWithFormat:@ "SELF CONTAINS[c] %@" , searchString]; if ( self .searchList!= nil ) { [ self .searchList removeAllObjects]; } //过滤数据 self .searchList= [ NSMutableArray arrayWithArray:[_dataList filteredArrayUsingPredicate:preicate]]; //刷新表格 [ self .tableView reloadData]; } 效果演示: 本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4273620.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android开发者指南(2) —— aapt

正文 使用aapt aapt是标准的Android辅助打包工具,位于SDK的tools/文件夹下。该工具允许查看、创建或更新Zip兼容格式(zip,jar,apk)的文档,并且能将资源编译到二进制格式的包中。 通常不需要直接使用aapt工具,IDE插件和编译脚本能利用它打包apk文件来合成应用程序。 详细的用法可以打开命令行终端,到tools文件夹下运行如下命令: Linux或Mac OS X: ./aapt Windows: aapt.exe 本文转自over140 51CTO博客,原文链接:http://blog.51cto.com/over140/582290,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android 项目开发基础再回顾(一)

1,主activity_splash: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/launcher_bg"//设置初始背景图片 tools:context=".SplashActivity" > <TextView android:id="@+id/tv_version_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true"#把这个textview 放到中间 android:shadowDx="1//这个指的是相对于原字体在x方向上的偏移量 android:shadowDy="1" android:shadowColor="#f00"//黑色 android:shadowRadius="1"//表示阴影的模糊程度 android:textSize="16sp" android:text="版本名称" /> <ProgressBar //加载滚动条 android:layout_below="@id/tv_version_name" android:layout_centerHorizontal="true" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout> 2,副activity_home <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:text="HomeActivity" android:textSize="20sp" android:textColor="#000" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> 3,让第二个活动可以启动 <activity android:name="com.example.moblesafe73.HomeActivity"/> 4,接下来创造两个工具类, 一个是将流转化为字符串 mport java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; public class StreamUtil { public static String StreamToString(InputStream is) { //1.在读取的过程中,将读取的内容存取到缓存中,然后一次性用字符转化成字符串 ByteArrayOutputStream bos=new ByteArrayOutputStream(); //2.读取操作,读到没有为止(循环) byte[] buffer=new byte[1024]; //3.记录读取内容的临时变量 int temp=-1; try { while((temp=is.read(buffer))!=-1){ bos.write(buffer,0,temp); } //返回读取的数据 return bos.toString(); } catch (IOException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); }finally{ try { is.close(); bos.close(); } catch (IOException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } return null; } } 另一个是可以弹出toast import android.content.Context; import android.widget.Toast; public class ToastUtils { public static void show(Context ctx,String msg){ Toast.makeText(ctx, msg, 0).show(); } } 5,主营业务的介绍: protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //去除当前activity头title requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_splash); //初始化ui initUI(); //初始化方法 initData(); } 6,关于如何初始化ui private void initUI() { // TODO 自动生成的方法存根 tv_version_name = (TextView) findViewById(R.id.tv_version_name); } 找到相应控件 private void initData() { // TODO 自动生成的方法存根 //应用版本名称 tv_version_name.setText(getVersionName()); //获取本地服务版本号 myLockVersionCode = getVersionCode(); //获取服务器版本号(客户端发请求,服务器给相应(json,xml一般用的是json)) checkVersion(); } //返回版本号 private int getVersionCode() { // TODO 自动生成的方法存根 //1,包管理者对象packagemanager PackageManager pm=getPackageManager(); //2,从包的管理者对象中,获取指定包名的基本信息(版本名称,版本号,0代表基本信息) try { PackageInfo packageinfo=pm.getPackageInfo(getPackageName(), 0); return packageinfo.versionCode; } catch (NameNotFoundException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } return 0; } 这个方法可以 再来看checkVersion();方法 如果上网的话需要用到线程方面的知识 private void checkVersion() { new Thread(){ public void run(){ //Message message=new Message(); Message msg=Message.obtain(); long startTime=System.currentTimeMillis();//程序开始的时间 try { //封装url地址 URL url=new URL("http://192.168.1.104:8080/update74.json"); //开启一个地址 HttpURLConnection connection=(HttpURLConnection)url.openConnection(); //3,设置常见的请求参数(请求头) //请求超时 connection.setConnectTimeout(2000); //读取超时 connection.setReadTimeout(2000); //默认是get请求 //connection.setRequestMethod("POST"); //获取请求响应码 if(connection.getResponseCode()==200){ //5.以流的形式,将数据保存起来 InputStream is=connection.getInputStream(); //6.将流换成字符串(工具类封装) String json=StreamUtil.StreamToString(is); Log.i(tag, json);//打印日志 //7.json解析 JSONObject jsonObject=new JSONObject(json); String versionName=jsonObject.getString("versionName"); mversionDes = jsonObject.getString("versionDes"); String versionCode=jsonObject.getString("versionCode"); mdownloadUrl = jsonObject.getString("downloadUrl"); Log.i(tag, versionName); Log.i(tag, mversionDes); Log.i(tag, versionCode); Log.i(tag, mdownloadUrl); //8,比对版本号(服务器版本号,提示用户更新) if(myLockVersionCode <Integer.parseInt(versionCode)){ //提示用户更新,弹出对话框 msg.what=UPDATE_VERSION; }else{ //进入应用程序主界面 msg.what=ENTER_HOME; } } }catch (MalformedURLException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); msg.what=URL_ERROR; }catch (IOException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); msg.what=IO_ERROR; } catch (JSONException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); msg.what=JSON_ERROR; }finally{ //请求网络的时长超过四秒则不做处理 //请求小于四秒,强制让其睡眠四秒 long endTime=System.currentTimeMillis(); if(endTime-startTime<4000) { try { Thread.sleep(4000-(endTime-startTime)); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } mhandler.sendMessage(msg); } }; }.start(); 对上述信息进行相关的处理: private Handler mhandler=new Handler(){ public void handleMessage(android.os.Message msg){ switch(msg.what){ case UPDATE_VERSION: //弹出对话框,提示用户更新 showUpdateDialog();//弹出一个对话框,让我们进行更新 break; case ENTER_HOME: enterHome(); break; case IO_ERROR: ToastUtils.show(getApplicationContext(), "IO异常"); enterHome(); break; case URL_ERROR: ToastUtils.show(getApplicationContext(), "url异常"); enterHome(); break; case JSON_ERROR: ToastUtils.show(getApplicationContext(), "URL异常");//SplashActivity.this enterHome(); break; } } }; protected void showUpdateDialog() { // TODO 自动生成的方法存根 //对话框是依赖activity存在的 Builder builder = new AlertDialog.Builder(this);//必须用this,而不是getApplicationContext() builder.setIcon(R.drawable.ic_launcher); builder.setTitle("版本更新"); //设置描述内容 builder.setMessage(mversionDes);//这个描述内容见上文是由其发送过来的 //积极按钮,立即更新 builder.setPositiveButton("立即更新", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //下载apk,apk链接地址,downloadUrl downloadApk(); } });//创建两个按钮监听器 builder.setNegativeButton("稍后再说", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //取消对话框,进入主界面 enterHome(); } }); builder.show(); } 接下来是对文件进行下载 protected void downloadApk() { //apk下载链接地址,放置apk的所在路径 //1,判断sd卡是否可用,是否挂在上 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){ //2,获取sd卡路径 String path=Environment.getExternalStorageDirectory().getAbsolutePath() +File.separator+"mobilesafe73.apk"; //发送请求,获取sdk,并且添加到指定路径 HttpUtils httpUtils=new HttpUtils(); //发送请求,传递参数吧(下载应用放置的位置) httpUtils.download(mdownloadUrl, path,new RequestCallBack<File>() {//mdownloadUrl刚才所获得的下载的地址 @Override public void onSuccess(ResponseInfo<File> responseInfo) { Log.i(tag, "下载成功"); // TODO 自动生成的方法存根 File file=responseInfo.result; //提示用户安装 installAPK(file); } @Override public void onFailure(HttpException arg0, String arg1) { Log.i(tag, "下载失败"); // TODO 自动生成的方法存根 } @Override public void onStart() { // TODO 自动生成的方法存根 Log.i(tag, "开始下载"); super.onStart(); } @Override public void onLoading(long total, long current, boolean isUploading) { // TODO 自动生成的方法存根 Log.i(tag, "下载中........"); Log.i(tag, "total = "+total); Log.i(tag, "current = "+current); super.onLoading(total, current, isUploading); } }); } } //开始安装 protected void installAPK(File file) { // TODO 自动生成的方法存根 //系统应用界面,源码,安装apk入口 Intent intent = new Intent("android.intent.action.VIEW"); intent.addCategory("android.intent.category.DEFAULT"); /*//文件作为数据源 intent.setData(Uri.fromFile(file)); //设置安装的类型 intent.setType("application/vnd.android.package-archive");*/ intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive"); // startActivity(intent); startActivityForResult(intent, 0); } //开启另一个界面 protected void enterHome() { Intent intent = new Intent(this,HomeActivity.class); startActivity(intent); //在开启一个新的界面后将导航界面关闭,因为导航界面只可见一次 finish(); } 本文转自眉间雪 51CTO博客,原文链接:http://blog.51cto.com/13348847/2046800,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android开发之如何实现日历控件

我们大家都知道,在Android平台3.0中才新增了日历视图控件,可以显示网格状的日历内容,那么对于3.0以下的版本要使用日历控件只能借助第三方,目前用的最多的是CalendarView。 先简单介绍下CalendarView日历控件的使用。 android.widget.CalendarView是从android.widget.FrameLayout中继承。 CalendarView 类提供了基本的日历设置方法: long getDate() 获取从1970年,1月1日,0点0分0秒到现在的毫秒数,因为返回是long型最终只能截止到2038年 int getFirstDayOfWeek() //获取当天是本周的第几天,Android123提示返回的定义在java.util.Calendar类中,比如Calendar.Monday为星期一,定义值为2。 long getMaxDate() //获取CalendarView支持1970年到那天的最大天数 long getMinDate() //获取CalendarView支持1970年到那天的最小天数 boolean getShowWeekNumber() //获取是否显示星期号 boolean isEnabled() //是否显示本日历视图 public void setDate (long date, boolean animate, boolean center) //设置选择日期到1970年的描述 void setDate(long date) //设置选择的日期描述到1970年 void setEnabled(boolean enabled) //设置是否启用视图 void setFirstDayOfWeek(int firstDayOfWeek) //设置本周起始天数 void setMaxDate(long maxDate) void setMinDate(long minDate) void setOnDateChangeListener(CalendarView.OnDateChangeListener listener) //日历视图修改的接口,这个介绍看下面。 void setShowWeekNumber(boolean showWeekNumber) //设置是否显示周号 有关日历控件CalendarView的设置接口 android.widget.CalendarView.OnDateChangeListener 只实现了一个回调方法void onSelectedDayChange(CalendarView view, int year, int month, int dayOfMonth)。 这四个参数的具体介绍为 view The view associated with this listener. year The year that was set. month The month that was set [0-11]. dayOfMonth The day of the month that was set. 下面给大家展示这几种有用的日历控件效果图: 这是CalendarView的效果图。可以实现上月和下月翻页,设置事件等。 这个日历控件也比较强大,但外观不够友好。 这是我们自己实现的日历控件。可以通过选择日期查询相关数据等操作。 这是Android3.0及以上版本自带的日历控件。 本文转自 wws5201985 51CTO博客,原文链接:http://blog.51cto.com/wws5201985/818593,如需转载请自行联系原作者

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册