React Native組件源碼分析之Image

本文基于React Native 0.32 對(duì) 官方提供的Image組件進(jìn)行分析徽龟。

Image是一個(gè)用于顯示多種圖片類型的React組件,它可以顯示來(lái)自網(wǎng)絡(luò)唉地,assets目錄据悔,本地SD卡,用戶自定義目錄的圖片耘沼。官網(wǎng)給出的用法如下:

renderImages() {
  return (
    <View>
      <Image
        style={styles.icon}
        source={require('./icon.png')}
      />
      <Image
        style={styles.logo}
        source={{uri: 'http://facebook.github.io/react/img/logo_og.png'}}
      />
    </View>
  );
}

那么它是如何實(shí)現(xiàn)的呢屠尊?為了更好地對(duì)RN如何封裝一個(gè)自定義組件進(jìn)行說明,下面我將分別從JS端和Native端的源碼進(jìn)行分析耕拷。


React端

在JS端讼昆,Image組件的源碼位于

react-native/Libraries/Image/Image.android.js

可以看到,盡管RN在0.18后全面轉(zhuǎn)向了ES6骚烧,但組件Image仍然采用了ES5風(fēng)格的JavaScript浸赫。

屬性的定義

Image在propTypes中定義了該組件支持的各種屬性及其屬性值的類型,這里我們著重介紹source屬性和style屬性的定義赃绊,而對(duì)于組件接收到的屬性值的處理則放在了render函數(shù)中

圖片URI

組件Image自身定義了如下幾種屬性:

  • source {uri: string}, number : 表示圖片資源的位置既峡。
source: PropTypes.oneOfType([//可以接受如下三種形式的資源位置
      PropTypes.shape({
      //`uri`是一個(gè)表示圖片的資源標(biāo)識(shí)的字符串,它可以是一個(gè)http地址或是一個(gè)本地文件路徑
        uri: PropTypes.string,
      }),
      // 也可以是一個(gè)通過函數(shù)`require('./path/to/image.png')`獲取到靜態(tài)資源
      PropTypes.number,
      //也可以接受一個(gè)包含了多個(gè)圖片uri的數(shù)組碧查,在數(shù)組里可以指定每個(gè)圖片顯示的寬高
      PropTypes.arrayOf(
        PropTypes.shape({
          uri: PropTypes.string,
          width: PropTypes.number,
          height: PropTypes.number,
        }))
    ]),
  • loadingIndicatorSource : 表示在真正圖片在加載過程中所顯示的圖片运敢,在加載網(wǎng)絡(luò)圖片的場(chǎng)景下特別有用。
loadingIndicatorSource: PropTypes.oneOfType([//該屬性與source的定義相似忠售,但是不支持多圖传惠。
      PropTypes.shape({
        uri: PropTypes.string,
      }),
      // Opaque type returned by require('./image.jpg')
      PropTypes.number,
    ]),

組件樣式style的定義

  • style: 定義了Image這個(gè)組件可以接收的樣式。
style: StyleSheetPropType(ImageStylePropTypes)

ImageStylePropTypes中定義了開發(fā)者可以為Image設(shè)置用到的style屬性:

var ImageStylePropTypes = {
//引入其他公用屬性
  ...LayoutPropTypes,
  ...ShadowPropTypesIOS,
  ...TransformPropTypes,
  //可以設(shè)置圖片的調(diào)整模式
  resizeMode: ReactPropTypes.oneOf(Object.keys(ImageResizeMode)),
  backfaceVisibility: ReactPropTypes.oneOf(['visible', 'hidden']),
  //背景色
  backgroundColor: ColorPropType,
  //邊框色
  borderColor: ColorPropType,
  //邊框?qū)挾?  borderWidth: ReactPropTypes.number,
  //邊框圓角度數(shù)
  borderRadius: ReactPropTypes.number,
  overflow: ReactPropTypes.oneOf(['visible', 'hidden']),
  tintColor: ColorPropType,
  opacity: ReactPropTypes.number,

  overlayColor: ReactPropTypes.string,

  borderTopLeftRadius: ReactPropTypes.number,
  borderTopRightRadius: ReactPropTypes.number,
  borderBottomLeftRadius: ReactPropTypes.number,
  borderBottomRightRadius: ReactPropTypes.number,
};

