MBProgressHUD——iOS進(jìn)度提示控件

以下內(nèi)容來源于官方源碼画侣、 README 文檔拇勃、測試 Demo或個(gè)人使用總結(jié) 硅卢!

MBProgressHUD

MBProgressHUD 是一個(gè) iOS 的半透明的指示器或標(biāo)簽組件驻谆,用于顯示后臺(tái)線程的進(jìn)度擅编。MBProgressHUD 比沒有文檔的所踊、私有的 UIKit UIProgressHUD 多了一些特性棺禾,旨在取而代之蓬蝶。

Requirements

MBProgressHUD 需要使用的Apple框架:

  • Foundation.framework
  • UIKit.framework
  • CoreGraphics.framework

使用

使用 MBProgressHUD 最重要的一點(diǎn)是:當(dāng)執(zhí)行需要較長時(shí)間的任務(wù)時(shí)读处,保證主線程是空閑的糊治,這樣可以使UI實(shí)時(shí)更新。因此: 推薦的做法是在主線程中使用 MBProgressHUD罚舱,把其他你想要執(zhí)行的任務(wù)分發(fā)到其他的線程里:

[MBProgressHUD showHUDAddedTo:self.view animated:YES];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    // Do something...
    dispatch_async(dispatch_get_main_queue(), ^{
        [MBProgressHUD hideHUDForView:self.view animated:YES];
    });
});

你可以在任何視圖或窗口中添加HUD井辜。 但是,請(qǐng)盡量避免將HUD添加到具有復(fù)雜視圖層次結(jié)構(gòu)的某些 UIKit 視圖(如 UITableViewUICollectionView )中管闷。 那些視圖可以以意想不到的方式變換他們的子視圖粥脚,從而影響 HUD的顯示。

如果你想配置 HUD,你可以使用由 showHUDAddedTo:animated: 方法返回的 MBProgressHUD 的實(shí)例.

MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeAnnularDeterminate;
hud.labelText = @"Loading";
[self doSomethingInBackgroundWithProgressCallback:^(float progress) {
    hud.progress = progress;
} completionCallback:^{
    [hud hide:YES];
}];

你也可以使用 NSProgress 對(duì)象包个,當(dāng)通過該對(duì)象報(bào)告進(jìn)度時(shí)刷允,MBProgressHUD 將自動(dòng)更新。

MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.mode = MBProgressHUDModeAnnularDeterminate;
hud.labelText = @"Loading";
NSProgress *progress = [self doSomethingInBackgroundCompletion:^{
    [hud hide:YES];
}];
hud.progressObject = progress;

UI 更新應(yīng)該通潮棠遥總是在主線程完成恃锉。但是某些 MBProgressHUD 設(shè)置器,考慮到了線程安全 ,并且可以在后臺(tái)線程里被調(diào)用。這些設(shè)置器,具體指的是: setMode:,setCustomView:, setLabelText:, setLabelFont:, setDetailsLabelText:,setDetailsLabelFont:setProgress:呕臂。

如果你需要在主線程執(zhí)行需要長時(shí)間運(yùn)行的任務(wù),你應(yīng)該在短暫的延遲后再執(zhí)行這個(gè)任務(wù),這樣在你的任務(wù)阻塞主線程之前, UIKit 就有足夠的時(shí)間來更新UI(如,繪制HUD).

[MBProgressHUD showHUDAddedTo:self.view animated:YES];
// 延遲 0.01s 后執(zhí)行
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0.01 * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    // Do something...
    [MBProgressHUD hideHUDForView:self.view animated:YES];
});

你應(yīng)該知道破托,在 Block塊完成之前,上述 Block塊中發(fā)出的任何 HUD 更新消息將不會(huì)被顯示歧蒋。

源碼

//
//  MBProgressHUD.h
//  Version 1.0.0
//  Created by Matej Bukovinski on 2.4.09.
//

// This code is distributed under the terms and conditions of the MIT license. 

// Copyright ? 2009-2016 Matej Bukovinski
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <CoreGraphics/CoreGraphics.h>

@class MBBackgroundView;
@protocol MBProgressHUDDelegate;


extern CGFloat const MBProgressMaxOffset;

typedef NS_ENUM(NSInteger, MBProgressHUDMode) {
    /// UIActivityIndicatorView.
    MBProgressHUDModeIndeterminate,
    /// 一個(gè)圓形的餅圖土砂,像進(jìn)度視圖州既。
    MBProgressHUDModeDeterminate,
    /// 水平進(jìn)度條。
    MBProgressHUDModeDeterminateHorizontalBar,
    /// 環(huán)形進(jìn)度視圖萝映。
    MBProgressHUDModeAnnularDeterminate,
    /// 顯示自定義視圖吴叶。
    MBProgressHUDModeCustomView,
    /// 僅顯示標(biāo)簽。
    MBProgressHUDModeText
};

