MBProgressHUD源碼(上)

来源:https://www.cnblogs.com/zlayne89/archive/2019/06/19/11049970.html
-Advertisement-
Play Games

本篇博文記錄MBProgressHUD源碼學習過程,從官方提供的 "Demo" 項目入手,一步步瞭解其代碼結構,學習它使用的技術,體會作者的編程思想。 一、結構 我們先來看下MBProgressHUD的結構,查看其類的定義。 1.MBProgressHUD是UIView的子類。 2.屬性: 3.其他 ...


本篇博文記錄MBProgressHUD源碼學習過程,從官方提供的Demo項目入手,一步步瞭解其代碼結構,學習它使用的技術,體會作者的編程思想。

一、結構

我們先來看下MBProgressHUD的結構,查看其類的定義。
1.MBProgressHUD是UIView的子類。
2.屬性:

1.
//代理,<MBProgressHUDDelegate>僅定義了一個方法:- (void)hudWasHidden:(MBProgressHUD *)hud;用於執行HUD隱藏之後的操作
@property (weak, nonatomic) id<MBProgressHUDDelegate> delegate;
//執行HUD隱藏之後的操作的Block,目的同上
@property (copy, nullable) MBProgressHUDCompletionBlock completionBlock;
2.
//延遲時間,若任務在graceTime到時之前就完成了,HUD不再展示,即防止為短時間任務顯示HUD
@property (assign, nonatomic) NSTimeInterval graceTime;
//最短展示時間,防止HUD隱藏的過快
@property (assign, nonatomic) NSTimeInterval minShowTime;
//配置HUD是否隱藏之後就從其superview上移除。預設NO
@property (assign, nonatomic) BOOL removeFromSuperViewOnHide;
3.
//指定進度條的樣式,包括菊花、圓餅、環形、水平進度條、自定義樣式和純文本等
@property (assign, nonatomic) MBProgressHUDMode mode;
//內容(label+indicator+customView)顏色
@property (strong, nonatomic, nullable) UIColor *contentColor;
//顯示和隱藏時的動畫類型:Fade(淡入淡出)、Zoom(放大顯示縮小隱藏)、ZoomIn、ZoomOut
@property (assign, nonatomic) MBProgressHUDAnimation animationType;
//內容框(bezelView)距離中心位置的偏移,例如CGPointMake(0.f, MBProgressMaxOffset),內容框會在底部居中
@property (assign, nonatomic) CGPoint offset;
@property (assign, nonatomic) CGFloat margin;//各元素到HUD的邊距
@property (assign, nonatomic) CGSize minSize;//內容框的最小尺寸
@property (assign, nonatomic, getter = isSquare) BOOL square;//強制HUD為方形
@property (assign, nonatomic, getter=areDefaultMotionEffectsEnabled) BOOL defaultMotionEffectsEnabled;//內容框(bezelView)是否受設備加速計的影響,預設YES
4.
@property (assign, nonatomic) float progress;//進度
@property (strong, nonatomic, nullable) NSProgress *progressObject;//進度對象,用於更新進度條
5.
//內容框,即展示實際內容(文本、indicator)的矩形框
@property (strong, nonatomic, readonly) MBBackgroundView *bezelView;
//背景試圖,會覆蓋整個屏幕
@property (strong, nonatomic, readonly) MBBackgroundView *backgroundView;
//自定義視圖用於展示
@property (strong, nonatomic, nullable) UIView *customView;
@property (strong, nonatomic, readonly) UILabel *label;//文本
@property (strong, nonatomic, readonly) UILabel *detailsLabel;//文本下麵的詳細文本
@property (strong, nonatomic, readonly) UIButton *button;//文本下麵的action button

3.其他相關類

(1) MBBackgroundView

  • UIView的子類,在MBPRogressHUD中充當內容框(bezelView)背景視圖(backgroundView)兩種角色。
  • 提供兩種樣式:清晰樣式(MBProgressHUDBackgroundStyleSolidColor)模糊樣式(MBProgressHUDBackgroundStyleBlur)
  • 模糊樣式是通過UIVisualEffectViewUIBlurEffect實現的。

(2) MBRoundProgressView

  • UIView的子類,展示為餅狀/環形的進度條。

(3) MBBarProgressView

  • UIView的子類,展示為條狀的進度條。