ReactNative把LayoutPropTypes等一些公用的style屬性提取出來(lái)稻扬,為了便于其他組件復(fù)用卦方。


其他屬性

  • progressiveRenderingEnabled:表示是否采用漸進(jìn)式加載,漸進(jìn)式加載時(shí)圖片會(huì)從模糊到清晰漸漸呈現(xiàn)泰佳。
  • fadeDuration: 圖片淡入淡出時(shí)間盼砍,毫秒。
  • resizeMode: 決定當(dāng)組件尺寸和圖片尺寸不成比例的時(shí)候如何調(diào)整圖片的大小逝她,目前支持以下幾種模式:
  • cover: 在保持圖片寬高比的前提下縮放圖片浇坐,直到寬度和高度都大于等于容器視圖的尺寸(如果容器有-padding內(nèi)襯的話,則相應(yīng)減去)黔宛。note:這樣圖片完全覆蓋甚至超出容器近刘,容器中不留任何空白。
  • contain: 在保持圖片寬高比的前提下縮放圖片,直到寬度和高度都小于等于容器視圖的尺寸(如果容器有padding內(nèi)襯的話跌宛,則相應(yīng)減去)酗宋。note:這樣圖片完全被包裹在容器中,容器中可能留有空白
  • stretch: 拉伸圖片且不維持寬高比疆拘,直到寬高都剛好填滿容器蜕猫。
  • center: 居中不拉伸。

另外哎迄,Image還可以通過屬性指定圖片加載階段的回調(diào)函數(shù):

  • onLoad: 圖片加載成功完成時(shí)調(diào)用此回調(diào)函數(shù)回右。
  • onLoadStart :圖片加載開始時(shí)調(diào)用。
  • onLoadEnd:圖片加載結(jié)束后漱挚,無(wú)論成功還是失敗翔烁,調(diào)用此回調(diào)函數(shù)。

Mixin

在 React component 構(gòu)建過程中旨涝,為了將同樣的功能添加到多個(gè)組件當(dāng)中蹬屹,可以將這些通用的功能包裝成一個(gè)mixin,然后導(dǎo)入到組件中白华。(ES6不支持mixin)
Image組件同樣引入了Mixin對(duì)象:

mixins: [NativeMethodsMixin]

Image所用到的主要功能是setNativeProps函數(shù):

setNativeProps: function (nativeProps) {
  if (process.env.NODE_ENV !== 'production') {
    warnForStyleProps(nativeProps, this.viewConfig.validAttributes);
  }
  var updatePayload = ReactNativeAttributePayload.create(nativeProps, this.viewConfig.validAttributes);

  UIManager.updateView(findNodeHandle(this), this.viewConfig.uiViewClassName, updatePayload);
}

我們都知道慨默,React Diff會(huì)計(jì)算出Virtual Dom中真正變化的部分并進(jìn)行渲染,而setNativeProps函數(shù)的作用在于直接將屬性對(duì)象傳遞給Native層弧腥,不經(jīng)過diff這個(gè)過程厦取。這就意味著,如果不在接下來(lái)的render過程中包含這些屬性管搪,這些屬性仍然會(huì)起作用虾攻。
那么,Image組件會(huì)傳遞哪些屬性給Native呢更鲁?默認(rèn)情況下霎箍,Image設(shè)置并傳遞了viewConfig對(duì)象:

viewConfig: {
  uiViewClassName: 'RCTView',
  validAttributes: ReactNativeViewAttributes.RCTView,
}

而在組件的生命周期回調(diào)函數(shù)componentWillMountcomponentWillReceiveProps則會(huì)更新屬性值:

_updateViewConfig: function(props) {
  if (props.children) {//有子組件
    this.viewConfig = {
      uiViewClassName: 'RCTView',
      validAttributes: ReactNativeViewAttributes.RCTView,
    };
  } else {
    this.viewConfig = {//無(wú)子組件
      uiViewClassName: 'RCTImageView',
      validAttributes: ImageViewAttributes,
    };
  }
},
componentWillMount: function() {
  this._updateViewConfig(this.props);
},