typedef NS_ENUM(NSInteger, MBProgressHUDAnimation) {
    /// 不透明動(dòng)畫
    MBProgressHUDAnimationFade,
    /// 不透明+縮放動(dòng)畫(顯示時(shí)縮小序臂,消失時(shí)放大)
    MBProgressHUDAnimationZoom,
    /// Opacity + scale animation (zoom out style)
    MBProgressHUDAnimationZoomOut,
    /// Opacity + scale animation (zoom in style)
    MBProgressHUDAnimationZoomIn
};

typedef NS_ENUM(NSInteger, MBProgressHUDBackgroundStyle) {
    /// 純色背景
    MBProgressHUDBackgroundStyleSolidColor,
    /// UIVisualEffectView 或 UIToolbar.layer 背景視圖
    MBProgressHUDBackgroundStyleBlur
};

typedef void (^MBProgressHUDCompletionBlock)();


NS_ASSUME_NONNULL_BEGIN


/** 
 * Displays a simple HUD window containing a progress indicator and two optional labels for short messages.
 *
 * This is a simple drop-in class for displaying a progress HUD view similar to Apple's private UIProgressHUD class.
 * The MBProgressHUD window spans over the entire space given to it by the initWithFrame: constructor and catches all
 * user input on this region, thereby preventing the user operations on components below the view.
 *
 * @note To still allow touches to pass through the HUD, you can set hud.userInteractionEnabled = NO.
 * @attention MBProgressHUD is a UI class and should therefore only be accessed on the main thread.
 */
@interface MBProgressHUD : UIView

/**
 * 創(chuàng)建一個(gè)新的HUD,并把它添加并顯示到提供的視圖上.與之相對(duì)應(yīng)的方法是 hideHUDForView:animated:.
 *
 * @note 這個(gè)方法會(huì)設(shè)置HUD的屬性 removeFromSuperViewOnHide 為YES.HUD會(huì)在隱藏時(shí)自動(dòng)從父視圖上移除.
 *
 * @param view 將HUD添加到此視圖上.
 * @param animated YES:顯示時(shí)使用當(dāng)前的動(dòng)畫類型顯示;NO:直接顯示不使用動(dòng)畫效果.
 * @return A reference to the created HUD.
 *
 * @see hideHUDForView:animated:
 * @see animationType
 */
+ (instancetype)showHUDAddedTo:(UIView *)view animated:(BOOL)animated;

/// @name Showing and hiding

/**
 * 找到并隱藏子視圖最頂層的HUD.與之對(duì)應(yīng)的方法是 showHUDAddedTo:animated:.
 
 *
 * @note 這個(gè)方法會(huì)設(shè)置HUD的屬性 removeFromSuperViewOnHide 為YES.HUD會(huì)在隱藏時(shí)自動(dòng)從父視圖上移除.
 *
 * @param view  用來在其子視圖中查找HUD的視圖.
 * @param animated YES,隱藏時(shí)使用當(dāng)前的動(dòng)畫類型;NO,直接隱藏不使用動(dòng)畫效果.
 * @return  如果某個(gè)HUD被找到并被移除;否則返回NO.
 *
 * @see showHUDAddedTo:animated:
 * @see animationType
 */
+ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated;

/**
 * 找到最頂層的 HUD 并返回.
 *
 * @param view The view that is going to be searched.
 * @return A reference to the last HUD subview discovered.
 */
+ (nullable MBProgressHUD *)HUDForView:(UIView *)view;

/**
 * 使用指定視圖的邊框尺寸創(chuàng)建HUD的便利初始化方法. Calls the designated constructor with
 * view.bounds as the parameter.
 *
 * @param view The view instance that will provide the bounds for the HUD. Should be the same instance as
 * the HUD's superview (i.e., the view that the HUD will be added to).
 */
- (instancetype)initWithView:(UIView *)view;

/** 
 * 顯示 HUD.
 *
 * @note 你需要確保調(diào)用此方法時(shí),主線程未被其他任務(wù)阻塞,以便于更新視圖.當(dāng)你已經(jīng)在新的線程中開始(比如,使用NSOperation或者NSURLRequest的異步請(qǐng)求等)執(zhí)行某個(gè)任務(wù)后,再執(zhí)行此方法.
 * (e.g., when using something like NSOperation or making an asynchronous call like NSURLRequest).
 * @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use
 * animations while appearing.
 *
 * @see animationType
 */
- (void)showAnimated:(BOOL)animated;

/** 
 * Hides the HUD. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to
 * hide the HUD when your task completes.
 *
 * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use
 * animations while disappearing.
 *
 * @see animationType
 */
- (void)hideAnimated:(BOOL)animated;

/** 
 * 指定延時(shí)后隱藏 HUD . This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to
 * hide the HUD when your task completes.
 *
 * @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use
 * animations while disappearing.
 * @param delay Delay in seconds until the HUD is hidden.
 *
 * @see animationType
 */