(4) MBProgressHUDRoundedButton

  • UIButton的子類,展示位圓角button,作為HUD上的功能按鈕。

知識點:HUD中有個button屬性如下:

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

註意它的註釋Visible only if a target / action is added。也就是說,只有給button添加事件之後,該按鈕才會展示出來。這是如何做到的呢?那就是重寫UIView的函數- (CGSize)intrinsicContentSize:

- (CGSize)intrinsicContentSize {
    // Only show if we have associated control events
    if (self.allControlEvents == 0) return CGSizeZero;
    CGSize size = [super intrinsicContentSize];
    // Add some side padding
    size.width += 20.f;
    return size;
}

這個函數用來設置控制項的內置尺寸。可以看到,通過判斷allControlEvents的個數來判斷button上是否有事件,如果有事件,就在原來內置的尺寸上加20。

二、代碼追蹤

瞭解了MBProgressHUD的基本結構之後,接下來我們就看看具體的功能是如何實現的。HUDDemo提供了15個樣例,我們選取純文本載入(菊花)條狀進度條自定義視圖進行分析,其他的樣例與它們類似。

1.純文本(Text)

我們先從最簡單的純文本開始。啟動HUDDemo項目,點開MBHudDemoViewController.m文件,找到函數- (void)textExample{…},這個函數就是顯示純文本的處理函數:

- (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");
    // Move to bottm center.
    hud.offset = CGPointMake(0.f, MBProgressMaxOffset);

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

① 進入到函數showHUDAddedTo:animated:中查看MBProgressHUD實例的創建過程:

  • initWithView:->initWithFrame:->commonInit

    使用self.navigationController.view的bounds初始化HUD,然後在commonInit里指定動畫類型(Fade)、HUD模式(菊花)、間距(20)、內容顏色(黑色半透明)。除此之外,還設置HUD為完全透明,背景色為clear,配置HUD的尺寸自動調整

    //保證上下間距比例不變、左右間距比例不變,即防止橫豎屏切換時HUD位置錯誤
    self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    //讓HUD的各個子視圖自己控制自己的透明度,使其不受HUD透明度的影響
    self.layer.allowsGroupOpacity = NO;
  • [self setupViews]

    在這個函數中真正執行子視圖的創建工作。

    • 背景視圖(backgroundView)

      為類MBBackgroundView的實例。MBBackgroundView實例預設會創建成白色半透明模糊效果,並覆蓋全屏,但在本例中,創建完成之後會更改其styleMBProgressHUDBackgroundStyleSolidColor,並將背景色設置為透明(clear)。

    • 內容框(bezelView)

      同為類MBBackgroundView實例,是實際展示內容的View(即中間的黑框),包含文本、indicator、進度條等。bezelView會預設創建成白色半透明模糊效果,但frame為0。創建後會設置其邊角半徑為5。

      知識點:作者為bezelView添加了MotionEffect,也就是說在bezelView顯示的時候,它會根據手機的傾斜方向調整自己的位置!

      - (void)updateBezelMotionEffects {
      #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 || TARGET_OS_TV
          MBBackgroundView *bezelView = self.bezelView;
          if (![bezelView respondsToSelector:@selector(addMotionEffect:)]) return;
      
          if (self.defaultMotionEffectsEnabled) {
              CGFloat effectOffset = 10.f;
              UIInterpolatingMotionEffect *effectX = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
              effectX.maximumRelativeValue = @(effectOffset);
              effectX.minimumRelativeValue = @(-effectOffset);
      
              UIInterpolatingMotionEffect *effectY = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
              effectY.maximumRelativeValue = @(effectOffset);
              effectY.minimumRelativeValue = @(-effectOffset);
      
              UIMotionEffectGroup *group = [[UIMotionEffectGroup alloc] init];
              group.motionEffects = @[effectX, effectY];
      
              [bezelView addMotionEffect:group];
          } else {
              NSArray *effects = [bezelView motionEffects];
              for (UIMotionEffect *effect in effects) {
                  [bezelView removeMotionEffect:effect];
              }
          }
      #endif
      }
    • label和detailsLabel

      設置顯示文字的label,其中detailsLabel允許多行。

    • button

      MBProgressHUDRoundedButton的實例,作為HUD上的功能按鈕,比如進度條下方可以顯示一個"取消"按鈕。

    • topSpacer和bottomSpacer

      均為UIView的實例,用於調節上下間距的輔助View。

    • 設置label、detailsLabel及button的抗壓繫數,並添加到父視圖上。

      for (UIView *view in @[label, detailsLabel, button]) {
          view.translatesAutoresizingMaskIntoConstraints = NO;//自己手動管理約束
          [view setContentCompressionResistancePriority:998.f forAxis:UILayoutConstraintAxisHorizontal];//設置水平抗壓縮繫數,值越大,越不容易被壓縮
          [view setContentCompressionResistancePriority:998.f forAxis:UILayoutConstraintAxisVertical];//設置垂直抗壓縮繫數,值越大,越不容易被壓縮
          [bezelView addSubview:view];
      }
  • [self updateIndicators]

    HUD的indicatorUIView的實例,用來記錄HUD上顯示的視圖,進度條、載入圖標(菊花)、自定義視圖等都是用HUD的indicator屬性記錄的。在函數- (void)updaetIndicators中,根據HUD的mode值配置不同的indicator。最後會調用[self setNeedsUpdateConstraints]觸發約束更新函數-(void)updateConstraints來更新UI。

  • [self registerForNotifications]

    註冊通知,處理屏幕旋轉的問題。

② 在創建完HUD之後,會調用[hud showAnimated:animated];將HUD展示到屏幕上。事實上,雖然當前HUD已經在屏幕上了,但由於初始化HUD的時候bezelView的frame為0,用戶看不到。

③ 配置HUD實例的屬性

hud.mode = MBProgressHUDModeText;//設置hud只顯示純文本
hud.label.text = NSLocalizedString(@"Message here!", @"HUD message title");//設置文本內容
hud.offset = CGPointMake(0.f, MBProgressMaxOffset);//設置hud相對於中心位置的偏移

在mode的setter函數中會調用- (void)updateIndicators,根據mode的新值重新配置indicator,然後調用- (void)setNeedsUpdateConstraints觸發-(void)updateConstraints來更新UI。而在offset的setter函數中會直接調用- (void)setNeedsUpdateConstraints觸發-(void)updateConstraints來更新UI。

④ 在函數- (void)updateConstraints中更新佈局:

  • 刪除所有控制項的constraints
  • 通過NSLayoutConstraint重新設置constraints
//1.以屏幕中心為基準,應用offset。priority = 998
CGPoint offset = self.offset;
NSMutableArray *centeringConstraints = [NSMutableArray array];
//x
[centeringConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.f constant:offset.x]];
//y
[centeringConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.f constant:offset.y]];
//為每個constraints設置priority
[self applyPriority:998.f toConstraints:centeringConstraints];
[self addConstraints:centeringConstraints];