componentWillReceiveProps: function(nextProps) {
  this._updateViewConfig(nextProps);
},

可以看到,如果Image有子組件的情況下則會(huì)傳遞ReactNativeViewAttributes.RCTView,否則會(huì)傳遞ImageViewAttributes

var ImageViewAttributes = merge(ReactNativeViewAttributes.UIView, {
  src: true,
  loadingIndicatorSrc: true,
  resizeMode: true,
  progressiveRenderingEnabled: true,
  fadeDuration: true,
  shouldNotifyLoadEvents: true,
});

渲染

作為一個(gè)組件岁经,Image首先需要對(duì)各種屬性進(jìn)行相應(yīng)的處理工作朋沮,然后根據(jù)開發(fā)者設(shè)置的屬性值,相應(yīng)的業(yè)務(wù)場(chǎng)景以及組件狀態(tài)渲染出相應(yīng)的界面缀壤。這部分邏輯在render函數(shù)中定義。

source屬性解析

Image首先會(huì)對(duì)開發(fā)者傳入的source進(jìn)行解析纠亚,判斷需要從哪里加載圖片:

const source = resolveAssetSource(this.props.source);
const loadingIndicatorSource = resolveAssetSource(this.props.loadingIndicatorSource);

來(lái)看一下resolveAssetSource.js中的路徑解析邏輯:

//由屬性定義可知塘慕,這里傳入的source值可以是一個(gè)uri對(duì)象,或者require函數(shù)返回的數(shù)字
function resolveAssetSource(source: any): ?ResolvedAssetSource {
  if (typeof source === 'object') {//如果是uri對(duì)象則不作處理直接返回
    return source;
  }
  //獲取靜態(tài)圖片的基本信息
  var asset = AssetRegistry.getAssetByID(source);
  if (!asset) {
    return null;
  }

  const resolver = new AssetSourceResolver(getDevServerURL(), getBundleSourcePath(), asset);
  if (_customSourceTransformer) {
    return _customSourceTransformer(resolver);
  }
  return resolver.defaultAsset();
}

這里創(chuàng)建了AssetSourceResolver蒂胞,并傳入了三個(gè)參數(shù):

  • getDevServerURL: 如果從Node服務(wù)器加載JS图呢,則返回相應(yīng)路徑;
function getDevServerURL(): ?string {
  if (_serverURL === undefined) {
    var scriptURL = SourceCode.scriptURL;//調(diào)用Native module獲取JSbundle路徑
    var match = scriptURL && scriptURL.match(/^https?:\/\/.*?\//);
    if (match) {
      // 從網(wǎng)絡(luò)中獲取JS
      _serverURL = match[0];
    } else {
      // 從本地加載JS文件
      _serverURL = null;
    }
  }
  return _serverURL;
}
  • getBundleSourcePath:如果用戶自定義了JS文件路徑,則返回?zé)o協(xié)議頭的路徑蛤织;否則返回空
function getBundleSourcePath(): ?string {
  if (_bundleSourcePath === undefined) {
    const scriptURL = SourceCode.scriptURL;
    if (!scriptURL) {//未傳遞JS路徑
      _bundleSourcePath = null;
      return _bundleSourcePath;
    }
    if (scriptURL.startsWith('assets://')) {
      // 未指定JS文件路徑赴叹,離線時(shí)默認(rèn)從asset目錄加載
      _bundleSourcePath = null;
      return _bundleSourcePath;
    }
    if (scriptURL.startsWith('file://')) {
      //如果開發(fā)者指定了JS的目錄,則返回去除協(xié)議頭部的文件路徑
      _bundleSourcePath = scriptURL.substring(7, scriptURL.lastIndexOf('/') + 1);
    } else {
      _bundleSourcePath = scriptURL.substring(0, scriptURL.lastIndexOf('/') + 1);
    }
  }

  return _bundleSourcePath;
}
  • asset:使用AssetRegistry.getAssetByID返回的圖片基本信息