- (void)hideAnimated:(BOOL)animated afterDelay:(NSTimeInterval)delay;

/**
 * The HUD delegate object. Receives HUD state notifications.
 */
@property (weak, nonatomic) id<MBProgressHUDDelegate> delegate;

/**
 * HUD完全隱藏后執(zhí)行的block.
 */
@property (copy, nullable) MBProgressHUDCompletionBlock completionBlock;

/*
 * 用于指定某個(gè)方法執(zhí)行一段時(shí)間之后再顯示HUD,以秒記.如果方法在這段時(shí)間之前就執(zhí)行完成,就不再顯示HUD.
 * This may be used to prevent HUD display for very short tasks.
 * Defaults to 0 (no grace time).
 */
@property (assign, nonatomic) NSTimeInterval graceTime;

/**
 * HUD顯示的最小時(shí)間(以秒記.)
 * This avoids the problem of the HUD being shown and than instantly hidden.
 * Defaults to 0 (no minimum show time).
 */
@property (assign, nonatomic) NSTimeInterval minShowTime;

/**
 * Removes the HUD from its parent view when hidden.
 * Defaults to NO.
 */
@property (assign, nonatomic) BOOL removeFromSuperViewOnHide;

/// @name Appearance

/** 
 * MBProgressHUD operation mode. The default is MBProgressHUDModeIndeterminate.
 */
@property (assign, nonatomic) MBProgressHUDMode mode;

/**
 * A color that gets forwarded to all labels and supported indicators. Also sets the tintColor
 * for custom views on iOS 7+. Set to nil to manage color individually.
 * Defaults to semi-translucent black on iOS 7 and later and white on earlier iOS versions.
 */
@property (strong, nonatomic, nullable) UIColor *contentColor UI_APPEARANCE_SELECTOR;

/**
 * HUD顯示和隱藏時(shí)使用的動(dòng)畫類型.
 */
@property (assign, nonatomic) MBProgressHUDAnimation animationType UI_APPEARANCE_SELECTOR;

/**
 * The bezel offset relative to the center of the view. You can use MBProgressMaxOffset
 * and -MBProgressMaxOffset to move the HUD all the way to the screen edge in each direction.
 * E.g., CGPointMake(0.f, MBProgressMaxOffset) would position the HUD centered on the bottom edge.
 */
@property (assign, nonatomic) CGPoint offset UI_APPEARANCE_SELECTOR;

/**
 * The amount of space between the HUD edge and the HUD elements (labels, indicators or custom views).
 * This also represents the minimum bezel distance to the edge of the HUD view.
 * Defaults to 20.f
 */
@property (assign, nonatomic) CGFloat margin UI_APPEARANCE_SELECTOR;

/**
 * The minimum size of the HUD bezel. Defaults to CGSizeZero (no minimum size).
 */
@property (assign, nonatomic) CGSize minSize UI_APPEARANCE_SELECTOR;

/**
 * Force the HUD dimensions to be equal if possible.
 */
@property (assign, nonatomic, getter = isSquare) BOOL square UI_APPEARANCE_SELECTOR;

/**
 * When enabled, the bezel center gets slightly affected by the device accelerometer data.
 * Has no effect on iOS < 7.0. Defaults to YES.
 */
@property (assign, nonatomic, getter=areDefaultMotionEffectsEnabled) BOOL defaultMotionEffectsEnabled UI_APPEARANCE_SELECTOR;

/// @name Progress

/**
 * The progress of the progress indicator, from 0.0 to 1.0. Defaults to 0.0.
 */
@property (assign, nonatomic) float progress;

/// @name ProgressObject

/**
 * The NSProgress object feeding the progress information to the progress indicator.
 */
@property (strong, nonatomic, nullable) NSProgress *progressObject;

/// @name Views

/**
 * The view containing the labels and indicator (or customView).
 */
@property (strong, nonatomic, readonly) MBBackgroundView *bezelView;

/**
 * View covering the entire HUD area, placed behind bezelView.
 */
@property (strong, nonatomic, readonly) MBBackgroundView *backgroundView;

/**
 * The UIView (e.g., a UIImageView) to be shown when the HUD is in MBProgressHUDModeCustomView.
 * The view should implement intrinsicContentSize for proper sizing. For best results use approximately 37 by 37 pixels.
 */
@property (strong, nonatomic, nullable) UIView *customView;

/**
 * A label that holds an optional short message to be displayed below the activity indicator. The HUD is automatically resized to fit
 * the entire text.
 */
@property (strong, nonatomic, readonly) UILabel *label;

/**
 * A label that holds an optional details message displayed below the labelText message. The details text can span multiple lines.
 */
@property (strong, nonatomic, readonly) UILabel *detailsLabel;

/**
 * A button that is placed below the labels. Visible only if a target / action is added. 
 */