//2.設置最小間距約束,priority = 999 
NSMutableArray *sideConstraints = [NSMutableArray array];
[sideConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>=margin)-[bezel]-(>=margin)-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(bezel)]];
[sideConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=margin)-[bezel]-(>=margin)-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(bezel)]];
[self applyPriority:999.f toConstraints:sideConstraints];
[self addConstraints:sideConstraints];

//3.bezel的最小尺寸約束 priority = 997
CGSize minimumSize = self.minSize;
if (!CGSizeEqualToSize(minimumSize, CGSizeZero)) {
  NSMutableArray *minSizeConstraints = [NSMutableArray array];
  [minSizeConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:minimumSize.width]];
  [minSizeConstraints addObject:[NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:minimumSize.height]];
  [self applyPriority:997.f toConstraints:minSizeConstraints];
  [bezelConstraints addObjectsFromArray:minSizeConstraints];
}

//4.方形約束 priority=997
if (self.square) {
    NSLayoutConstraint *square = [NSLayoutConstraint constraintWithItem:bezel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeWidth multiplier:1.f constant:0];
    square.priority = 997.f;
    [bezelConstraints addObject:square];
}

//5.根據margin和設置上下spacer的間距約束
[topSpacer addConstraint:[NSLayoutConstraint constraintWithItem:topSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:margin]];
[bottomSpacer addConstraint:[NSLayoutConstraint constraintWithItem:bottomSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.f constant:margin]];

[bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:topSpacer attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:bottomSpacer attribute:NSLayoutAttributeHeight multiplier:1.f constant:0.f]];

