         }
     }
     
-    open func qmui_setPlaceholder(_ newPlaceholder: String?) {
-        guard let holder = newPlaceholder else {
+    @objc open func qmui_setPlaceholder(_ newPlaceholder: String?) {
+        qmui_setPlaceholder(newPlaceholder)
+        
+        guard let _ = newPlaceholder else {
             return
         }
         
-        if (qmui_placeholderColor != nil || qmui_font != nil) {
-            var attributes[String: String] = []
-        }
-        
-        qmui_setPlaceholder(holder)
-        
-        
+        var attributes = [NSAttributedStringKey : Any]()
+        attributes[NSAttributedStringKey.foregroundColor] = qmui_placeholderColor
+        attributes[NSAttributedStringKey.font] = qmui_font
+        qmui_textField()?.attributedPlaceholder = NSAttributedString(string: newPlaceholder!, attributes: attributes)
+    }
+    
+    @objc open func qmui_layoutSubviews() {
+        qmui_layoutSubviews()
+        
+        fixLandscapeStyle()
+        fixSafeAreaInsetsStyle()
+        
+        if (!UIEdgeInsetsEqualToEdgeInsets(qmui_textFieldMargins, UIEdgeInsets.zero)) {
+            if let newFrame = qmui_textField()?.frame.insetEdges(qmui_textFieldMargins) {
+                qmui_textField()?.frame = newFrame
+            }
+        }
+        
+        fix58InchScreenStyle()
+    }
+    
+    @objc open func qmui_setFrame(_ frame: CGRect) {
+        
+        var newFrame = frame
+        
+        if (!qmui_usedAsTableHeaderView) {
+            qmui_setFrame(newFrame)
+            return;
+        }
+        
+        // 重写 setFrame: 是为了这个 issue：https://github.com/QMUI/QMUI_iOS/issues/233
+        if #available(iOS 11.0, *) {
+            // iOS 11 下用 tableHeaderView 的方式使用 searchBar 的话，进入搜索状态时 y 偏上了，导致间距错乱
+            if !qmui_isActive() {
+                qmui_setFrame(newFrame)
+                return;
+            }
+            
+            if (IS_58INCH_SCREEN) {
+                // 竖屏
+                if (newFrame.minY == 38) {
+                    // searching
+                    newFrame.setY(44)
+                }
+                
+                // 横屏
+                if (newFrame.minY == -6) {
+                    newFrame.setY(0)
+                }
+            } else {
+                // 竖屏
+                if (newFrame.minY == 14) {
+                    newFrame.setY(20)
+                }
+                
+                // 横屏
+                if (newFrame.minY == -6) {
+                    newFrame.setY(0)
+                }
+            }
+            
+            if layer.animationKeys() != nil {
+                // 这一段是为了修复进入/退出搜索状态时的抖动
+                if (superview?.frame.height == (frame.height + StatusBarHeight) && !showsScopeBar) {
+                    newFrame.setHeight(56)
+                }
+            }
+        }
+        
+        qmui_setFrame(newFrame)
+    }
+    
+    private func fixLandscapeStyle() {
+        if !qmui_usedAsTableHeaderView {
+            return
+        }
+        if #available(iOS 11.0, *) {
+            if (qmui_isActive() && IS_LANDSCAPE) {
+                // 11.0 及以上的版本，横屏时，searchBar 内部的内容布局会偏上，所以这里强制居中一下
+                qmui_textField()?.frame.setY(qmui_textField()?.qmui_minYWhenCenterInSuperview ?? 0)
+                qmui_cancelButton()?.frame.setY(qmui_cancelButton()?.qmui_minYWhenCenterInSuperview ?? 0)
+                if let superView = qmui_segmentedControl()?.superview, let bottom = qmui_textField()?.frame.maxY {
+                    if (superView.frame.minY < bottom) {// scopeBar 显示在搜索框右边
+                        let y = superView.bounds.height.center(with: superView.frame.height)
+                        superView.frame.setY(y)
+                    }
+                }
+                
+            }
+         }
+    }
+    
+    private func fixSafeAreaInsetsStyle() {
+        if !qmui_usedAsTableHeaderView {
+            return
+        }
+        if #available(iOS 11.0, *) {
+            // [11.0, 11.1) 这个范围内的 iOS 版本在以 tableHeaderView 的方式使用 searchBar 时，不会根据 safeAreaInsets 自动调整输入框的布局，所以手动处理一下
+            if (IOS_VERSION >= 11.1) {
+                return
+            }
+            if var newframe = qmui_cancelButton()?.frame {
+                let _ = newframe.setX(newframe.minX - safeAreaInsets.left)
+            }
+            
+            var isBelow = false
+            if let superView = qmui_segmentedControl()?.superview, let bottom = qmui_textField()?.frame.maxY {
+                if (superView.frame.minY < bottom) {
+                    isBelow = true
+                }
+            }
+            let isScopeBarShowingAtRightOfTextField = IS_LANDSCAPE && qmui_isActive() && showsScopeBar && isBelow
+            
+            let newLeft = qmui_textField()?.frame.minX ?? 0 + safeAreaInsets.left
+            let _ = qmui_textField()?.frame.setX(newLeft)
+            
+            if (isScopeBarShowingAtRightOfTextField) {
+                // 如果 scopeBar 显示在搜索框右边，则搜索框右边不用调整
+                let scopeBarHorizontalMargin:CGFloat = 16
+                
+                let newLeft = fmax(qmui_textField()?.frame.maxX ?? 0 + scopeBarHorizontalMargin, qmui_segmentedControl()?.superview?.frame.minX ?? 0)
+                var newWidth = qmui_segmentedControl()?.superview?.frame.maxX ?? 0 - newLeft
+                let _ = qmui_segmentedControl()?.superview?.frame.setX(newLeft)
+                let _ = qmui_segmentedControl()?.superview?.frame.setWidth(newWidth)
+                
+                let newRight = fmin(qmui_cancelButton()?.frame.minX ?? 0 - scopeBarHorizontalMargin, qmui_segmentedControl()?.superview?.frame.maxX ?? 0)
+                newWidth = newRight - (qmui_segmentedControl()?.superview?.frame.minX ?? 0)
+                let _ = qmui_segmentedControl()?.superview?.frame.setWidth(newWidth)
+            } else {
+                // 如果 scopeBar 显示在搜索框下方，则搜索框右边要调整到不与 safeAreaInsets 重叠
+                let newRight = qmui_textField()?.frame.maxX ?? 0 - safeAreaInsets.right
+                let newWidth = newRight - (qmui_textField()?.frame.minX ?? 0)
+                qmui_textField()?.frame.setWidth(newWidth)
+            }
+            
+            // 如果是没进入搜索状态就已经显示了 scopeBar，则此时的 scopeBar 一定是在搜索框下方的
+            if (!qmui_isActive() && showsScopeBar) {
+                let newLeft = qmui_segmentedControl()?.frame.minX ?? 0 + safeAreaInsets.left
+                var newWidth = qmui_segmentedControl()?.frame.maxX ?? 0 - newLeft
+                let _ = qmui_segmentedControl()?.frame.setX(newLeft)
+                let _ = qmui_segmentedControl()?.frame.setWidth(newWidth)
+                
+                let newRight = qmui_segmentedControl()?.frame.maxX ?? 0 - safeAreaInsets.right
+                newWidth = newRight - (qmui_segmentedControl()?.frame.minX ?? 0)
+                qmui_segmentedControl()?.frame.setWidth(newWidth)
+            }
+        }
+    }
+    
+    private func fix58InchScreenStyle() {
+        if !qmui_usedAsTableHeaderView {
+            return
+        }
+        
+        if #available(iOS 11.0, *) {
+            // [11.0, 11.1) 范围内的 iOS 版本才会有问题 https://github.com/QMUI/QMUI_iOS/issues/233
+            if (IOS_VERSION >= 11.1) {
+                return
+            }
+            if (!IS_58INCH_SCREEN) {
+                return
+            }
+            
+            guard let backgroundView = qmui_backgroundView() else {
+                return
+            }
+            
+            let isActive = backgroundView.superview?.clipsToBounds ?? false
+            let isFrameError = backgroundView.safeAreaInsets.top > 0 && (backgroundView.frame.minY == 0)
+            if (isActive && isFrameError) {
+                // 修改 backgroundView.frame 会导致 searchBar 在进入搜索状态后背景色变成系统默认的（不知道为什么），所以先取出背景图存起来再设置回去
+                if let originImage = backgroundView.layer.contents {
+                    backgroundView.frame.setY(-backgroundView.safeAreaInsets.top)
+                    let newHeight = backgroundView.frame.maxY - (-backgroundView.safeAreaInsets.top)
+                    let _ = backgroundView.frame.setHeight(newHeight)
+                    backgroundView.layer.contents = originImage
+                }
+            }
+        }
+    }
+    
+    private func qmui_isActive() -> Bool {
+        // 某些情况下 scopeBar 是显示在搜索框右边的，所以要区分判断
+        var scopeBarHeight:CGFloat = qmui_segmentedControl()?.superview?.frame.height ?? 0
+        
+        if let superView = qmui_segmentedControl()?.superview, let bottom = qmui_textField()?.frame.maxY {
+            if (superView.frame.minY < bottom) {
+                scopeBarHeight = 0
+            }
+        }
+        let result = (frame.height - scopeBarHeight == 50)
+        return result
     }
 }
 

                objc_setAssociatedObject(self, &AssociatedKeys.kPlaceholderColor, value, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
                if (placeholder != nil) {
                    // 触发 setPlaceholder 里更新 placeholder 样式的逻辑
//                    self.placeholder = self.placeholder
                }
            }
        }
    }

        static var kUsedAsTableHeaderView = "kUsedAsTableHeaderView"
        static var kPlaceholderColor = "kPlaceholderColor"
        static var kFont = "kFont"
        static var kTextFieldMargins = "kTextFieldMargins"
        static var kTextColor = "kTextColor"
    }

    /// 当以 tableHeaderView 的方式使用 UISearchBar 时，建议将这个属性置为 YES，从而可以帮你处理 https://github.com/QMUI/QMUI_iOS/issues/233 里列出的问题（抖动、iPhone X 适配等）
    /// 默认值为 false
    public var qmui_usedAsTableHeaderView: Bool {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.kUsedAsTableHeaderView) as? Bool ?? false
        }
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.kUsedAsTableHeaderView, newValue, .OBJC_ASSOCIATION_ASSIGN)
        }
    }
    