@property (strong, nonatomic, readonly) UIButton *button;

@end


@protocol MBProgressHUDDelegate <NSObject>

@optional

/** 
 * Called after the HUD was fully hidden from the screen. 
 */
- (void)hudWasHidden:(MBProgressHUD *)hud;

@end


/**
 * A progress view for showing definite progress by filling up a circle (pie chart).
 */
@interface MBRoundProgressView : UIView 

/**
 * Progress (0.0 to 1.0)
 */
@property (nonatomic, assign) float progress;

/**
 * Indicator progress color.
 * Defaults to white [UIColor whiteColor].
 */
@property (nonatomic, strong) UIColor *progressTintColor;

/**
 * Indicator background (non-progress) color. 
 * Only applicable on iOS versions older than iOS 7.
 * Defaults to translucent white (alpha 0.1).
 */
@property (nonatomic, strong) UIColor *backgroundTintColor;

/*
 * Display mode - NO = round or YES = annular. Defaults to round.
 */
@property (nonatomic, assign, getter = isAnnular) BOOL annular;

@end


/**
 * A flat bar progress view. 
 */
@interface MBBarProgressView : UIView

/**
 * Progress (0.0 to 1.0)
 */
@property (nonatomic, assign) float progress;

/**
 * Bar border line color.
 * Defaults to white [UIColor whiteColor].
 */
@property (nonatomic, strong) UIColor *lineColor;

/**
 * Bar background color.
 * Defaults to clear [UIColor clearColor];
 */
@property (nonatomic, strong) UIColor *progressRemainingColor;

/**
 * Bar progress color.
 * Defaults to white [UIColor whiteColor].
 */
@property (nonatomic, strong) UIColor *progressColor;

@end


@interface MBBackgroundView : UIView

/**
 * The background style. 
 * Defaults to MBProgressHUDBackgroundStyleBlur on iOS 7 or later and MBProgressHUDBackgroundStyleSolidColor otherwise.
 * @note Due to iOS 7 not supporting UIVisualEffectView, the blur effect differs slightly between iOS 7 and later versions.
 */
@property (nonatomic) MBProgressHUDBackgroundStyle style;

/**
 * The background color or the blur tint color.
 * @note Due to iOS 7 not supporting UIVisualEffectView, the blur effect differs slightly between iOS 7 and later versions.
 */
@property (nonatomic, strong) UIColor *color;

@end

@interface MBProgressHUD (Deprecated)

+ (NSArray *)allHUDsForView:(UIView *)view __attribute__((deprecated("Store references when using more than one HUD per view.")));
+ (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated __attribute__((deprecated("Store references when using more than one HUD per view.")));

- (id)initWithWindow:(UIWindow *)window __attribute__((deprecated("Use initWithView: instead.")));

- (void)show:(BOOL)animated __attribute__((deprecated("Use showAnimated: instead.")));
- (void)hide:(BOOL)animated __attribute__((deprecated("Use hideAnimated: instead.")));
- (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay __attribute__((deprecated("Use hideAnimated:afterDelay: instead.")));

- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated __attribute__((deprecated("Use GCD directly.")));
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block __attribute__((deprecated("Use GCD directly.")));
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(nullable MBProgressHUDCompletionBlock)completion __attribute__((deprecated("Use GCD directly.")));
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue __attribute__((deprecated("Use GCD directly.")));
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue
     completionBlock:(nullable MBProgressHUDCompletionBlock)completion __attribute__((deprecated("Use GCD directly.")));
@property (assign) BOOL taskInProgress __attribute__((deprecated("No longer needed.")));

@property (nonatomic, copy) NSString *labelText __attribute__((deprecated("Use label.text instead.")));
@property (nonatomic, strong) UIFont *labelFont __attribute__((deprecated("Use label.font instead.")));
@property (nonatomic, strong) UIColor *labelColor __attribute__((deprecated("Use label.textColor instead.")));
@property (nonatomic, copy) NSString *detailsLabelText __attribute__((deprecated("Use detailsLabel.text instead.")));
@property (nonatomic, strong) UIFont *detailsLabelFont __attribute__((deprecated("Use detailsLabel.font instead.")));
@property (nonatomic, strong) UIColor *detailsLabelColor __attribute__((deprecated("Use detailsLabel.textColor instead.")));
@property (assign, nonatomic) CGFloat opacity __attribute__((deprecated("Customize bezelView properties instead.")));
@property (strong, nonatomic) UIColor *color __attribute__((deprecated("Customize the bezelView color instead.")));
@property (assign, nonatomic) CGFloat xOffset __attribute__((deprecated("Set offset.x instead.")));
@property (assign, nonatomic) CGFloat yOffset __attribute__((deprecated("Set offset.y instead.")));
@property (assign, nonatomic) CGFloat cornerRadius __attribute__((deprecated("Set bezelView.layer.cornerRadius instead.")));
@property (assign, nonatomic) BOOL dimBackground __attribute__((deprecated("Customize HUD background properties instead.")));
@property (strong, nonatomic) UIColor *activityIndicatorColor __attribute__((deprecated("Use UIAppearance to customize UIActivityIndicatorView. E.g.: [UIActivityIndicatorView appearanceWhenContainedIn:[MBProgressHUD class], nil].color = [UIColor redColor];")));
@property (atomic, assign, readonly) CGSize size __attribute__((deprecated("Get the bezelView.frame.size instead.")));

@end

NS_ASSUME_NONNULL_END

Demo

1.1 不確定模式

- (void)indeterminateExample {
    // 在根視圖上顯示HUD(self.view 是一個(gè)可滾動(dòng)的列表視圖蚌卤,因此不適合將 HUD 隨著用戶劃動(dòng)與內(nèi)容一起移動(dòng))。
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];

    // 激發(fā)異步任務(wù)奥秆,使 UIKit 有機(jī)會(huì)重新繪制HUD添加到視圖層次結(jié)構(gòu)逊彭。
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{

        // Do something useful in the background
        [self doSomeWork];

        // 重要 - 分配回主線程。 始終在主線程上訪問UI類(包括MBProgressHUD)构订。
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
}

1.2 帶標(biāo)簽

- (void)labelExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];

    // 設(shè)置標(biāo)簽文本.
    hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");
    // You can also adjust other label properties if needed.
    // hud.label.font = [UIFont italicSystemFontOfSize:16.f];

    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        [self doSomeWork];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
}