這里需要注意的是指蚜,RN允許開發(fā)者在Native端自定義JS的加載路徑乞巧,在JS端可以調(diào)用SourceCode.scriptURL來(lái)獲取。如果開發(fā)者未指定JSbundle的路徑摊鸡,則在離線環(huán)境下返回asset目錄绽媒,開發(fā)環(huán)境下從node服務(wù)器讀取。

通過上述三個(gè)參數(shù):JSbundle在node服務(wù)器的路徑免猾,JS在本地的路徑以及圖片的基本信息是辕,RN構(gòu)建了AssetSourceResolver對(duì)象,并調(diào)用了defaultAsset()

defaultAsset(): ResolvedAssetSource {
    if (this.isLoadedFromServer()) {//從服務(wù)器加載,返回url
      return this.assetServerURL();
    }
    if (Platform.OS === 'android') {
      return this.isLoadedFromFileSystem() ?
        this.drawableFolderInBundle() ://從自定義路徑加載
        this.resourceIdentifierWithoutScale();//從asset目錄加載
    } else {
      return this.scaledAssetPathInBundle();
    }
  }

defaultAsset()方法其實(shí)根據(jù)具體的場(chǎng)景返回了一個(gè)包含了圖片加載所需信息的對(duì)象而已猎提。
值得我們注意的是获三,如果開發(fā)者未指定JSbundle的加載路徑,則會(huì)調(diào)用resourceIdentifierWithoutScale方法锨苏,該方法中會(huì)調(diào)用assetPathUtils對(duì)圖片的加載路徑進(jìn)行處理疙教,把圖片目錄/圖片名稱的格式處理成圖片目錄_圖片名稱的形式。(這是由于打包命令同樣會(huì)調(diào)用assetPathUtils對(duì)資源文件進(jìn)行處理)

根據(jù)上述代碼的分析蚓炬,對(duì)于source屬性的處理解析而言松逊,我們可以得出結(jié)論如下:

  • 通過uri指定圖片路徑,則對(duì)source屬性不做處理肯夏,直接返回包含了uri字符串的對(duì)象经宏。
  • 通過require()請(qǐng)求靜態(tài)資源的方式加載圖片,則會(huì)根據(jù)加載位置的不同返回路徑不同的對(duì)象:
  • 開發(fā)環(huán)境下驯击,從node server加載JS 烁兰,則返回類似http://localhost:8081/index.android.bundle?platform=android&dev=true的路徑。
  • 離線狀態(tài)下徊都,如果未指定JS路徑沪斟,則返回經(jīng)過處理的asset路徑,例如:
  • 如果用戶未指定JS路徑暇矫,則返回用戶自定義的路徑主之,例如file:///sdcard/AwesomeModule/drawable-mdpi/icon.png.

style處理

通過resolveAssetSource對(duì)source屬性解析后,我們得到了一個(gè)包含了圖片加載信息的對(duì)象李根,并利用該對(duì)象中的信息創(chuàng)建了要渲染的樣式style槽奕,并將source屬性封裝為一個(gè)含有uri對(duì)象的數(shù)組:

const {width, height} = source;
//讀取到圖片的寬高,Image定義的style房轿,開發(fā)者自定義的style
style = flattenStyle([{width, height}, styles.base, this.props.style]);
sources = [{uri: source.uri}];

函數(shù)flattenStyle接收了一個(gè)包含各類樣式對(duì)象的數(shù)組粤攒。通過遞歸所森,flattenStyle把數(shù)組中的樣式都進(jìn)行了整理,合并為一個(gè)統(tǒng)一的style對(duì)象夯接。


渲染組件

在組件渲染之前焕济,Image把之前處理過的style,source以及開發(fā)者傳入的組件的屬性進(jìn)行了整理合并:

const nativeProps = merge(this.props, {
        style,//把style解析合并傳遞給native
        shouldNotifyLoadEvents: !!(onLoadStart || onLoad || onLoadEnd),
        src: sources,//歷史原因?qū)е翹ative端對(duì)應(yīng)的屬性名為src盔几,但開發(fā)者在react端要用source
        loadingIndicatorSrc: loadingIndicatorSource ? loadingIndicatorSource.uri : null,
      });