//6.設置bezel子視圖(topSpacer、label、detailLabel、button、bottomSpacer)的約束
[subviews enumerateObjectsUsingBlock:^(UIView *view, NSUInteger idx, BOOL *stop) {
        // Center in bezel
        [bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeCenterX multiplier:1.f constant:0.f]];
        // Ensure the minimum edge margin is kept
        [bezelConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"|-(>=margin)-[view]-(>=margin)-|" options:0 metrics:metrics views:NSDictionaryOfVariableBindings(view)]];
        // Element spacing
        if (idx == 0) {
            // First, ensure spacing to bezel edge
            [bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeTop multiplier:1.f constant:0.f]];
        } else if (idx == subviews.count - 1) {
            // Last, ensure spacing to bezel edge
            [bezelConstraints addObject:[NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:bezel attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f]];
        }
        if (idx > 0) {
            // Has previous
            NSLayoutConstraint *padding = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:subviews[idx - 1] attribute:NSLayoutAttributeBottom multiplier:1.f constant:0.f];
            [bezelConstraints addObject:padding];
            [paddingConstraints addObject:padding];
        }
}];
[bezel addConstraints:bezelConstraints];
self.bezelConstraints = bezelConstraints;

self.paddingConstraints = [paddingConstraints copy];
[self updatePaddingConstraints];//在該函數里,根據子視圖的可視性(hidden),設置子視圖的上下間距(為4)

通過上面的priority可以知道優先順序:最小間距約束>bezel的偏移約束>bezel最小尺寸約束=方形約束。因此,如果你設置了hud.square = YES,但是實際bezel並沒有變為方形,則很可能是因為上面的這幾個約束之間存在衝突,系統採用了高優先順序的約束而忽略了square約束。不信你可以把square優先順序改為1000試試看:)

知識點:這裡出現了一個巨集NSDictionaryOfVariableBindings,它可以用來方便的創建NSDictionary:

UIView *view1 = [UIView new];
UIView *view2 = [UIView new];
NSDictionary *dict = NSDictionaryOfVariableBindings(view1,view2);//{@"view1":view1,@"view2":view2}

總結:

​ 至此,我們來總結下純文本HUD的整個創建及顯示流程:

  1. 調用[MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES]創建HUD實例:包括配置屬性預設值(動畫類型、HUD樣式、間距、內容顏色等),初始化view(backgroundView、bezelView、label、detailLabel、button、topSpacer、bottomSpacer),且會預設創建一個indicator。之後hud會顯示在屏幕上,但由於約束未觸發,因此用戶看不到。
  2. hud.mode = MBProgressHUDModeText。HUD會根據mode的值去隱藏indicator,並更新約束。
  3. hud.label.text = NSLocalizedString(@"Message here!", @"HUD message title")設置要顯示的文字。
  4. hud.offset = CGPointMake(0.f, MBProgressMaxOffset)設置bezelView的偏移屬性:讓其顯示在最底部。並更新約束。
  5. [hud hideAnimated:YES afterDelay:3.f]設置一個延遲timer,在3s之後隱藏hud。隱藏之後調用completionBlock和代理方法- (void)hudWasHidden:(MBProgressHUD *)hud;

2.載入(菊花)

載入樣式表現為一個旋轉的菊花,底部也可包含"Loading…"等字樣提示。我們以包含"Loading…"字樣的HUD為例剖析其內部原理。代碼如下:

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

    // Set the label text.
    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];
        });
    });
}
  • 調用MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];創建HUD實例,過程跟純文本是一樣的。
  • hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");配置提示文案為"Loading"。
  • 之後在global_queue裡面執行任務,完成任務之後回到主線程隱藏HUD。

通過分析純文本HUD的創建過程我們知道,hud在初始化的時候,它的mode預設為MBProgressHUDModeIndeterminate,也就是說單純的調用MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];創建出來的HUD就是帶有菊花載入控制項的HUD,我們接下來做的就是給它的label賦上文案即可。

3.條狀進度條

MBProgressHUD提供了三種樣式的進度條:條狀、餅狀、環狀。其中餅狀和環狀差不多,接下來我們分析下條狀進度條的實現原理:

- (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];
        });
    });
}
  • 調用MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];創建HUD實例,過程跟純文本是一樣的。
  • hud.mode = MBProgressHUDModeDeterminateHorizontalBar;設置mode為條狀進度條。在mode的setter方法中會調用- (void)updateIndicator創建進度條indicator。
  • 進度條indicator是類MBBarProgressView的實例。創建時預設寬為120,高為20,內容高度(intrinsicContentSize)為10。它的樣式是在- (void)drawRect中繪製的。在其progress屬性的setter方法中調用了-(void)setNeedsDisplay從而觸發- (void)drawRect來更新進度。
  • hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");配置HUD提示文案為"Loading"。

4.自定義視圖

MBProgressHUD提供了顯示自定義視圖的功能。在Demo中是展示一個對勾。

- (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];
}
  • 調用MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];創建HUD實例,過程跟純文本是一樣的。
  • hud.mode = MBProgressHUDModeCustomView;設置mode為自定義視圖。接下來將需要展示的自定義視圖賦值給hud的customView屬性。在customView屬性的setter方法中會調用- (void)updateIndicatorscustomView添加到HUD上。
  • 為了讓界面美觀,規定hud顯示為方形:hud.square = YES;
  • hud.label.text = NSLocalizedString(@"Loading...", @"HUD loading title");配置HUD提示文案為"Loading"。

至此,我們已經簡單瞭解了MBProgressHUD的整個代碼結構及使用流程,這已經足夠我們去創建和使用符合我們需求的HUD了。但其實MBProgressHUD的源碼中還包含不少高級的技術細節,我們將在下篇文章中一個個分析學習。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • sql註入判斷流程(結合sqli labs學習) 類型一 1. 類型判斷 ?id=1 and 1=2 + 如果返回結果正常,說明不是數字類型 and 為兩方都為真才算爭取 ?id=1' + 顯示不正常 ?id=1') + 若顯示正常,則該類型為字元註入,且以('')的方式閉合字元串,還有("") + ...
  • 更改oracle RAC public ip,vip,scan ip和private ip oifcfg - Oracle 介面配置工具 用法: oifcfg iflist [-p [-n]] oifcfg setif {-node | -global} {/:}... oifcfg getif [ ...
  • 資料庫設計 1. 說在前面 項目開發的流程包括哪些環節 (1) 根據市場公司需求分析公司是否需要開發軟體來輔助日常工作 (2) 公司高層市場考察,市場分析,決定做什麼軟體。 (3) 不懂技術的人想象軟體應該有什麼功能,長什麼樣子 (1) 根據領導的需求設計出產品的原型(圖紙) ① 有具體的功能,功能 ...
  • 版權聲明:本文為xing_star原創文章,轉載請註明出處! 本文同步自http://javaexception.com/archives/130 微信好友檢測助手App 最近幾周,寫了個微信好友檢測助手App,寫這個的初衷是為了低成本的讓用戶檢測自己微信上刪除或拉黑自己的好友,不考慮用xposed ...
  • 例如需求,我有一個WebView 載入一個url, 該url對應的網頁本身自帶下拉刷新 ,但是網頁本身會有出現400 500 等異常請求錯誤碼 這時候網頁載入失敗,頁面本身的下拉是無法使用的,要求重新載入頁面的話就需要在webview外層套一個android下拉控制項(SwipeRefreshLayo ...
  • Hi3120是海思的一款高性能視頻掃描格式轉換晶元。該晶元集成了降噪、去隔行、平滑縮放、視頻增強、微控制器、圖形界面菜單等多項功能,能從PAL、NTSC、高清等彩色電視信號中去除雜訊以提取清晰的圖像信號,並兼480P/576P/720P/10801/1080PNGA/SVGA/XGA/UXGA等多種 ...
  • 通過VOLUME_UP,VOLUME_DOWN調節atv的聲音,不變化,只有調到靜音的時候,才沒有聲音,界面上的聲音大小是顯示對的.[Solution]這類問題常見的原因是音頻參數沒有進行設置,使用原始release預設的參數,而預設的參數在各版本上0-6均為255,導致調節音量等級,聲音大小無變化 ...
  • Objective-C語言的動態性主要體現在以下3個方面 (1)動態類型:運行時確定對象的類型。 (2)動態綁定:運行時確定對象的方法。 (3)動態載入:運行時載入需要的資源或者或代碼模塊。 一、動態類型 動態類型指對象指針類型的動態性,具體地說就是使用id類型將對象的類型推遲到運行時才確定,由賦給 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...