1.3 帶詳細(xì)標(biāo)簽

- (void)detailsLabelExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];

    // Set the label text.
    hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");
    // Set the details label text. Let's make it multiline this time.
    hud.detailsLabel.text = NSLocalizedString(@"Parsing data\n(1/1)", @"HUD title");

    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        [self doSomeWork];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
}

2.1 確定模式

- (void)determinateExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];

    // Set the determinate mode to show task progress.
    // 一個(gè)圓形的餅圖
    hud.mode = MBProgressHUDModeDeterminate;
    hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");

    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        // Do something useful in the background and update the HUD periodically.
        [self doSomeWorkWithProgress];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
}

- (void)doSomeWorkWithProgress {
    self.canceled = NO;
    // This just increases the progress indicator in a loop.
    float progress = 0.0f;
    while (progress < 1.0f) {
        if (self.canceled) break;
        progress += 0.01f;
        dispatch_async(dispatch_get_main_queue(), ^{
            // Instead we could have also passed a reference to the HUD
            // to the HUD to myProgressTask as a method parameter.
            [MBProgressHUD HUDForView:self.navigationController.view].progress = progress;
        });
        usleep(50000);
    }
}

2.2 環(huán)形確定模式

- (void)annularDeterminateExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];

    // Set the annular determinate mode to show task progress.
    hud.mode = MBProgressHUDModeAnnularDeterminate;
    hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");

    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        // Do something useful in the background and update the HUD periodically.
        [self doSomeWorkWithProgress];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
}

2.3 條形確定模式

- (void)barDeterminateExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];

    // Set the bar determinate mode to show task progress.
    hud.mode = MBProgressHUDModeDeterminateHorizontalBar;
    hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");

    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        // Do something useful in the background and update the HUD periodically.
        [self doSomeWorkWithProgress];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
}

3.1僅顯示文本

- (void)textExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];

    // Set the text mode to show only text.
    hud.mode = MBProgressHUDModeText;
    hud.label.text = NSLocalizedString(@"Message here!", @"HUD message title");
    // 移動(dòng)到底部中心
    hud.offset = CGPointMake(0.f, MBProgressMaxOffset);
    // 3秒后自動(dòng)消失
    [hud hideAnimated:YES afterDelay:3.f];
}

Tips

屬性 bezelView 可以修改 HUD 窗口顏色侮叮,該視圖屬性僅包含標(biāo)簽和指示器(或customView)。
backgroundView 屬性:

View covering the entire HUD area, placed behind bezelView

// 設(shè)置文字為白色
hud.label.textColor = [UIColor whiteColor];   
// 設(shè)置 HUD窗口為黑色
hud.bezelView.blurEffectStyle = UIBlurEffectStyleDark;

3.2 自定義視圖