通過對(duì)開發(fā)者傳入的組件的屬性晴弃,樣式以及source等屬性進(jìn)行合并后,根據(jù)不同的業(yè)務(wù)場(chǎng)景渲染出相應(yīng)的組件:

if (nativeProps.children) {
    //如果Image組件中包含了其他組件
    const containerStyle = filterObject(style, (val, key) => !ImageSpecificStyleKeys.has(key));
    const imageStyle = filterObject(style, (val, key) => ImageSpecificStyleKeys.has(key));
    const imageProps = merge(nativeProps, {
      style: [imageStyle, styles.absoluteImage],
      children: undefined,
        });

    return (
      <View style={containerStyle}>
        <RKImage {...imageProps}/>
        {this.props.children}
      </View>
    );
  } else {
    if (this.context.isInAParentText) {//如果是TextView內(nèi)嵌Image
      return <RCTTextInlineImage {...nativeProps}/>;
    } else {//渲染普通情況下的Image組件
      return <RKImage {...nativeProps}/>;
    }
  }

Image組件提供了兩種圖片展示方式问欠,內(nèi)嵌于TextView中的圖片和普通圖片:

var RKImage = requireNativeComponent('RCTImageView', Image, cfg);
var RCTTextInlineImage = requireNativeComponent('RCTTextInlineImage', Image, cfg);

可以看到肝匆,內(nèi)嵌圖片的情況下引用了Native端實(shí)現(xiàn)的RCTTextInlineImage組件,而普通圖片則使用了RCTImageView顺献。
通過對(duì)Image組件在JavaScript端代碼進(jìn)行分析旗国,我們了解該組件是如何定義屬性以及如何根據(jù)開發(fā)者所設(shè)置的屬性渲染出不同的效果。而對(duì)于這些屬性所設(shè)置的效果進(jìn)行顯示和響應(yīng)則要靠Native層的實(shí)現(xiàn)注整。


Native端

我們知道能曾,ReactNative的圖片相關(guān)處理工作是交給圖片庫(kù)Fresco完成的,這里我們不去深究細(xì)節(jié)肿轨,只去關(guān)注組件本身的實(shí)現(xiàn)邏輯寿冕。Image組件在native端實(shí)的現(xiàn)位于:

.../react/views/image/ReactImageManager.java
對(duì)于自定義的組件,在Native端需要?jiǎng)?chuàng)建一個(gè)ReactImageManager負(fù)責(zé)進(jìn)行Native組件的創(chuàng)建椒袍,相關(guān)屬性的管理驼唱,事件的響應(yīng)等工作,而真正的具體實(shí)現(xiàn)操作則要放在Native組件中完成驹暑。
同樣玫恳,Image組件通過ReactImageManager來(lái)完成Native組件ReactImageView的創(chuàng)建和管理:

public ReactImageView createViewInstance(ThemedReactContext context) {
  return new ReactImageView(
      context,
      getDraweeControllerBuilder(),
      getCallerContext());
}
//與react端關(guān)聯(lián)
public String getName() {
    return "RCTImageView";
}

通過注解@ReactPropReactPropGroupReactImageManager導(dǎo)出了暴露給React端的屬性設(shè)置方法优俘,將相關(guān)屬性值交給Native組件ReactImageView京办,以src屬性為例:

@ReactProp(name = "src")
public void setSource(ReactImageView view, @Nullable ReadableArray sources) {
  view.setSource(sources);
}
public void setSource(@Nullable ReadableArray sources) {
  mSources.clear();
  if (sources != null && sources.size() != 0) {
    if (sources.size() == 1) {
      mSources.add(new ImageSource(getContext(), sources.getMap(0).getString("uri")));
    } else {
      for (int idx = 0; idx < sources.size(); idx++) {
        ReadableMap source = sources.getMap(idx);
        mSources.add(new ImageSource(
          getContext(),
          source.getString("uri"),
          source.getDouble("width"),
          source.getDouble("height")));
      }
    }
  }
  mIsDirty = true;
}

