首页 文章 精选 留言 我的

精选列表

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

Android应用开发—setResult()的调用时机

本文转载自setResult()的调用时机,此处做了重新的排版,只是感觉markdown的排版比较好看些,侵删。 今天遇到这样一个问题,我在Activity-A中用startActivityForResult()方法启动了Activity-B,并且在B中通过setResult()方法给A返回值,由于某些原因不能在setResult()之后立刻调用finish()函数,只能通过用户按Back键自己退出到A。按理说从B退出回到Aactivity-A过程中,A中的 onActivityResult() 应该被调用, 可是通过log发现,整个操作过程中 onActivityResult() 始终没有被调用。 前后研究了半天才发现 是 setResult() 的调用时机不对造成的,因为在我是在B的onStop() 函数中调用setResult()函数的,这个时候的seResult是没有任何意义的,因为已经错过了A onActivityResult() 的调用时机。 因为在 B 退回 A过程中,执行过程是 B---onPause A---onActivityResult A---onRestart A---onStart A---onResume B---onStop B---onDestroy 从上面过程可以看出,首先是B处于Pause 状态,然后等待A执行 onRestart-> onStart ->onResume,然后才是B 的onStop->onDestroy,而A的 onActivityResult() 需要在B的onPause之后,A的onRestart之前这中间调用,所以B中的setResult()函数应该放在B的onPause之前调用。 另外我试验了一下,如果把setResult()放在 B 的 onPause() 里面调用,结果仍然是无效的。 那么setResult()应该在什么时候调用呢?从源码可以看出,Activity返回result是在被finish的时候,也就是说调用setResult()方法必须在finish()之前。所以在onPause、onStop、onDestroy方法中调用setResult()也有可能不会返回成功,因为这些方法调用不一定是在finish之前的 (why,to find out the reason),当然在onCreate()就调用setResult肯定是在finish之前的,但是又不满足业务需要。 实际使用场景有两个: 按BACK键从一个Activity退出来的,一按BACK,android就会自动调用Activity的finish()方法。 @Override public void onBackPressed() { Log.i(TAG, "onBackPressed"); setResult(Const.LIVE_OK); super.onBackPressed(); } 按点击事件中显式的调用finish() setResult(RESULT_OK); finish(); 执行过程为: B---onBackPressed B---finish B---onPause A---onActivityResult A---onRestart A---onStart A---onResume B---onStop B---onDestroy

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

Android开发实践:利用ProGuard进行代码混淆