- (void)customViewExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];

    // Set the custom view mode to show any view.
    hud.mode = MBProgressHUDModeCustomView;
    // Set an image view with a checkmark.
    UIImage *image = [[UIImage imageNamed:@"Checkmark"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
    hud.customView = [[UIImageView alloc] initWithImage:image];
    // Looks a bit nicer if we make it square.
    hud.square = YES;
    // Optional label text.
    hud.label.text = NSLocalizedString(@"Done", @"HUD done title");

    [hud hideAnimated:YES afterDelay:3.f];
}

3.3 帶按鈕

- (void)cancelationExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view
                                              animated:YES];

    // Set the determinate mode to show task progress.
    hud.mode = MBProgressHUDModeDeterminate;
    hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");

    // Configure the button.
    [hud.button setTitle:NSLocalizedString(@"Cancel", @"HUD cancel button title")
                forState:UIControlStateNormal];
    [hud.button addTarget:self
                   action:@selector(cancelWork:)
         forControlEvents:UIControlEventTouchUpInside];

    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        // Do something useful in the background and update the HUD periodically.
        [self doSomeWorkWithProgress];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
}

- (void)cancelWork:(id)sender {
    self.canceled = YES;
}

- (void)doSomeWorkWithProgress {
    self.canceled = NO;
    // This just increases the progress indicator in a loop.
    float progress = 0.0f;
    while (progress < 1.0f) {
        if (self.canceled) break;
        progress += 0.01f;
        dispatch_async(dispatch_get_main_queue(), ^{
            // Instead we could have also passed a reference to the HUD
            // to the HUD to myProgressTask as a method parameter.
            [MBProgressHUD HUDForView:self.navigationController.view].progress = progress;
        });
        usleep(50000);
    }
}

3.4 切換模式

- (void)modeSwitchingExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view
                                              animated:YES];

    // Set some text to show the initial status.
    hud.label.text = NSLocalizedString(@"Preparing...", @"HUD preparing title");
    // Will look best, if we set a minimum size.
    hud.minSize = CGSizeMake(150.f, 100.f);

    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        // Do something useful in the background and update the HUD periodically.
        [self doSomeWorkWithMixedProgress];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
}

- (void)doSomeWorkWithMixedProgress {
    // HUDForView: 找到頂層視圖上的 HUD
    MBProgressHUD *hud = [MBProgressHUD HUDForView:self.navigationController.view];
    // 不確定模式
    sleep(2);
    // 異步主線程悼瘾,切換到確定模式
    dispatch_async(dispatch_get_main_queue(), ^{
        hud.mode = MBProgressHUDModeDeterminate;
        hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");
    });
    float progress = 0.0f;
    while (progress < 1.0f) {
        progress += 0.01f;
        dispatch_async(dispatch_get_main_queue(), ^{
            hud.progress = progress;
        });
        usleep(50000);
    }
    // 異步主線程囊榜,回到不確定模式
    dispatch_async(dispatch_get_main_queue(), ^{
        hud.mode = MBProgressHUDModeIndeterminate;
        hud.label.text = NSLocalizedString(@"Cleaning up...", @"HUD cleanining up title");
    });
    sleep(2);
    // 同步主線程,自定義視圖
    dispatch_sync(dispatch_get_main_queue(), ^{
        UIImage *image = [[UIImage imageNamed:@"Checkmark"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
        UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
        hud.customView = imageView;
        hud.mode = MBProgressHUDModeCustomView;
        hud.label.text = NSLocalizedString(@"Completed", @"HUD completed title");
    });
    sleep(2);
}

4.1 顯示在窗口

- (void)windowExample {
    // 覆蓋整個(gè)屏幕亥宿。 類似于使用根視圖控制器視圖卸勺。
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view.window animated:YES];
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        [self doSomeWork];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
}

4.2 NSURLSession

- (void)networkingExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];

    // Set some text to show the initial status.
    hud.label.text = NSLocalizedString(@"Preparing...", @"HUD preparing title");
    // Will look best, if we set a minimum size.
    hud.minSize = CGSizeMake(150.f, 100.f);

    [self doSomeNetworkWorkWithProgress];
}

- (void)doSomeNetworkWorkWithProgress {
    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
    NSURL *URL = [NSURL URLWithString:@"https://support.apple.com/library/APPLE/APPLECARE_ALLGEOS/HT1425/sample_iPod.m4v.zip"];
    NSURLSessionDownloadTask *task = [session downloadTaskWithURL:URL];
    [task resume];
}