ReactImageView維護(hù)了相關(guān)的屬性對(duì)象,并在接收到React端傳遞過來(lái)的屬性值后進(jìn)行相應(yīng)處理解析帆焕,但此時(shí)不會(huì)刷新組件惭婿,只會(huì)標(biāo)記一下該組件需要刷新。而統(tǒng)一的刷新操作則放在ReactImageManageronAfterUpdateTransaction方法中進(jìn)行:

protected void onAfterUpdateTransaction(ReactImageView view) {
  super.onAfterUpdateTransaction(view);
  view.maybeUpdateView();
}

具體的刷新實(shí)現(xiàn)是通過圖片庫(kù)Fresco進(jìn)行實(shí)現(xiàn)的叶雹,這里不再詳細(xì)分析财饥。

總結(jié)

通過對(duì)整個(gè)Image組件的分析,我們可以看到React端定義了組件可以使用的屬性類型和事件折晦,并在渲染時(shí)將它們傳遞給Native層佑力;Native層通過ViewManager來(lái)對(duì)Native組件進(jìn)行對(duì)傳遞過來(lái)的屬性值進(jìn)行管理,而具體的實(shí)現(xiàn)則放在Native組件中筋遭。

如有疏漏之處,還請(qǐng)各位反饋。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末漓滔,一起剝皮案震驚了整個(gè)濱河市编饺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌响驴,老刑警劉巖透且,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異豁鲤,居然都是意外死亡秽誊,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門琳骡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)锅论,“玉大人,你說我怎么就攤上這事楣号∽钜祝” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵炫狱,是天一觀的道長(zhǎng)藻懒。 經(jīng)常有香客問我,道長(zhǎng)视译,這世上最難降的妖魔是什么嬉荆? 我笑而不...
    開封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮酷含,結(jié)果婚禮上鄙早,老公的妹妹穿的比我還像新娘。我一直安慰自己第美,他們只是感情好蝶锋,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著什往,像睡著了一般扳缕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上别威,一...
    開封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天躯舔,我揣著相機(jī)與錄音,去河邊找鬼省古。 笑死粥庄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的豺妓。 我是一名探鬼主播惜互,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼布讹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了训堆?” 一聲冷哼從身側(cè)響起描验,我...
    開封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎坑鱼,沒想到半個(gè)月后膘流,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鲁沥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年呼股,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片画恰。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡彭谁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出阐枣,到底是詐尸還是另有隱情马靠,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布蔼两,位于F島的核電站甩鳄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏额划。R本人自食惡果不足惜妙啃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望俊戳。 院中可真熱鬧揖赴,春花似錦、人聲如沸抑胎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)阿逃。三九已至铭拧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間恃锉,已是汗流浹背搀菩。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留破托,地道東北人肪跋。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像土砂,于是被迫代替她去往敵國(guó)和親州既。 傳聞我的和親對(duì)象是個(gè)殘疾皇子谜洽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,304評(píng)論 25 707
  • 持續(xù)更新中...... 一套企業(yè)級(jí)的 UI 設(shè)計(jì)語(yǔ)言和 React 實(shí)現(xiàn)。 https://mobile.ant....
    日不落000閱讀 5,726評(píng)論 0 35
  • 前言 學(xué)習(xí)本系列內(nèi)容需要具備一定 HTML 開發(fā)基礎(chǔ)易桃,沒有基礎(chǔ)的朋友可以先轉(zhuǎn)至 HTML快速入門(一) 學(xué)習(xí) 本人...
    珍此良辰閱讀 20,672評(píng)論 15 16
  • 福建土樓主要集中在永定褥琐、南靖、華安這幾個(gè)地區(qū)晤郑。其中以永定、南靖的土樓保留的最為完整贸宏,永定造寝、南靖兩地相聚不是很遠(yuǎn),2...
    印象智慧游閱讀 515評(píng)論 0 2
  • 我想吭练,它這樣吸引著我的原因是诫龙,最美的天在這里,最美的笑容在這里鲫咽,若說這天下還有最純潔的人签赃,還是在這里! 忘卻分尸、陶醉...
    行咖在路上閱讀 342評(píng)論 0 2