前言:
该技术前提是 已经掌握一定程度的mvvmlight for win8 技巧
实现思路:
通过Messenger 机制 动态发送导航参数 到 需要导航的page 完成导航
导航参数:
public class NavigateParameter
{
private string pageType;
public string PageType
{
get { return pageType; }
set { pageType = value; }
}
private object parameter;
public object Parameter
{
get { return parameter; }
set { parameter = value; }
}
}
在 OnNavigated 到首页的地方 加入以下方法 注册 该处理通道
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
this.prContent.IsIndeterminate = true;
this.ContentFrame.Navigate(typeof(MainPage));
this.TopFrame.Navigate(typeof(VideosPage));
#region Messengers 消息处理中心
Messenger.Default.Register<NavigateParameter>(this, "MenuNavigate", async s =>
{
var type = await Task.Run<Type>(() =>
{
var fullName = "IntTourism.View." + s.PageType;
return Type.GetType(fullName);
});
if (null != s.Parameter)
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
this.ContentFrame.Navigate(type, s.Parameter));
else
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
this.ContentFrame.Navigate(type));
});
Messenger.Default.Register<NavigateParameter>(this, "TopFrameNavigate", async s =>
{
var type = await Task.Run<Type>(() =>
{
var fullName = "IntTourism.View." + s.PageType;
return Type.GetType(fullName);
});
await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
{
if (!TopFrame.CurrentSourcePageType.Equals(type))
if (null != s.Parameter)
this.TopFrame.Navigate(type, s.Parameter);
else
this.TopFrame.Navigate(type);
});
});
#endregion
}
Unloaded 注销
private void LayoutAwarePage_Unloaded(object sender, RoutedEventArgs e)
{
Messenger.Default.Unregister<NavigateParameter>(this, "MenuNavigate");
Messenger.Default.Unregister<LogBean>(this, "LogError");
Messenger.Default.Unregister<LogBean>(this, "TopBusy");
Messenger.Default.Unregister<LogBean>(this, "ContentBusy");
Messenger.Default.Unregister<LogBean>(this, "TopFrame");
this.btnCancel.PointerPressed -= SendError;
this.btnSend.PointerPressed -= SendError;
}
以下为xaml 里 gridview 菜单的binding方式
注意:ItemClick 此处通过eventTocommand 将事件与 viewmodel中相应的命令进行了binding处理 请结合我上一篇文章 对EventTocomand这一概念进行理解
<common:LayoutAwarePage x:
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="using:IntTourism.Com.Transvalue.Tools"
xmlns:ignore="http://www.ignore.com"
xmlns:common="using:IntTourism.Common"
xmlns:cmd="using:IntTourism"
mc:Ignorable="d ignore"
d:DesignHeight="1080"
d:DesignWidth="1080"
DataContext="{Binding Main, Source={StaticResource Locator}}"
NavigationCacheMode="Required">
<Viewbox>
<Grid Width="1080" Height="1080" x:Name="root">
<GridView HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="1080"
Height="1080"
CanDragItems="false"
IsRightTapEnabled="False"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
IsSwipeEnabled="False"
x:Name="gv"
ItemsSource="{Binding MenuItems}"
SelectionMode="None"
>
<GridView.Transitions>
<TransitionCollection>
<EntranceThemeTransition/>
</TransitionCollection>
</GridView.Transitions>
<GridView.ItemContainerTransitions>
<TransitionCollection>
<EntranceThemeTransition/>
</TransitionCollection>
</GridView.ItemContainerTransitions>
<GridView.HeaderTransitions>
<TransitionCollection>
<EntranceThemeTransition/>
</TransitionCollection>
</GridView.HeaderTransitions>
<GridView.ItemTemplate>
<DataTemplate>
<GridViewItem>
<Image Height="280" Width="280" Source="{Binding IconUrl}"/>
<i:EventToCommandCollection.Items>
<i:EventToCommand Command="{Binding MenuCMD}"
CommandParameter="{Binding NavigateParameter}"
NavigateUrl="{Binding NavigateUrl}"
Event="ItemClick"/>
</i:EventToCommandCollection.Items>
</GridViewItem>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,80,0"
ItemWidth="300" ItemHeight="300" MaximumRowsOrColumns="10"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</Grid>
</Viewbox>
</common:LayoutAwarePage>
下面这一段是ViewModel中对命令的处理,以及菜单的动态加载
using GalaSoft.MvvmLight;
using IntTourism.Com.Transvalue.Service;
using GalaSoft.MvvmLight.Command;
using System.Diagnostics;
using Windows.UI.Xaml.Controls;
using System.Collections;
using System.Collections.ObjectModel;
using IntTourism.Com.Transvalue.Model;
using GalaSoft.MvvmLight.Messaging;
using System;
using System.ComponentModel;
using System.Collections.Generic;
using IntTourism.Com.Transvalue.Bean;
using IntTourism.Com.Transvalue.Tools;
using IntTourism.Com.Transvalue.Const;
using System.Threading.Tasks;
namespace IntTourism.ViewModel
{
/// <summary>
/// This class contains properties that the main View can data bind to.
/// <para>
/// See http://www.galasoft.ch/mvvm
/// </para>
/// </summary>
public class MainViewModel : ViewModelBase
{
private readonly IMainPageSerivce _dataService;
#region Command
private RelayCommand<ExCommandParameter> _menuCMD;
/// <summary>
/// Gets the MenuCMD.
/// </summary>
public RelayCommand<ExCommandParameter> MenuCMD
{
get
{
return _menuCMD ?? (_menuCMD = new RelayCommand<ExCommandParameter>(
ExecuteMenuCMD,
CanExecuteMenuCMD));
}
}
private async void ExecuteMenuCMD(ExCommandParameter url)
{
await Task.Run(() =>
{
var nav = new NavigateParameter();
nav.Parameter = url.Parameter;
nav.PageType = url.NavigateUrl;
if (null != url.NavigateUrl)
{
Messenger.Default.Send<bool>(true, "ContentBusy");
Messenger.Default.Send<NavigateParameter>(nav, "MenuNavigate");
}
});
}
private bool CanExecuteMenuCMD(ExCommandParameter url)
{
if (null != url && !"".Equals(url))
return true;
else return false;
}
#endregion
#region DataProperties
#region MenuItems
/// <summary>
/// The <see cref="MenuItems" /> property's name.
/// </summary>
public const string MenuItemsPropertyName = "MenuItems";
private ObservableCollection<MenuItem> _menuItems;
/// <summary>
/// Sets and gets the MenuItems property.
/// Changes to that property's value raise the PropertyChanged event.
/// This property's value is broadcasted by the MessengerInstance when it changes.
/// </summary>
public ObservableCollection<MenuItem> MenuItems
{
get
{
return _menuItems;
}
set
{
if (_menuItems == value)
{
return;
}
RaisePropertyChanging(() => MenuItems);
var oldValue = _menuItems;
_menuItems = value;
RaisePropertyChanged(() => MenuItems, oldValue, value, true);
}
}
#endregion
/// <summary>
/// The <see cref="WelcomeTitle" /> property's name.
/// </summary>
public const string WelcomeTitlePropertyName = "WelcomeTitle";
private string _welcomeTitle;
/// <summary>
/// Sets and gets the WelcomeTitle property.
/// Changes to that property's value raise the PropertyChanged event.
/// This property's value is broadcasted by the MessengerInstance when it changes.
/// </summary>
public string WelcomeTitle
{
get
{
return _welcomeTitle;
}
set
{
if (_welcomeTitle == value)
{
return;
}
RaisePropertyChanging(WelcomeTitlePropertyName);
var oldValue = _welcomeTitle;
_welcomeTitle = value;
RaisePropertyChanged(WelcomeTitlePropertyName, oldValue, value, true);
}
}
#endregion
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel(IMainPageSerivce dataService)
{
_dataService = dataService;
InitPropertyChanged();
_dataService.GetItemData(
async (items, error) =>
{
if (await Pollute.ReportError(error, "GetItemData", ErrorDesc._E01))
{
Messenger.Default.Send<bool>(false, "ContentBusy");
return;
}
var data = await items;
foreach (var item in data)
item.MenuCMD = MenuCMD;
MenuItems = data;
Messenger.Default.Send<bool>(false, "ContentBusy");
});
}
#region PropertyChangeMethods
/// <summary>
/// 初始化相关方法
/// </summary>
private void InitPropertyChanged()
{
PropertyChanging += PropertyChangingMethod;
PropertyChanged += PropertyChangedMethod;
}
//private static Dictionary<Predicate<string>, Action> PropertyChangingActions;
//private static Dictionary<Predicate<string>, Action> PropertyChangedActions;
private void PropertyChangedMethod(object sender, PropertyChangedEventArgs e)
{
}
private void PropertyChangingMethod(object sender, PropertyChangingEventArgs e)
{
}
#endregion
public override void Cleanup()
{
// Clean up if needed
base.Cleanup();
}
}
}
菜单实例数据:
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using IntTourism.Com.Transvalue.Bean;
using IntTourism.Com.Transvalue.Model;
using IntTourism.Com.Transvalue.Service;
namespace IntTourism.Com.Transvalue.Service.Impl
{
public class MainPageService : IMainPageSerivce
{
public void GetData(Action<DataItem, Exception> callback)
{
var item = new DataItem("Welcome to MVVM Light");
callback(item, null);
}
public void GetItemData(Action<Task<ObservableCollection<MenuItem>>, Exception> callback)
{
var result = Task.Run(() =>
{
var items = new ObservableCollection<MenuItem>();
var menu1 = new MenuItem();
menu1.IconUrl = "../Assets/ICON/交通.png";
menu1.NavigateUrl = "IntMaps";
items.Add(menu1);
var menu2 = new MenuItem();
menu2.IconUrl = "../Assets/ICON/娱乐.png";
menu2.NavigateUrl = "IntMaps";
menu2.NavigateParameter = "Play";
items.Add(menu2);
var menu3 = new MenuItem();
menu3.IconUrl = "../Assets/ICON/景点.png";
menu3.NavigateUrl = "SceneViewGroup";
items.Add(menu3);
var menu4 = new MenuItem();
menu4.IconUrl = "../Assets/ICON/购物.png";
menu4.NavigateUrl = "IntMaps";
menu4.NavigateParameter = "Buy";
items.Add(menu4);
var menu5 = new MenuItem();
menu5.IconUrl = "../Assets/ICON/专题旅游.png";
menu5.NavigateUrl = "SceneViewGroup";
menu5.NavigateParameter = "Travel";
items.Add(menu5);
var menu6 = new MenuItem();
menu6.IconUrl = "../Assets/ICON/实用信息.png";
items.Add(menu6);
var menu7 = new MenuItem();
menu7.IconUrl = "../Assets/ICON/武汉之最.png";
items.Add(menu7);
var menu8 = new MenuItem();
menu8.IconUrl = "../Assets/ICON/住宿.png";
menu8.NavigateUrl = "IntMaps";
menu8.NavigateParameter = "Rest";
items.Add(menu8);
var menu9 = new MenuItem();
menu9.IconUrl = "../Assets/ICON/推荐线路.png";
items.Add(menu9);
//var menu10 = new MenuItem();
//menu10.IconUrl = "../Assets/ICON/武汉介绍.png";
//items.Add(menu10);
var menu11 = new MenuItem();
menu11.IconUrl = "../Assets/ICON/周边旅游.png";
menu11.NavigateUrl = "IntMaps";
menu11.NavigateParameter = "AllTravel";
items.Add(menu11);
var menu12 = new MenuItem();
menu12.IconUrl = "../Assets/ICON/旅游动态.png";
items.Add(menu12);
var menu13 = new MenuItem();
menu13.IconUrl = "../Assets/ICON/美图欣赏.png";
items.Add(menu13);
var menu14 = new MenuItem();
menu14.IconUrl = "../Assets/ICON/天气预报.png";
items.Add(menu14);
var menu15 = new MenuItem();
menu15.IconUrl = "../Assets/ICON/旅游咨询.png";
items.Add(menu15);
var menu16 = new MenuItem();
menu16.IconUrl = "../Assets/ICON/美食.png";
menu16.NavigateUrl = "IntMaps";
menu16.NavigateParameter = "Eat";
items.Add(menu16);
return items;
});
callback(result, null);
}
}
}
以上sample 数据 可以存入数据库中 进行动态配置,完成菜单的动态显示,降低了程序的耦合,增加了可配置性。
一、安装Wax
当前,我们推荐你使用Xcode3创建Wax项目。Xcode4的项目模板仍然有些问题,因此请使用Xcode3。
1. 从http://github.com/probablycorey/wax/下载Wax或者用git命令将它复制到本地
2. 在shell中,转到wax文件夹,输入rake install命令。这将安装xcode项目模板。
3. 你知道Lua吗?如果你熟悉Javascript、Python、Runby之类的动态语言,你通过5分钟的学习就能入门。你可以阅读这些免费教程或者买本《Programingin Lua》。
二、创建新项目
三、开始使用Lua
- 并不需要在Xcode中编写Lua代码,它们全都在APP_ROOT/scripts目录下,直接用你喜欢的文本编辑工具编辑它们好了。Wax标准库文件位于APP_ROOT/wax/lib/stdlib目录下。这些全是你会用到的代码!
- 如果你使用TextMate,从APP_ROOT目录下执行rake tm,以便从项目打开。还可以安装wax-bundle已支持快捷键。
- 如果你迷恋于Xcode,你可以试试 capgo.com's 的语法加亮插件。
- 如果你使用的是vi或Emacs,你总不会连Lua支持都不会装吧?
- 要创建一个TableView,首先创建一个文件: APP_ROOT/scripts/MyTableViewController.lua
- 要创建新的OC控制器类,使用:
waxClass{"MyTableViewController",UITableViewController}
- 现在实现init函数,在里面设置tableView的内容并调用父类的init方法(正如你在OC中所做的一样)。
function init(self)
self.super:initWithStyle(UITableViewStylePlain)
-- Here are the tableView'scontents
self.things ={"Planes", "Trains", "Automobiles"}
return self
end
- 接下来实现UIDataSource协议方法。最终 MyTableViewController.lua 文件如下所示:
waxClass{"MyTableViewController",UITableViewController}
function init(self)
self.super:initWithStyle(UITableViewStylePlain)
-- Here are thetableView's contents
self.things ={"Planes", "Trains", "Automobiles"}
return self
end
functionnumberOfSectionsInTableView(self, tableView)
return 1
end
functiontableView_numberOfRowsInSection(self, tableView, section)
return #self.things
end
functiontableView_cellForRowAtIndexPath(self, tableView, indexPath)
local identifier ="MyTableViewControllerCell"
local cell =tableView:dequeueReusableCellWithIdentifier(identifier) or
UITableViewCell:initWithStyle_reuseIdentifier(UITableViewCellStyleDefault,identifier)
local thing =self.things[indexPath:row() + 1] -- Must +1 because Lua arrays are 1 based
cell:textLabel():setText(thing)
return cell
end
- 最后就是创建MyTableViewController示例并加到主窗口中。这需要修改APP_ROOT/scripts/AppDelegate.lua。它跟我们在OC程序中的UIApplicationDelegate是一样的。
require"MyTableViewController"
waxClass{"AppDelegate",protocols = {"UIApplicationDelegate"}}
functionapplicationDidFinishLaunching(self, application)
local frame =UIScreen:mainScreen():bounds()
self.window =UIWindow:initWithFrame(frame)
self.controller =MyTableViewController:init()
self.window:addSubview(self.controller:view())
self.window:makeKeyAndVisible()
end
- 运行程序…你已经用Lua创建了一个真正的UITableView!这真是太好了。
- 在这里下载framework:https://github.com/downloads/probablycorey/wax/wax.framework.zip
1. 用Xcode打开项目,将wax.framework拖到Xcode的frameworks组下。确保勾选"Copy items into destination group's folder"。
2. 新建init.lua(确保加到了应用程序束中)。在文件中加入代码:
puts("ZOMG, LUA IS RUNNING")
puts("Here is Lua talking to ObjC%s", tostring(UIApplication:sharedApplication()))
3. 打开AppDelegate文件,导入wax头文件:
#import "wax/wax.h"
4. 在AppDelegate的application:didFinishLaunchingWithOptions:方法中加入:
wax_start("init.lua",nil);
// To add wax with extensions, use thisline instead
// #import "wax/wax_http.h"
// #import "wax/wax_json.h"
// #import"wax/wax_filesystem.h"
// wax_start("init.lua",luaopen_wax_http, luaopen_wax_json, luaopen_wax_filesystem, nil);
最后,build and run,你将在Xcode控制台重看到Lua输出的内容。
package com.testasyntextview;
/**
* 把获取的线程写到方法中(比较好)
*/
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Html;
import android.text.Spanned;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MethodTestAsynTextViewActivity extends Activity {
private TextView textView1;
private Button button1;
private Context context;
private ProgressDialog progressDialog;
private Spanned html;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
context = this;
textView1 = (TextView) findViewById(R.id.textView1);
button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(l);
}
private OnClickListener l = new OnClickListener() {
@Override
public void onClick(View v) {
progressDialog = ProgressDialog.show(context, "获取数据中", "等待");
getHtmlDate();
}
};
private void getHtmlDate() {// 获取数据,把线程写入了其中
new Thread() {
public void run() {
Message msg = myHandler.obtainMessage();
try {
html = HttpUtil.fromHtml(HttpUtil
.getHtml("http://wap.sina.com"));
msg.what = 0;
} catch (Exception e) {
e.printStackTrace();
msg.what = 1;
}
myHandler.sendMessage(msg);
}
}.start();
}
Handler myHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
textView1.setText(html);
progressDialog.dismiss();
break;
case 1:
textView1.setText("当前无数据");
progressDialog.dismiss();
break;
}
super.handleMessage(msg);
}
};
}package com.testasyntextview;
/**
* 使用AsyncTask类
*/
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Html;
import android.text.Spanned;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class TestAsynTextViewActivity extends Activity {
private TextView textView1;
private Button button1;
private Context context;
private ProgressDialog progressDialog;
private Spanned html;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
context = this;
progressDialog = new ProgressDialog(context);
progressDialog.setTitle("进度条");
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
textView1 = (TextView) findViewById(R.id.textView1);
button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(l);
}
private OnClickListener l = new OnClickListener() {
@Override
public void onClick(View v) {
new InitTask().execute("http://wap.sina.com",
"http://wap.baidu.com");
}
};
private void getHtmlDate(String url) {// 获取数据,把线程写入了其中
try {
html = HttpUtil.fromHtml(HttpUtil.getHtml(url));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* When an asynchronous task is executed, the task goes through 4 steps:
*
* onPreExecute(),
* invoked on the UI thread immediately after the task is
* executed. This step is normally used to setup the task, for instance by
* showing a progress bar in the user interface.
*
* doInBackground(Params...),
* invoked on the background thread immediately after onPreExecute()
* finishes executing. This step is used to perform background computation
* that can take a long time. The parameters of the asynchronous task are
* passed to this step. The result of the computation must be returned by
* this step and will be passed back to the last step. This step can also
* use
*
* publishProgress(Progress...) to publish one or more units of
* progress. These values are published on the UI thread, in the
*
* onProgressUpdate(Progress...) step. onProgressUpdate(Progress...),
* invoked on the UI thread after a call to publishProgress(Progress...).
* The timing of the execution is undefined. This method is used to display
* any form of progress in the user interface while the background
* computation is still executing. For instance, it can be used to animate a
* progress bar or show logs in a text field. onPostExecute(Result), invoked
* on the UI thread after the background computation finishes. The result of
* the background computation is passed to this step as a parameter.
*/
class InitTask extends AsyncTask<String, Integer, Long> {
protected void onPreExecute() {
progressDialog.show();
super.onPreExecute();
}
protected Long doInBackground(String... params) {// Long是结果 String 是入口参数
getHtmlDate(params[0]);// 可以运行两个任务
publishProgress(50);// 发送进度50%
getHtmlDate(params[1]);
publishProgress(100);// 发送进度100%
return (long) 1;
}
@Override
protected void onProgressUpdate(Integer... progress) {
progressDialog.setProgress(progress[0]);// 设置进度
super.onProgressUpdate(progress);
Log.e("测试", progress[0] + "");
}
@Override
protected void onPostExecute(Long result) {
setTitle(result + "测试");
textView1.setText(html);
progressDialog.dismiss();
super.onPostExecute(result);
}
}
}package com.testasyntextview;
/**
* 使用Runable
*/
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Html;
import android.text.Spanned;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class RunableTestAsynTextViewActivity extends Activity {
private TextView textView1;
private Button button1;
private Context context;
private ProgressDialog progressDialog;
private Spanned html;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
context = this;
textView1 = (TextView) findViewById(R.id.textView1);
button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(l);
}
private OnClickListener l = new OnClickListener() {
@Override
public void onClick(View v) {
progressDialog = ProgressDialog.show(context, "获取数据中", "等待");
new Thread(new ThreadDemo()).start();
}
};
private void getHtmlDate() {
try {
html = HttpUtil.fromHtml(HttpUtil.getHtml("http://wap.sina.com"));
} catch (Exception e) {
e.printStackTrace();
}
}
class ThreadDemo implements Runnable {//一个runable
public void run() {
getHtmlDate();
myHandler.sendEmptyMessage(0);
}
}
Handler myHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
textView1.setText(html);
progressDialog.dismiss();
break;
case 1:
textView1.setText("当前无数据");
progressDialog.dismiss();
break;
}
super.handleMessage(msg);
}
};
}package com.testasyntextview;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import android.graphics.drawable.Drawable;
import android.text.Html;
import android.text.Spanned;
public class HttpUtil {
public static String getHtml(String path) throws Exception {
URL url = new URL(/blog_article/path/index.html);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5 * 1000);
InputStream inStream = conn.getInputStream();// 通过输入流获取html数据
byte[] data = readInputStream(inStream);// 得到html的二进制数据
String html = new String(data, "utf-8");
return html;
}
public static byte[] readInputStream(InputStream inStream) throws Exception {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outStream.write(buffer, 0, len);
}
inStream.close();
return outStream.toByteArray();
}
public static Spanned fromHtml(String html) {
Spanned sp = Html.fromHtml(html, new Html.ImageGetter() {
@Override
public Drawable getDrawable(String source) {
InputStream is = null;
try {
is = (InputStream) new URL(/blog_article/source/index.html).getContent();
Drawable d = Drawable.createFromStream(is, "src");
d.setBounds(0, 0, d.getIntrinsicWidth(),
d.getIntrinsicHeight());
is.close();
return d;
} catch (Exception e) {
return null;
}
}
}, null);
return sp;
}
}