知乎日报详情页的实现(集成webView)
来源:互联网 发布:2017网络流行词汇大全 编辑:程序博客网 时间:2024/05/18 12:04
详情页的实现
知乎日报的文章详情页是使用一个 WebView
显示内容的。遗憾的是,React Native 官方在 Android 上并没有提供 WebView 的支持。好在 React Native 很容易集成原生的组件: Native UI Components 。我就按照官方文档,导出一个 React 的 WebView 组件。Java 端的代码如下:
public class ReactWebViewManager extends SimpleViewManager<WebView> { public static final String REACT_CLASS = "RCTWebView"; @UIProp(UIProp.Type.STRING) public static final String PROP_URL = "url"; @UIProp(UIProp.Type.STRING) public static final String PROP_HTML = "html"; @UIProp(UIProp.Type.STRING) public static final String PROP_CSS = "css"; @Override public String getName() { return REACT_CLASS; } @Override protected WebView createViewInstance(ThemedReactContext reactContext) { return new WebView(reactContext); } @Override public void updateView(final WebView webView, CatalystStylesDiffMap props) { super.updateView(webView, props); if (props.hasKey(PROP_URL)) { webView.loadUrl(props.getString(PROP_URL)); } if (props.hasKey(PROP_HTML)) { String html = props.getString(PROP_HTML); if (props.hasKey(PROP_CSS)) { String css = props.getString(PROP_CSS); html = "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + css + "\" />" + html; } webView.loadData(html, "text/html; charset=utf-8", "UTF-8"); } }}
这里我导出了一个简单的 WebView,并暴露了 url
, html
, css
三个属性。 url
表示网页要显示的网页地址, html
表示要加载的 HTML 字符串, css
表示网页样式链接。还要注册这个 ReactWebViewManager
到 ReactInstanceManager
中。具体代码可以看 MyReactPackage.java 和MainActivity.java
在 JS 端,需要做对应的封装:
class ObservableWebView extends React.Component { ... render() { return <RCTWebView {...this.props} onChange={this._onChange} />; }}ObservableWebView.propTypes = { url: PropTypes.string, html: PropTypes.string, css: PropTypes.string, onScrollChange: PropTypes.func,};var RCTWebView = requireNativeComponent('RCTWebView', ObservableWebView, { nativeOnly: {onChange: true}});module.exports = ObservableWebView;
然后就可以在 React 中使用了,如下:
var MyWebView = require('./WebView');render: function() {return ( <View style={styles.container}> <MyWebView style={styles.content} html={this.state.detail.body} css={this.state.detail.css[0]}/> </View> );}
这样就能直接显示了网页内容,挺出乎我意料的简单。
还有一个细节,官方客户端,随着 WebView 的滑动,头部的 Image 也跟着往上收起来。这里我们就要监听 WebView 的滑动事件,然后来设置头部的 Image 的跟随移动。还好,官方文档也提供了一个可以方便从 Native 往 React 传递事件的方法: Events 。跟着文档来,实现了一个 ObservableWebView
,继承于原生的 WebView
,同时把滑动事件上报给 React:
// ObservableWebView.javapublic class ObservableWebView extends WebView {... @Override protected void onScrollChanged(final int l, final int t, final int oldl, final int oldt) { super.onScrollChanged(l, t, oldl, oldt); WritableMap event = Arguments.createMap(); event.putInt("ScrollX", l); event.putInt("ScrollY", t); ReactContext reactContext = (ReactContext)getContext(); reactContext.getJSModule(RCTEventEmitter.class).receiveEvent( getId(), "topChange", event); }}
这里在 onScrollChanged()
回调中,就是往 React 中报 topChange
事件。事件中包含ScrollX
和 ScrollY
两个值。这里的 topChange
被映射到了 JS 的 onChange
事件。在 React 层就能这样用了: <MyWebView onChange={onChangeCallback}/>
,这里的 onChangeCallback
是一个自定义的回调函数。 WebView
滑动的时候,就会回调到这个函数中来。为了实用方便,这里还可以做一些封装,把 topChange
封装为我们关心的滑动事件 onScrollChange
:
class ObservableWebView extends React.Component { constructor() { super(); this._onChange = this._onChange.bind(this); } _onChange(event: Event) { if (!this.props.onScrollChange) { return; } this.props.onScrollChange(event.nativeEvent.ScrollY); } render() { return <RCTWebView {...this.props} onChange={this._onChange} />; }}
详情可以参考: WebView.js 。
这时,我们就可以在 React 组件中的 onScrollChange
事件回调中实现滑动详情页的头部图片的效果:
onWebViewScroll: function(event) {// 这里移动头部的 Image},render: function() {return (<View style={styles.container}><MyWebView ... onScrollChange={this.onWebViewScroll}/><Image ref={REF_HEADER} source={{uri: this.state.detail.image}} style={styles.headerImage} />{toolbar}</View>);},
这里的写起来也很简单。关键看一下 onWebViewScroll
函数的实现。最简单的实现方法就是,通过 ScrollY 来设置组件的 state
,来让 React 自动触发重绘。因为事件上报非常频繁,就会触发大量的重绘,会带来严重的性能问题。
React Native 提供了 Direct Manipulation ,也就是直接操作组件,这种方式不会触发重绘,效率会高很多。
onWebViewScroll: function(event) { // 像素转为 React 中的大小单元var scrollY = -event / PIXELRATIO;var nativeProps = precomputeStyle({transform: [{translateY: scrollY}]});// 直接操作组件的属性this.refs[REF_HEADER].setNativeProps(nativeProps);},
到这里,实现这个 React Native 版的知乎日报客户端所涉及的技术点,基本都讲完了。还有很多细节请参考源码: ZhiHuDaily-React-Native ,欢迎一起交流,和发 pull request 来一起完善这个项目。
总结
这篇文章几百字就写完了,看起来实现这个客户端并不复杂。其实,这里有远超过我想象的坑,后面我应该还会写一篇文章,来总结这个项目中遇到的坑。总体来说,React Native for Android 作为初期的版本,实现一个简单 APP 已经可行。但是它并不完善,如果想用在实际项目中,还需要慎重考量。
最后,大家可以关注这个项目: ZhiHuDaily-React-Native 。希望能对开始关注 React Native 的同学有些帮助。
- 知乎日报详情页的实现(集成webView)
- Material Design之利用CollapsingToolbarLayout轻松实现知乎日报新闻详情页顶部效果(带banner的toolbar伸缩折叠效果)
- android 实现了知乎日报的大部分功能,增加双击标题栏回到顶部以及双击 webview 返回两个实用功能
- 知乎日报客户端的模拟实现(进行时)
- Labview实现简单知乎日报客户端
- 基于Vue2.0的知乎日报单页应用
- 基于Vue2.0的知乎日报单页应用
- 都说“知乎”逼格高,我们来实现“知乎”回答详情页动画效果
- 知乎日报风格的博客园
- 我的低仿“知乎日报”
- react 版的知乎日报
- 知乎日报客户端
- 知乎日报API
- 知乎日报API
- 练手--知乎日报
- 知乎日报
- 知乎标签详情页爬虫
- RxAndroid项目实践-使用RxJava响应式编码实现知乎日报的欢迎界面
- 关押罪犯 洛谷1525 并查集
- 【闯王的宝藏】 水题 链表
- 学着做点事
- HDU1094 A+B for Input-Output Practice (VI)
- 什么是机器学习
- 知乎日报详情页的实现(集成webView)
- ANR完全解析
- ZJOI 2010 贪吃的老鼠 网络流
- HDU1095 A+B for Input-Output Practice (VII)
- [R语言入门]R 语言数据操作总结
- HDU1096 A+B for Input-Output Practice (VIII)
- react native ios打包到真机
- BZOJ 4243 交朋友
- 浅谈 JSP 技术