#pragma mark - NSURLSessionDelegate

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
    // Do something with the data at location...

    // Update the UI on the main thread
    dispatch_async(dispatch_get_main_queue(), ^{
        MBProgressHUD *hud = [MBProgressHUD HUDForView:self.navigationController.view];
        UIImage *image = [[UIImage imageNamed:@"Checkmark"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
        UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
        hud.customView = imageView;
        hud.mode = MBProgressHUDModeCustomView;
        hud.label.text = NSLocalizedString(@"Completed", @"HUD completed title");
        [hud hideAnimated:YES afterDelay:3.f];
    });
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
    float progress = (float)totalBytesWritten / (float)totalBytesExpectedToWrite;

    // 在主線程更新 UI 進(jìn)度條
    dispatch_async(dispatch_get_main_queue(), ^{
        MBProgressHUD *hud = [MBProgressHUD HUDForView:self.navigationController.view];
        hud.mode = MBProgressHUDModeDeterminate;
        hud.progress = progress;
    });
}

4.3 帶進(jìn)度條的確定模式

- (void)determinateNSProgressExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
    
    // Set the determinate mode to show task progress.
    hud.mode = MBProgressHUDModeDeterminate;
    hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");
    
    // Set up NSProgress
    NSProgress *progressObject = [NSProgress progressWithTotalUnitCount:100];
    hud.progressObject = progressObject;
    
    // Configure a cancel button.
    [hud.button setTitle:NSLocalizedString(@"Cancel", @"HUD cancel button title") forState:UIControlStateNormal];
    [hud.button addTarget:progressObject action:@selector(cancel) forControlEvents:UIControlEventTouchUpInside];
    
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        // Do something useful in the background and update the HUD periodically.
        [self doSomeWorkWithProgressObject:progressObject];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
}

4.4 Dim background

- (void)dimBackgroundExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
    
    // Change the background view style and color.
    hud.backgroundView.style = MBProgressHUDBackgroundStyleSolidColor;
    hud.backgroundView.color = [UIColor colorWithWhite:0.f alpha:0.1f];
    
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        [self doSomeWork];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
}

MBProgressHUDBackgroundStyle

typedef NS_ENUM(NSInteger, MBProgressHUDBackgroundStyle) {
    /// 純色背景
    MBProgressHUDBackgroundStyleSolidColor,
    /// UIVisualEffectView 或 UIToolbar.layer 背景視圖
    MBProgressHUDBackgroundStyleBlur
};

背景視圖樣式有2種:

MBProgressHUDBackgroundStyleSolidColor:

MBProgressHUDBackgroundStyleBlur

4.5 Colored

- (void)colorExample {
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view
                                              animated:YES];
    hud.contentColor = [UIColor colorWithRed:0.f green:0.6f blue:0.7f alpha:1.f];

    // Set the label text.
    hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");

    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
        [self doSomeWork];
        dispatch_async(dispatch_get_main_queue(), ^{
            [hud hideAnimated:YES];
        });
    });
}

自定義的便捷擴(kuò)展類

為了方便使用,我們可以通過自己封裝一個(gè) Category 擴(kuò)展烫扼,以方便使用孔庭,下面附上我自己封裝的類:

MBProgressHUD+HQL.h

封裝的便捷方法:

  1. 顯示成功 HUD,帶 Image 和 Label材蛛,3 秒后自動(dòng)消失。
  2. 顯示失敗 HUD怎抛,帶 Image 和 Label卑吭,3 秒后自動(dòng)消失。
  3. 顯示文本標(biāo)簽马绝,3 秒后自動(dòng)消失豆赏。
#import <MBProgressHUD/MBProgressHUD.h>

@interface MBProgressHUD (HQL)

#pragma mark - Style 1:Image+Label
/**
 顯示成功 HUD,帶 Image 和 Label富稻,3 秒后自動(dòng)消失掷邦。

 @param text 描述信息
 @param view 顯示HUD的視圖
 */
+ (void)hql_showSuccessHUD:(NSString *)text toView:(UIView *)view;

/**
 在窗口顯示成功 HUD,帶 Image 和 Label椭赋,3 秒后自動(dòng)消失抚岗。

 @param text 標(biāo)簽文字
 */
+ (void)hql_showSuccessHUD:(NSString *)text;

/**
 顯示失敗 HUD,帶 Image 和 Label哪怔,3 秒后自動(dòng)消失宣蔚。

 @param text 描述信息
 @param view 顯示HUD的視圖
 */
+ (void)hql_showErrorHUD:(NSString *)text toView:(UIView *)view;

/**
 顯示失敗 HUD向抢,帶 Image 和 Label,3 秒后自動(dòng)消失胚委。

 @param text  描述信息
 */
+ (void)hql_showErrorHUD:(NSString *)text;


#pragma mark - Style 2:Label

/**
 中心顯示提示標(biāo)簽,3 秒后自動(dòng)消失

 @param message 描述信息
 @param view 顯示HUD的視圖
 */
+ (MBProgressHUD *)hql_showTextHUD:(NSString *)message toView:(UIView *)view;

/**
 在窗口顯示提示標(biāo)簽 HUD,3 秒后自動(dòng)消失

 @param message 描述信息
 */
+ (MBProgressHUD *)hql_showTextHUD:(NSString *)message;

#pragma mark - Hide

+ (void)hql_hideHUDForView:(UIView *)view;
+ (void)hql_hideHUD;

@end

MBProgressHUD+HQL.m

#import "MBProgressHUD+HQL.h"

static const NSTimeInterval KAnimationDuration = 3.0;

@implementation MBProgressHUD (HQL)

#pragma mark - 顯示自動(dòng)隱藏 HUD:Image + Label