由于Android的代码大都是Java代码,所以挺容易被反编译的,好在Android ADT为我们集成了混淆代码的工具,一来可以混淆我们的代码,让程序被反编译后基本看不懂,另外还能起到代码优化的作用。发布项目前,建议打开Android的代码混淆功能。 Android ADT主要通过ProGuard工具来提供代码混淆,网上也有挺多博客文章讲这个的,但感觉很多都介绍得太过于复杂,这里我就以问答的方式来更加简洁地介绍下ProGuard吧。 1. ProGuard是什么 ProGuard是一个工具,用来混淆和优化Java代码。 工作方式:移除无效的代码,将代码中的类名、函数名替换为晦涩难懂的名字。 注意,它只能混淆Java代码,Android工程中Native代码,资源文件(图片、xml),它是无法混淆的。 2. 如何开启ProGuard 修改Android工程根目录下的project.properties文件,把proguard.config=....这一行前面的注释“#”去掉。 这一行指定了系统默认的proguard配置文件,位于Android SDK/tools/proguard目录下。 当然,你也可以自己编写配置文件,但不建议这样做,因此系统默认的配置已经涵盖了许多通用的细节,如果你还有额外的配置,可以添加在 proguard-project.txt 文件中。 注意: 只有在生成release版本的apk时,混淆配置才会起作用,debug版本的apk不会进行混淆。 3. 哪些内容需要手动配置 系统默认的配置已经涵盖了大部分的内容,但是如果你的工程中有如下内容,则需要手动添加配置到proguard-project.txt文件中。 (1) 只在 AndroidManifest.xml 引用的类 (2) 通过JNI回调方式被调用的函数 (3) 运行时动态调用的函数或者成员变量 (4) 当然,如果你不确定哪些需要手动配置,可以以默认的配置生成程序,当运行中发现ClassNotFoundException异常时,即可找到哪个类不该被混淆。 4. 手动配置的规则 手动添加的配置,一般以“-keep”开头,常用的配置命令分别示例如下: 假设Android工程中有一个接口和一个类: 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 package com.ticktick.example; public interface TestInterface{ public void test(); } public class Test{ private StringmTestString; private final int mMinValue; private final int mMaxValue; public Test( int min, int max){ mMinValue=min; mMaxValue=max; } public int getMinValue(){ return mMinValue; } public int getMaxValue(){ return mMaxValue; } public void setTestString(StringtestStr){ mTestString=testStr; } } (1) 不混淆某个类的构造函数 例如:不混淆Test类的构造函数: 1 2 3 4 -keepclassmembers class com.ticktick.example.Test{ public <init>( int , int ); } (2) 不混淆某个包所有的类或指定的类 例如,不混淆package com.ticktick.example下的所有类/接口 1 -keep class com.ticktick.example.**{*;} 例如,不混淆com.ticktick.example.Test类: 1 -keep class com.ticktick.example.Test{*;} 如果希望不混淆某个接口,则把上述命令中的class替换为interface即可。 (3) 不混淆某个类的特定的函数 例如:不混淆com.ticktick.example.Test类的setTestString函数: 1 2 3 4 -keepclassmembers class com.ticktick.example.Test{ public void setTestString(java.lang.String); } (4) 不混淆某个类的子类,某个接口的实现 例如:不混淆com.ticktick.example.Test类的子类 1 -keep public class * extends com.ticktick.example.Test 例如:不混淆com.ticktick.example.TestInterface的实现 1 2 3 -keep class *implementscom.ticktick.example.TestInterface{ public static final com.ticktick.example.TestInterface$Creator*; } (5) 添加第三方依赖包 例如:添加android-support-v4.jar依赖包 1 2 3 4 5 6 -libraryjars libs/android-support-v4.jar -dontwarn android.support.v4.**{*;} -keep class android.support.v4.**{*;} -keep interface android.support.v4.**{*;} 注意: 需要添加dontwarn,因为默认情况下proguard会检查每一个引用是否正确,但是第三方库里往往有些不会用到的类,没有正确引用,所以如果不配置的话,系统会报错。 5. 混淆后的调试信息解析 当代码混淆之后,输出的Log信息也会带有混淆内容,比如函数名和类名会被替换为晦涩难懂的名字,而与代码中的不一致。 因此,ProGuard工具还提供了恢复混淆内容的工具和文件。 当你开启了ProGuard混淆后,每次生成release版的apk时,Andriod工程的根目录下会对应生成一个proguard文件夹,该文件夹下的mapping.txt文件记录了混淆后的名字与混淆前的名字的对应关系,通过该文件,我们反向得到恢复后的Log信息。 假设Log文件名为log.txt,则恢复混淆的命令为: 1 $retrace.sh-verbosemapping.txtlog.txt 注1:retrace.sh命令位于 <sdk_root>/tools/proguard/目录下 注2:你需要保存每一个release版本的mapping.txt,因为每一次release的混淆结果和映射关系都不一样。 本文转自 Jhuster 51CTO博客,原文链接:http://blog.51cto.com/ticktick/1413066,如需转载请自行联系原作者

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

Android开发实践:为什么要继承onMeasure()