+ (void)showCustomHUDWithText:(NSString *)text
               WithImageNamed:(NSString *)name
                       toView:(UIView *)view
                   afterDelay:(NSTimeInterval)delay {
    if (!view) {
        view = [[UIApplication sharedApplication] keyWindow];
    }
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:view animated:YES];
    hud.mode = MBProgressHUDModeCustomView;
    hud.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:name]];
    hud.label.text = [text isNotBlank] ? text : @"錯(cuò)誤提示:返回?cái)?shù)據(jù)為空";
    hud.minSize = CGSizeMake(150.f, 100.f);
    // dim background
    hud.backgroundView.style = MBProgressHUDBackgroundStyleSolidColor;
    hud.backgroundView.color = [UIColor colorWithWhite:0.f alpha:0.1f];
    [hud hideAnimated:YES afterDelay:delay];
}


#pragma mark -
#pragma mark 顯示帶ICON的成功/錯(cuò)誤信息挟鸠,自動(dòng)消失
+ (void)hql_showSuccessHUD:(NSString *)text toView:(UIView *)view {
    [self showCustomHUDWithText:text
                 WithImageNamed:@"password_success"
                         toView:view
                     afterDelay:KAnimationDuration];
}

+ (void)hql_showSuccessHUD:(NSString *)text {
    [self hql_showSuccessHUD:text toView:nil];
}

+ (void)hql_showErrorHUD:(NSString *)text toView:(UIView *)view {
    [self showCustomHUDWithText:text
                 WithImageNamed:@"password_error"
                         toView:view
                     afterDelay:KAnimationDuration];
}

+ (void)hql_showErrorHUD:(NSString *)text {
    [self hql_showErrorHUD:text toView:nil];
}


#pragma mark - 顯示提示標(biāo)簽
+ (MBProgressHUD *)hql_showTextHUD:(NSString *)message toView:(UIView *)view {
    if (!view)  {
        view = [[UIApplication sharedApplication] keyWindow];
    }
    MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:view animated:YES];
    hud.mode = MBProgressHUDModeText;
//    hud.label.text = message;
//    hud.label.textColor = [UIColor whiteColor];
    hud.detailsLabel.text = [message isNotBlank] ? message : @"錯(cuò)誤提示:返回?cái)?shù)據(jù)為空";
    hud.detailsLabel.textColor = [UIColor whiteColor];
    hud.bezelView.color = [[UIColor blackColor] colorWithAlphaComponent:0.8];
    // 3秒后自動(dòng)消失
    [hud hideAnimated:YES afterDelay:KAnimationDuration];
    return hud;
}

#pragma mark 在窗口上顯示提示信息
+ (MBProgressHUD *)hql_showTextHUD:(NSString *)message {
    return [self hql_showTextHUD:message toView:nil];
}

#pragma mark - 隱藏HUD
+ (void)hql_hideHUDForView:(UIView *)view {
    if (view == nil) {
        view = [[UIApplication sharedApplication] keyWindow];
    }
    [self hideHUDForView:view animated:YES];
}

+ (void)hql_hideHUD {
    [self hql_hideHUDForView:nil];
}

@end

參考:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市亩冬,隨后出現(xiàn)的幾起案子艘希,更是在濱河造成了極大的恐慌,老刑警劉巖硅急,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件覆享,死亡現(xiàn)場離奇詭異,居然都是意外死亡铜秆,警方通過查閱死者的電腦和手機(jī)淹真,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來连茧,“玉大人核蘸,你說我怎么就攤上這事⌒パ保” “怎么了客扎?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長罚斗。 經(jīng)常有香客問我徙鱼,道長,這世上最難降的妖魔是什么针姿? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任袱吆,我火速辦了婚禮,結(jié)果婚禮上距淫,老公的妹妹穿的比我還像新娘绞绒。我一直安慰自己,他們只是感情好榕暇,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布蓬衡。 她就那樣靜靜地躺著,像睡著了一般彤枢。 火紅的嫁衣襯著肌膚如雪狰晚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天缴啡,我揣著相機(jī)與錄音壁晒,去河邊找鬼。 笑死业栅,一個(gè)胖子當(dāng)著我的面吹牛讨衣,可吹牛的內(nèi)容都是我干的换棚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼反镇,長吁一口氣:“原來是場噩夢啊……” “哼固蚤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起歹茶,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤夕玩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后惊豺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體燎孟,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年尸昧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了揩页。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡烹俗,死狀恐怖爆侣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情幢妄,我是刑警寧澤兔仰,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站蕉鸳,受9級(jí)特大地震影響乎赴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜潮尝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一榕吼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧勉失,春花似錦羹蚣、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽踢匣。三九已至告匠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間离唬,已是汗流浹背后专。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留输莺,地道東北人戚哎。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓裸诽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親型凳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子丈冬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

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