首先,我们写一个自定义View,直接调用系统默认的onMeasure函数,看看会是怎样的现象: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.titcktick.customview; import android.content.Context; import android.util.AttributeSet; import android.view.View; public class CustomView extends View{ public CustomView(Contextcontext){ super (context); } public CustomView(Contextcontext,AttributeSetattrs){ super (context,attrs); } @Override protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec){ super .onMeasure(widthMeasureSpec,heightMeasureSpec); } } 1. 父控件使用match_parent,CustomView使用match_parent 1 2 3 4 5 6 7 8 9 10 11 12 13 <LinearLayoutxmlns: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:orientation= "vertical" > <com.titcktick.customview.CustomView android:layout_width= "match_parent" android:layout_height= "match_parent" android:layout_margin= "10dp" android:background= "@android:color/black" /> </LinearLayout> 这里加了10dp的margin并且把View的背景设置为了黑色,是为了方便辨别我们的CustomView,效果如下: 我们可以看到,默认情况下,如果父控件和CustomView都使用match_parent,则CustomView会充满父控件。 2. 父控件使用match_parent,CustomView使用wrap_content 把layout文件中,CustomView的layout_width/layout_height替换为wrap_content,你会发现,结果依然是充满父控件。 3. 父控件使用match_parent,CustomView使用固定的值 把layout文件中,CustomView的layout_width/layout_height替换为50dp,你会发现,CustomView的显示结果为50dpx50dp,如图所示: 4. 父控件使用固定的值,CustomView使用match_parent或者wrap_content 那么,如果把父控件的layout_width/layout_height替换为50dp,CustomView设置为match_parent或者wrap_content,你会发现,CustomView的显示结果也是为50dpx50 dp。 5 结论 如果自定义的CustomView采用默认的onMeasure函数,行为如下: (1) CustomView设置为 match_parent 或者 wrap_content 没有任何区别,其显示大小由父控件决定,它会填充满整个父控件的空间。 (2) CustomView设置为固定的值,则其显示大小为该设定的值。 如果你的自定义控件的大小计算就是跟系统默认的行为一致的话,那么你就不需要重写onMeasure函数了。 6. 怎样编写onMeasure函数 系统默认的onMeasure函数的行为就讨论到这,下面也说说怎样重写onMeasure函数,以及onMeasure函数的基本原理,关键部分在代码中以注释的形式给出了,仅供参考: 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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 package com.titcktick.customview; import android.content.Context; import android.util.AttributeSet; import android.view.View; public class CustomView extends View{ private static final int DEFAULT_VIEW_WIDTH= 100 ; private static final int DEFAULT_VIEW_HEIGHT= 100 ; public CustomView(Contextcontext){ super (context); } public CustomView(Contextcontext,AttributeSetattrs){ super (context,attrs); } @Override protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec){ int width=measureDimension(DEFAULT_VIEW_WIDTH,widthMeasureSpec); int height=measureDimension(DEFAULT_VIEW_HEIGHT,heightMeasureSpec); setMeasuredDimension(width,height); } protected int measureDimension( int defaultSize, int measureSpec){ int result=defaultSize; int specMode=MeasureSpec.getMode(measureSpec); int specSize=MeasureSpec.getSize(measureSpec); //1.layout给出了确定的值,比如:100dp //2.layout使用的是match_parent,但父控件的size已经可以确定了,比如设置的是具体的值或者match_parent if (specMode==MeasureSpec.EXACTLY){ result=specSize; //建议:result直接使用确定值 } //1.layout使用的是wrap_content //2.layout使用的是match_parent,但父控件使用的是确定的值或者wrap_content else if (specMode==MeasureSpec.AT_MOST){ result=Math.min(defaultSize,specSize); //建议:result不能大于specSize } //UNSPECIFIED,没有任何限制,所以可以设置任何大小 //多半出现在自定义的父控件的情况下,期望由自控件自行决定大小 else { result=defaultSize; } return result; } } 这样重载了onMeasure函数之后,你会发现,当CustomView使用match_parent的时候,它会占满整个父控件,而当CustomView使用wrap_content的时候,它的大小则是代码中定义的默认大小100x100像素。当然,你也可以根据自己的需求改写measureDimension()的实现。 本文转自 Jhuster 51CTO博客,原文链接:http://blog.51cto.com/ticktick/1540134,如需转载请自行联系原作者

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

DLNA&UPnP开发笔记(2)

1. UPnP协议组成 UPnP协议中,定义了两个主要的组件,一个是设备(Device),一个是控制点(Control Point)。这就是为什么很多UPnP协议栈的SDK的接口代码一般都主要由Device和Control Point构成。设备是在网络中可见的对象,而控制点在网络中不可见。 一个UPnP的设备(Device)是不能直接访问和控制另一个UPnP的设备(Device)的,对设备的访问和控制都必须通过控制点(Control Point)来代为完成。而控制点对设备的控制则主要是由设备定义的“服务”(Service)来实现。 设备(Device)需要向网络中广播自己的信息,并提供设备描述和服务(Service)描述,并发送设备事件消息. 控制点(Control Point)则是搜索设备,并使用其提供的服务(Service)访问和控制设备,同时监听设备事件消息。 2. 典型的UPnP AV应用架构 如图所示是一种典型的UPnP AV应用架构,它来自《UPnP-av-AVArchitecture》。在一个典型的UPnP应用中,有三个主体,一个服务器(MediaServer),一个播放器(MediaRender),以及一个控制点(Control Point)。 服务器(MediaServer)主要负责提供多媒体文件的浏览和控制。 播放器(MediaRender)主要负责提供播放和渲染。 控制点(Control Point)则控制整个播放过程。 它们三个在物理上可以是同一个设备,当然,也可以在不同的设备上。 对应到UPnP协议组件的话,“MediaServer”和“MediaRnederer”都属于UPnP的Device。 “ContentDirectory”、“ConnectionManager”、“AVTransport”、“RenderingControl”这些都属于UPnP设备所提供的服务(Service),通过这些服务描述,Control Point就知道该如何访问和控制设备了。 3. UPnP的设备描述和服务描述 UPnP的设备(Device)是通过广播包来通知局域网中的控制点自己的设备信息和服务的,而这些设备信息和服务都必须根据UPnP协议规定的XML文档格式来编写,UPnP提供了标准的模板可以参考,具体的文档地址: http://upnp.org/sdcps-and-certification/standards/sdcps/ 由这些文档我们可以看到,UPnP官网为我们定义了12种设备,在每种设备的文档中详细地定义了设备描述XML如何编写,定义了每种设备需要实现哪些服务,每种服务的XML文档如何编写。 到这里,我们其实可以看到,实现一个上述的UPnP AV应用也并没有那么可怕,一切都是有章可循的,我们需要做的就是熟读协议所定义了一系列文档。 本文转自 Jhuster 51CTO博客,原文链接:http://blog.51cto.com/ticktick/1637727,如需转载请自行联系原作者

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

Android开发学习笔记:Spinner和AutoCompleteTextView浅析

一.Spinner的简介与创建 1.Spinner的简介 Spinner(下拉列表)是一个每次只能选择所有项中一项的控件,相当于Html中的下拉列表框。它的继承关系如下: java.lang.Object ↳ android.view.View ↳ android.view.ViewGroup ↳ android.widget.AdapterView<T extends android.widget.Adapter> ↳ android.widget.AbsSpinner ↳ android.widget.Spinner Spinner常用的XML属性: 属性名称 描述 android:prompt 该提示在下拉列表对话框显示时显示。(译者注:对话框的标题: 2.创建使用Spinner的步骤如下: ①需要在布局中定时Spinner组件,然后向Spinner添加需要选择的数据 ②设置事件监听器setOnItemSelectedListener( )并实现onItemSelected( ) 3.Spinner添加数据的两种方法: ①在Java代码中载入列表数据 具体的例子如下: MainActivity.java packagecom.android.spinner; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.View; importandroid.widget.AdapterView; importandroid.widget.ArrayAdapter; importandroid.widget.Spinner; importandroid.widget.TextView; publicclassMainActivityextendsActivity{ privatestaticfinalString[]province={"广东","广西","湖南","河南","福建"}; privateTextViewtext; privateSpinnerspinner; privateArrayAdapter<String>adapter; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); text=(TextView)findViewById(R.id.text); spinner=(Spinner)findViewById(R.id.spinner); //将Spinner里面的可选择内容通过ArrayAdapter连接起来 adapter=newArrayAdapter<String>(this,android.R.layout.simple_spinner_item,province); //设置Spinner的样式 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); //为对话框设置标题 //也可在XMl文件中通过“android:prompt”设置 spinner.setPrompt("你来自哪个省"); //为Spinner设置适配器 spinner.setAdapter(adapter); //添加Spinner事件监听 spinner.setOnItemSelectedListener(newSpinner.OnItemSelectedListener(){ @Override publicvoidonItemSelected(AdapterView<?>arg0,Viewarg1, intarg2,longarg3){ //TODOAuto-generatedmethodstub text.setText("你所在的城市是:"+province[arg2]); //设置显示当前选择的项 arg0.setVisibility(View.VISIBLE); } @Override publicvoidonNothingSelected(AdapterView<?>arg0){ //TODOAuto-generatedmethodstub } }); } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="10dip" android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="10dip" android:text="@string/planet_prompt" /> <Spinner android:id="@+id/spinner" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> strings.xml <?xmlversion="1.0"encoding="utf-8"?> <resources> <stringname="planet_prompt">你来自的省份是:</string> <stringname="app_name">测试Spinner</string> </resources> 效果图: ②在XML文件中定义列表的数据 具体的例子如下: MainActivity.java packagecom.android.spinner; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.View; importandroid.widget.AdapterView; importandroid.widget.AdapterView.OnItemSelectedListener; importandroid.widget.ArrayAdapter; importandroid.widget.Spinner; importandroid.widget.Toast; publicclassMainActivityextendsActivity{ @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); Spinnerspinner=(Spinner)findViewById(R.id.spinner); ArrayAdapter<CharSequence>adapter=ArrayAdapter.createFromResource( this,R.array.province, android.R.layout.simple_spinner_item); //调用setDropDownViewResource方法,以XML的方式定义下拉菜单要显示的样式 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); //为spinner设置适配器 spinner.setAdapter(adapter); spinner.setOnItemSelectedListener(newMyOnItemSelectedListener()); } publicclassMyOnItemSelectedListenerimplementsOnItemSelectedListener{ publicvoidonItemSelected(AdapterView<?>parent,Viewview,intpos,longid){ Toast.makeText(parent.getContext(),"你来自的省份是:"+ parent.getItemAtPosition(pos).toString(),Toast.LENGTH_LONG).show(); } publicvoidonNothingSelected(AdapterView<?>parent){ //TODOAuto-generatedmethodstub } } } main.xml <?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="10dip" android:layout_width="fill_parent" android:layout_height="wrap_content" > <TextView android:id="@+id/text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="10dip" android:text="@string/planet_prompt" /> <Spinner android:id="@+id/spinner" android:layout_width="fill_parent" android:layout_height="wrap_content" android:prompt="@string/planet_prompt" /> </LinearLayout> strings.xml <?xmlversion="1.0"encoding="utf-8"?> <resources> <stringname="planet_prompt">你来自的省份是</string> <stringname="app_name">测试Spinner</string> <string-arrayname="province"> <item>广东</item> <item>广西</item> <item>湖南</item> <item>河南</item> <item>福建</item> </string-array> </resources> 效果图: 二.AutoCompleteTextView简介 我们平常上网的时候经常会用到Google或百度,在输入框中输入类似”51CTO“,和51CTO相关的信息就会被列出来,供用户选择,非常方便。这种效果在Android中是用AutoCompleteTextView实现的。在AutoCompleteTextView中,主要是设置想显示资源的适配器(Adapter)。 AutoCompleteTextView有三个重要的方法clearListSelection():清除选中的列表项、dismissDropDown():如果存在关闭下拉菜单、getAdapter():获取适配器。 具体的例子如下: MainActivity.java packagecom.android.autocomplete; importandroid.app.Activity; importandroid.os.Bundle; importandroid.widget.ArrayAdapter; importandroid.widget.AutoCompleteTextView; publicclassMainActivityextendsActivity{ privateAutoCompleteTextViewatv; //创建字符串数组 privatestaticfinalString[]strs={"an","and","android","abc","abcdef"}; @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); atv=(AutoCompleteTextView)findViewById(R.id.AutoCompleteTextView1); //创建适配器 ArrayAdapter<String>adapter=newArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line,strs); //为AutoCompleteTextView设置适配器 atv.setAdapter(adapter); } } 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" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="自动完成文本框" /> <AutoCompleteTextView android:id="@+id/AutoCompleteTextView1" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout> 效果图: 本文转自 lingdududu 51CTO博客,原文链接:http://blog.51cto.com/liangruijun/652801

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

iOS开发-UIWebView加载本地和网络数据

UIWebView是内置的浏览器控件,可以用它来浏览网页、打开文档,关于浏览网页榜样可以参考UC,手机必备浏览器,至于文档浏览的手机很多图书阅读软件,UIWebView是一个混合体,具体的功能控件内置的,实现一些基本的功能。UIWebView可以查看Html网页,pdf文件,docx文件,txt文件文件,系统自带的Safari就是UIWebView实现的。 基础布局 页面布局很简单就是一个文本框,一个按钮,一个UIWebView,页面布局如下: 如果想简单一点的话,其实用UIWebView也行,不过需要先准备一些文本数据,具体如下: 数据加载 ①直接拼接Html,用UIWebView显示,viewDidLoad中添加代码: 1 2 3 //直接加载Html字符串 NSString *htmlStr=@ "<html><head><title>Html加载</title></head><body>HtmlDemo-FlyElephant</body></html>" ; [ self .webView loadHTMLString:htmlStr baseURL: nil ]; ②加载本地的Html网页,Book.html中代码: 1 2 3 4 5 6 7 8 9 10 <!DOCTYPE html> <html> <head> <meta charset= "UTF-8" > <title>书籍</title> </head> <body> 少年维特之烦恼-歌德 </body> </html> viewDidLoad代码: 1 2 3 NSString *filePath = [[ NSBundle mainBundle]pathForResource:@ "Book" ofType:@ "html" ]; NSString *htmlString = [ NSString stringWithContentsOfFile:filePath encoding: NSUTF8StringEncoding error: nil ]; [ self .webView loadHTMLString:htmlString baseURL:[ NSURL URLWithString:filePath]]; ③加载本地的pdf文件,viewDidLoad代码: 1 2 3 4 5 NSURL *url = [[ NSBundle mainBundle]URLForResource:@ "Book.pdf" withExtension: nil ]; NSURLRequest *request = [ NSURLRequest requestWithURL:url]; [ self .webView loadRequest:request]; 加载pdf的第二种方式: 1 2 3 4 5 6 NSString *path = [[ NSBundle mainBundle]pathForResource:@ "Book.pdf" ofType: nil ]; //以二进制的形式加载数据 NSData *data = [ NSData dataWithContentsOfFile:path]; [ self .webView loadData:data MIMEType:@ "application/pdf" textEncodingName:@ "UTF-8" baseURL: nil ]; ④加载本地txt文件,viewDidLoad代码如下: 1 2 3 4 //加载txt NSURL *url = [[ NSBundle mainBundle]URLForResource:@ "Book.txt" withExtension: nil ]; //设置Url [ self .webView loadRequest:[ NSURLRequest requestWithURL:url]]; ⑤加载Word,viewDidLoad代码如下: 1 2 3 4 //加载Word NSURL *url = [[ NSBundle mainBundle]URLForResource:@ "Book.docx" withExtension: nil ]; //设置加载Url [ self .webView loadRequest:[ NSURLRequest requestWithURL:url]]; ⑥加载网络数据,跳转按钮事件中实现如下: 1 2 NSURLRequest *request =[ NSURLRequest requestWithURL:[ NSURL URLWithString: self .urlText.text]]; [ self .webView loadRequest:request]; ⑦设置委托,在不同的阶段处理数据,实现UIWebViewDelegate,设置自己本身为委托对象; 1 [ self .webView setDelegate: self ]; 常用的三个方法: 1 2 3 4 5 6 7 8 9 10 11 12 //加载开始 - ( void )webViewDidStartLoad:(UIWebView *)webView{ NSLog (@ "加载开始的时候的方法调用" ); } //加载完成 -( void )webViewDidFinishLoad:(UIWebView *)webView{ NSLog (@ "加载完成的时候电脑方法调用" ); } //加载出错 - ( void )webView:(UIWebView *)webView didFailLoadWithError:( NSError *)error{ NSLog (@ "加载出错的时候的调用" ); } 本文转自Fly_Elephant博客园博客,原文链接:http://www.cnblogs.com/xiaofeixiang/p/4307573.html,如需转载请自行联系原作者

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

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

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

用户登录
用户注册