Commit 7dadafe9 authored by yqz's avatar yqz

init

parent e9fc7fcd
...@@ -11,6 +11,15 @@ target 'SpeakEasyLearnEnglish' do ...@@ -11,6 +11,15 @@ target 'SpeakEasyLearnEnglish' do
pod 'Moya', '~> 15.0.0' pod 'Moya', '~> 15.0.0'
pod 'lottie-ios', '~> 4.5.2' pod 'lottie-ios', '~> 4.5.2'
pod 'SnapKit', '~> 5.7.1' pod 'SnapKit', '~> 5.7.1'
pod 'YYText'
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '15.0' # Exclude arm64 for simulator
end
end
end
end end
{
"images" : [
{
"filename" : "icon_Settings_weixuan.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "icon_Settings_weixuan@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon_Settings_weixuan@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
{ {
"images" : [ "images" : [
{ {
"filename" : "icon_home_yixuan.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"filename" : "icon_home_yixuan@2x.png", "filename" : "Back@2x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"filename" : "icon_home_yixuan@3x.png", "filename" : "Back@3x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x" "scale" : "3x"
} }
......
{ {
"images" : [ "images" : [
{ {
"filename" : "icon_home_weixuan.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"filename" : "icon_home_weixuan@2x.png", "filename" : "Shut@2x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"filename" : "icon_home_weixuan@3x.png", "filename" : "Shut@3x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x" "scale" : "3x"
} }
......
{ {
"images" : [ "images" : [
{ {
"filename" : "icon_Settings_yixuan.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "1x" "scale" : "1x"
}, },
{ {
"filename" : "icon_Settings_yixuan@2x.png", "filename" : "bg@2x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "2x" "scale" : "2x"
}, },
{ {
"filename" : "icon_Settings_yixuan@3x.png", "filename" : "bg@3x.png",
"idiom" : "universal", "idiom" : "universal",
"scale" : "3x" "scale" : "3x"
} }
......
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<scenes> <scenes>
...@@ -11,15 +14,32 @@ ...@@ -11,15 +14,32 @@
<objects> <objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController"> <viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> <subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sp-bg" translatesAutoresizingMaskIntoConstraints="NO" id="6w9-Kp-lLi">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
</imageView>
</subviews>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/> <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="6w9-Kp-lLi" secondAttribute="bottom" id="Rkz-ov-EAY"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="trailing" secondItem="6w9-Kp-lLi" secondAttribute="trailing" id="clk-Uo-Uk1"/>
<constraint firstItem="6w9-Kp-lLi" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" id="fpJ-cC-akj"/>
<constraint firstItem="6w9-Kp-lLi" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="vaQ-ho-AjH"/>
</constraints>
</view> </view>
</viewController> </viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects> </objects>
<point key="canvasLocation" x="53" y="375"/> <point key="canvasLocation" x="52.671755725190835" y="374.64788732394368"/>
</scene> </scene>
</scenes> </scenes>
<resources>
<image name="sp-bg" width="402" height="874"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document> </document>
...@@ -16,8 +16,18 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ...@@ -16,8 +16,18 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
_ = SpeakVideoPlayer.share _ = SpeakVideoPlayer.share
// Override point for customization after application launch.
#if DEBUG
// // 获取所有可用字体家族名称
// let fontFamilyNames = UIFont.familyNames
// for familyName in fontFamilyNames {
// print("字体家族: \(familyName)")
// let fontNames = UIFont.fontNames(forFamilyName: familyName)
// for fontName in fontNames {
// print(" 字体: \(fontName)")
// }
// }
#endif
return true return true
} }
......
...@@ -14,7 +14,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { ...@@ -14,7 +14,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return } guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene) window = UIWindow(windowScene: windowScene)
window?.rootViewController = SpeakEleBaseNavigationCtr(rootViewController: SpeakEleTabbarViewCtr()) window?.rootViewController = SpeakEleLaunchViewCtr()
window?.makeKeyAndVisible() window?.makeKeyAndVisible()
UIScrollView.appearance().contentInsetAdjustmentBehavior = .never UIScrollView.appearance().contentInsetAdjustmentBehavior = .never
UITableView.appearance().contentInsetAdjustmentBehavior = .never UITableView.appearance().contentInsetAdjustmentBehavior = .never
......
...@@ -17,13 +17,72 @@ class SpeakEleBaseViewCtr: UIViewController { ...@@ -17,13 +17,72 @@ class SpeakEleBaseViewCtr: UIViewController {
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) super.viewWillAppear(animated)
setup() setup()
titleView.snp.makeConstraints { make in
make.left.right.top.equalToSuperview()
make.height.equalTo(Dev.navHeight + Dev.safeAreaInsets.top)
}
titleView.isHidden = !(self.navigationController?.viewControllers.count ?? 0 > 1)
} }
func setup() -> Void { func setup() -> Void {
} }
@objc func PopViewCtr() -> Void {
self.navigationController?.popViewController(animated: true)
}
deinit { deinit {
Print("\(type(of: self)) deinit") Print("\(type(of: self)) deinit")
} }
override var title: String? {
didSet {
titleView.titleLabel.text = title
}
}
lazy var titleView: SpeakTitleView = {
let titleV = SpeakTitleView()
view.addSubview(titleV)
titleV.backBtn.addTarget(self, action: #selector(PopViewCtr), for: .touchUpInside)
return titleV
}()
}
class SpeakTitleView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setupUI()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupUI() -> Void {
titleLabel.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.bottom.equalToSuperview()
make.top.equalToSuperview().offset(Dev.safeAreaInsets.top)
}
backBtn.snp.makeConstraints { make in
make.left.equalToSuperview().inset(marginLR)
make.centerY.equalTo(titleLabel)
}
}
lazy var titleLabel: UILabel = {
let label = UILabel()
addSubview(label)
return label
}()
lazy var backBtn: UIButton = {
let back = UIButton(type: .custom)
back.setImage(UIImage(named: "sp-Back"), for: .normal)
addSubview(back)
return back
}()
} }
//
// SpeakEleWebViewCtr.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/10.
//
import UIKit
import WebKit
class SpeakEleWebViewCtr: SpeakEleBaseViewCtr, WKUIDelegate ,WKNavigationDelegate, UIScrollViewDelegate ,WKScriptMessageHandler {
lazy var funcNameArray:[String] = []
private lazy var webView: WKWebView = {
let webConfiguration = WKWebViewConfiguration()
webConfiguration.applicationNameForUserAgent = "iOS"
let webView1:WKWebView = WKWebView(frame:CGRect(x: 0, y: Dev.navHeight + Dev.safeAreaInsets.top, width: Dev.screenW, height: Dev.screenH - (Dev.navHeight + Dev.safeAreaInsets.top)),configuration: webConfiguration)
webView1.scrollView.showsVerticalScrollIndicator = false
webView1.scrollView.showsHorizontalScrollIndicator = false
webView1.allowsLinkPreview = false
webView1.scrollView.backgroundColor = .white
webView1.allowsBackForwardNavigationGestures = true
webView1.backgroundColor = .white
webView1.uiDelegate = self
webView1.navigationDelegate = self
webView1.scrollView.delegate = self
if #available(iOS 11.0, *) {
webView1.scrollView.contentInsetAdjustmentBehavior = .never
}
for name in funcNameArray {
webView1.configuration.userContentController.add(self, name: name)
}
view.addSubview(webView1)
return webView1
}()
private lazy var activityView:UIActivityIndicatorView = {
let activityView = UIActivityIndicatorView()
activityView.width = 24.adapterW()
activityView.height = 24.adapterW()
activityView.centerX = view.width / 2.0
activityView.centerY = (view.height - Dev.navHeight) / 2.0
activityView.color = .black
activityView.hidesWhenStopped = true
let transform:CGAffineTransform = CGAffineTransformMakeScale(24.adapterW() / 20,24.adapterW() / 20);
activityView.transform = transform;
activityView.startAnimating()
view.addSubview(activityView)
return activityView
}()
func LoadWithUrl(url:String) {
if url.count == 0 {
return
}
let newUrl = url.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
guard let URL1 = URL(string:newUrl) else { return }
let request = URLRequest(url: URL1)
webView.load(request)
activityView.isHidden = false
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
}
}
extension SpeakEleWebViewCtr {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
activityView.stopAnimating()
webView.evaluateJavaScript("document.documentElement.style.webkitUserSelect='none';") { any1, error1 in}
webView.evaluateJavaScript("document.documentElement.style.webkitTouchCallout='none';", completionHandler: nil)
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
activityView.stopAnimating()
Print("网页加载失败:\(error.localizedDescription)")
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
activityView.stopAnimating()
Print("网页加载失败:\(error.localizedDescription)")
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
guard let url = navigationAction.request.url else {
decisionHandler(.cancel)
return
}
let scheme = url.absoluteString.lowercased()
if scheme.contains("/stdeula") {
UIApplication.shared.open(url)
decisionHandler(.cancel)
}else{
decisionHandler(.allow)
}
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
}
}
...@@ -12,3 +12,23 @@ let isDebug = true ...@@ -12,3 +12,23 @@ let isDebug = true
#else #else
let isDebug = false let isDebug = false
#endif #endif
let marginLR = 24
enum SpeakEasyAssociatedKeys : UInt32 {
case fontsize = 0x101010
case UnsafeCallBack = 0x10000
case labelTextTap = 0x10001
}
protocol CutomFontProtocol {
var fontSize:CGFloat { get set }
var cutomFont:Int { get }
}
enum UnsafeRawUserDefaultsKey:String {
case UnsafeThreeDayGuide = "UnsafeThreeDayGuide"
}
...@@ -7,18 +7,42 @@ ...@@ -7,18 +7,42 @@
import UIKit import UIKit
extension String { extension String {
func attributed() -> AttributedStringBuilder { func attributed() -> AttributedStringBuilder {
return AttributedStringBuilder(self) return AttributedStringBuilder(self)
} }
// 支持多个字符串组合的富文本 // 支持多个字符串组合的富文本
func combined(with other: NSAttributedString) -> NSAttributedString { func combined(with other: [Any]) -> NSAttributedString {
let result = NSMutableAttributedString(string: self) let result = NSMutableAttributedString(string: self)
result.append(other) other.forEach { objc in
if let v = objc as? String {
result.append(NSAttributedString(string: v))
}else if let v = objc as? NSAttributedString {
result.append(v)
}
}
return result return result
} }
} }
extension NSAttributedString {
// 支持多个字符串组合的富文本
func combined(with other: [Any]) -> NSAttributedString {
let result = NSMutableAttributedString(attributedString: self)
other.forEach { objc in
if let v = objc as? String {
result.append(NSAttributedString(string: v))
}else if let v = objc as? NSAttributedString {
result.append(v)
}
}
return result
}
}
class AttributedStringBuilder { class AttributedStringBuilder {
private var attributes: [NSAttributedString.Key: Any] = [:] private var attributes: [NSAttributedString.Key: Any] = [:]
......
//
// UIButton+Extension.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/10.
//
import UIKit
extension UIButton : CutomFontProtocol {
@IBInspectable var fontSize:CGFloat {
set {
var state = SpeakEasyAssociatedKeys.fontsize.rawValue
objc_setAssociatedObject(self, &state, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
var state = SpeakEasyAssociatedKeys.fontsize.rawValue
let size = objc_getAssociatedObject(self, &state) as? CGFloat
return size ?? 12
}
}
@IBInspectable var cutomFont:Int {
set {
switch newValue {
case 0:
self.titleLabel?.font = UIFont.montserrat(.regular ,size: fontSize)
break
case 1:
self.titleLabel?.font = UIFont.montserrat(.medium ,size: fontSize)
break
case 2:
self.titleLabel?.font = UIFont.montserrat(.semiBold ,size: fontSize)
break
default:
self.titleLabel?.font = UIFont.montserrat(.bold ,size: fontSize)
break
}
}
get {
return 0
}
}
}
...@@ -6,38 +6,116 @@ ...@@ -6,38 +6,116 @@
// //
import UIKit import UIKit
import CoreText
extension UILabel { fileprivate var state = SpeakEasyAssociatedKeys.fontsize.rawValue
fileprivate var textTapState = SpeakEasyAssociatedKeys.labelTextTap.rawValue
@IBDesignable
extension UILabel : CutomFontProtocol{
/// 设置文字间距
func lineSpacing(_ lineSpacing:CGFloat = 5) {
let style = NSMutableParagraphStyle()
style.lineSpacing = lineSpacing
style.alignment = self.textAlignment
self.attributedText = NSAttributedString(string: self.text ?? "", attributes: [NSAttributedString.Key.paragraphStyle: style])
self.sizeToFit()
}
@IBInspectable var spacing: CGFloat { @IBInspectable var fontSize:CGFloat {
set {
objc_setAssociatedObject(self, &state, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get { get {
guard let attributedText = self.attributedText, let size = objc_getAssociatedObject(self, &state) as? CGFloat
let paragraphStyle = attributedText.attributes(at: 0, effectiveRange: nil)[.paragraphStyle] as? NSParagraphStyle else { return size ?? 12
return 0 }
}
@IBInspectable var cutomFont:Int {
set {
switch newValue {
case 0:
self.font = UIFont.montserrat(.regular ,size: fontSize)
break
case 1:
self.font = UIFont.montserrat(.medium ,size: fontSize)
break
case 2:
self.font = UIFont.montserrat(.semiBold ,size: fontSize)
break
default:
self.font = UIFont.montserrat(.bold ,size: fontSize)
break
} }
return paragraphStyle.lineSpacing
} }
get {
return 0
}
}
var textTaps:[String] {
set { set {
guard let text = self.text else { return } objc_setAssociatedObject(self, &textTapState, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
if let attributedText = self.attributedText { }
let mutableAttributedText = NSMutableAttributedString(attributedString: attributedText) get {
let paragraphStyle = NSMutableParagraphStyle() return objc_getAssociatedObject(self, &textTapState) as? [String] ?? []
paragraphStyle.lineSpacing = newValue }
paragraphStyle.alignment = self.textAlignment }
mutableAttributedText.addAttribute(.paragraphStyle,
value: paragraphStyle, func AddTextTap(_ text:[String]) -> Void {
range: NSRange(location: 0, length: mutableAttributedText.length)) if text.count > 0 {
self.attributedText = mutableAttributedText textTaps = text
} else { self.gesture(target: self, class: UITapGestureRecognizer.self, selector: #selector(handleTap(_:)))
let attributedString = NSMutableAttributedString(string: text) }
let paragraphStyle = NSMutableParagraphStyle() }
paragraphStyle.lineSpacing = newValue
paragraphStyle.alignment = self.textAlignment @objc private func handleTap(_ gesture: UITapGestureRecognizer) {
attributedString.addAttribute(.paragraphStyle, guard let attributedText = attributedText else { return }
value: paragraphStyle, let framesetter = CTFramesetterCreateWithAttributedString(attributedText as CFAttributedString)
range: NSRange(location: 0, length: text.count)) let path = CGMutablePath()
path.addRect(bounds)
self.attributedText = attributedString let frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, nil)
let location = gesture.location(in: self)
let lines = CTFrameGetLines(frame) as! [CTLine]
var lineOrigins = [CGPoint](repeating: .zero, count: lines.count)
CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), &lineOrigins)
for (index, line) in lines.enumerated() {
let lineOrigin = lineOrigins[index]
var ascent: CGFloat = 0
var descent: CGFloat = 0
var leading: CGFloat = 0
let lineWidth = CTLineGetTypographicBounds(line, &ascent, &descent, &leading)
let lineHeight = ascent + descent + leading
let lineTop = lineOrigin.y
let lineBottom = lineOrigin.y + lineHeight
if location.y >= lineTop && location.y <= lineBottom {
let xOffset: CGFloat
switch textAlignment {
case .left, .natural, .justified:
xOffset = lineOrigin.x
case .center:
xOffset = lineOrigin.x + (bounds.width - lineWidth) / 2
case .right:
xOffset = lineOrigin.x + bounds.width - lineWidth
@unknown default:
xOffset = lineOrigin.x
}
let offsetInLine = location.x - xOffset
let indexOfCharacter = CTLineGetStringIndexForPosition(line, CGPoint(x: offsetInLine, y: location.y))
for targetText in textTaps {
if let range = attributedText.string.range(of: targetText) {
let nsRange = NSRange(range, in: attributedText.string)
if indexOfCharacter >= nsRange.location && indexOfCharacter < nsRange.location + nsRange.length {
return
}
}
}
break
} }
} }
} }
......
...@@ -7,17 +7,16 @@ ...@@ -7,17 +7,16 @@
import UIKit import UIKit
fileprivate var state = SpeakEasyAssociatedKeys.UnsafeCallBack.rawValue
@IBDesignable @IBDesignable
extension UIView { extension UIView {
@objc public var callblack:((Any)->Void)? { @objc public var callblack:((Any)->Void)? {
set { set {
var state = UnsafeRawPointerState.UnsafeCallBack.rawValue
objc_setAssociatedObject(self, &state, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) objc_setAssociatedObject(self, &state, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
} }
get { get {
var state = UnsafeRawPointerState.UnsafeCallBack.rawValue
return objc_getAssociatedObject(self, &state) as? ((Any)->Void) return objc_getAssociatedObject(self, &state) as? ((Any)->Void)
} }
} }
...@@ -81,6 +80,7 @@ extension UIView { ...@@ -81,6 +80,7 @@ extension UIView {
@IBInspectable var corners:Double { @IBInspectable var corners:Double {
set { set {
self.layer.cornerRadius = newValue self.layer.cornerRadius = newValue
self.clipsToBounds = true
} }
get { get {
return self.layer.cornerRadius return self.layer.cornerRadius
...@@ -91,6 +91,7 @@ extension UIView { ...@@ -91,6 +91,7 @@ extension UIView {
@IBInspectable var borderColor:UIColor { @IBInspectable var borderColor:UIColor {
set { set {
self.layer.borderColor = newValue.cgColor self.layer.borderColor = newValue.cgColor
self.clipsToBounds = true
} }
get { get {
return UIColor(cgColor: self.layer.borderColor ?? UIColor.clear.cgColor) return UIColor(cgColor: self.layer.borderColor ?? UIColor.clear.cgColor)
...@@ -137,11 +138,22 @@ extension UIView { ...@@ -137,11 +138,22 @@ extension UIView {
self.layer.cornerRadius = cornerRadius self.layer.cornerRadius = cornerRadius
} }
/// 添加渐变
enum UnsafeRawPointerState:UInt32 { func gradient(colors: [UIColor], direction: gradientTion = .leftToRight, cornerRadius: CGFloat = 0) {
case UnsafeCallBack = 0x10000 self.layer.sublayers?.filter { $0 is CAGradientLayer }.forEach { $0.removeFromSuperlayer() }
let gradientLayer = CAGradientLayer()
gradientLayer.colors = colors.map { $0.cgColor }
gradientLayer.locations = [0.0, 1.0] // 渐变位置
gradientLayer.startPoint = direction.startPoint
gradientLayer.endPoint = direction.endPoint
gradientLayer.frame = self.bounds
gradientLayer.cornerRadius = cornerRadius
gradientLayer.zPosition = -10
self.layer.insertSublayer(gradientLayer, at: 0)
} }
enum Gesture{ enum Gesture{
case tap case tap
case long case long
...@@ -151,6 +163,39 @@ extension UIView { ...@@ -151,6 +163,39 @@ extension UIView {
case rotation case rotation
case edgePan case edgePan
} }
enum gradientTion {
case leftToRight
case topToBottom
case topLeftToBottomRight
case topRightToBottomLeft
var startPoint: CGPoint {
switch self {
case .leftToRight:
return CGPoint(x: 0.0, y: 0.5)
case .topToBottom:
return CGPoint(x: 0.5, y: 0.0)
case .topLeftToBottomRight:
return CGPoint(x: 0.0, y: 0.0)
case .topRightToBottomLeft:
return CGPoint(x: 1.0, y: 0.0)
}
}
var endPoint: CGPoint {
switch self {
case .leftToRight:
return CGPoint(x: 1.0, y: 0.5)
case .topToBottom:
return CGPoint(x: 0.5, y: 1.0)
case .topLeftToBottomRight:
return CGPoint(x: 1.0, y: 1.0)
case .topRightToBottomLeft:
return CGPoint(x: 0.0, y: 1.0)
}
}
}
} }
/// frame /// frame
......
//
// UIWindow+Extension.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/10.
//
import UIKit
extension UIWindow {
private func setRootViewControllerWithTransition(_ viewController: UIViewController, transition: CATransition) {
self.layer.add(transition, forKey: kCATransition)
self.rootViewController = viewController
self.makeKeyAndVisible()
}
func switchToController(_ vc:UIViewController) {
let transition = CATransition()
transition.duration = 0.35
transition.type = .push
transition.subtype = .fromRight
transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
setRootViewControllerWithTransition(vc, transition: transition)
}
}
//
// SpeakEleGuideViewCtr.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/11.
//
import UIKit
class SpeakEleGuideViewCtr: SpeakEleBaseViewCtr ,UIScrollViewDelegate {
// MARK: - ib
@IBOutlet weak var SpeakScroll: UIScrollView!
private var selectIdx:Double = 0 {
didSet {
UIView.animate(withDuration: 0.35) {
self.SpeakScroll.contentOffset = CGPointMake(self.selectIdx * self.SpeakScroll.width, 0)
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
SpeakScroll.delegate = self
selectIdx = 0
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
}
@IBAction func SpeakNextTaps(_ sender: Any) {
if selectIdx >= 2 {
if let isThree = UserDefaults.standard.object(forKey: UnsafeRawUserDefaultsKey.UnsafeThreeDayGuide.rawValue) as? Bool {
let iap = SpeakEleIAPViewCtr()
iap.modalPresentationStyle = .overFullScreen
self.present(iap, animated: true)
iap.callback = { [weak self] in
let QAndA = SpeakEleQAViewCtr()
self?.navigationController?.pushViewController(QAndA, animated: true)
}
}else {
UserDefaults.standard.set(true, forKey: UnsafeRawUserDefaultsKey.UnsafeThreeDayGuide.rawValue)
let threeFree = SpeakEleThrDaysFreeViewCtr()
self.navigationController?.pushViewController(threeFree, animated: true)
}
}else{
selectIdx += 1
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
selectIdx = scrollView.contentOffset.x / scrollView.width
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SpeakEleGuideViewCtr" customModule="SpeakEasyLearnEnglish" customModuleProvider="target">
<connections>
<outlet property="SpeakScroll" destination="xKo-Ae-XDM" id="ssl-EM-oKX"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xKo-Ae-XDM">
<rect key="frame" x="0.0" y="138" width="393" height="474"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Vmb-QG-1Wg">
<rect key="frame" x="0.0" y="0.0" width="1179" height="474"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="d0L-QK-MCE">
<rect key="frame" x="0.0" y="0.0" width="1179" height="474"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Tbc-bq-3rD">
<rect key="frame" x="0.0" y="0.0" width="393" height="474"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="b14-Xp-dTD">
<rect key="frame" x="24" y="0.0" width="345" height="474"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="uTy-wS-Wcy">
<rect key="frame" x="0.0" y="0.0" width="345" height="380.33333333333331"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="More trust from users" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="DIR-LI-wiP">
<rect key="frame" x="0.0" y="396.33333333333337" width="345" height="21"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="21" id="FJT-t5-TpH"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cutomFont">
<integer key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="fontSize">
<real key="value" value="32"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Accumulatively helped 1000+ people improve their vocabulary" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="kb8-ZK-2qh">
<rect key="frame" x="0.0" y="433.33333333333337" width="345" height="40.666666666666686"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="36" id="U1P-nd-5Od"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.5446960034013606" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cutomFont">
<integer key="value" value="1"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="fontSize">
<real key="value" value="16"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="b14-Xp-dTD" secondAttribute="trailing" constant="24" id="MrJ-BY-FZk"/>
<constraint firstItem="b14-Xp-dTD" firstAttribute="top" secondItem="Tbc-bq-3rD" secondAttribute="top" id="OkX-BQ-n9G"/>
<constraint firstItem="b14-Xp-dTD" firstAttribute="leading" secondItem="Tbc-bq-3rD" secondAttribute="leading" constant="24" id="bK4-KR-HRA"/>
<constraint firstAttribute="bottom" secondItem="b14-Xp-dTD" secondAttribute="bottom" id="jjG-7d-VpE"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Rdh-di-qri">
<rect key="frame" x="393" y="0.0" width="393" height="474"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="lVK-So-1pG">
<rect key="frame" x="24" y="0.0" width="345" height="474"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vSM-Yn-NkU">
<rect key="frame" x="0.0" y="0.0" width="345" height="385"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="An APP for learning English" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ncj-Xn-x9Y">
<rect key="frame" x="0.0" y="401" width="345" height="21"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="21" id="UU1-ec-8DO"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cutomFont">
<integer key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="fontSize">
<real key="value" value="32"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Use the learning tools you need" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OqL-By-lhi">
<rect key="frame" x="0.0" y="438" width="345" height="36"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="36" id="CJg-8J-ZQ4"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.54469600340000002" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cutomFont">
<integer key="value" value="1"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="fontSize">
<real key="value" value="16"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="lVK-So-1pG" firstAttribute="leading" secondItem="Rdh-di-qri" secondAttribute="leading" constant="24" id="35v-tL-OSt"/>
<constraint firstAttribute="trailing" secondItem="lVK-So-1pG" secondAttribute="trailing" constant="24" id="SWu-9v-FT5"/>
<constraint firstItem="lVK-So-1pG" firstAttribute="top" secondItem="Rdh-di-qri" secondAttribute="top" id="dKz-C5-KH9"/>
<constraint firstAttribute="bottom" secondItem="lVK-So-1pG" secondAttribute="bottom" id="xo1-Sb-dy2"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="flT-gf-4KY">
<rect key="frame" x="786" y="0.0" width="393" height="474"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="4Mv-bg-BZ6">
<rect key="frame" x="24" y="0.0" width="345" height="474"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bH1-7V-NdX">
<rect key="frame" x="0.0" y="0.0" width="345" height="380.33333333333331"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Higher learning efficiency" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="I0J-HW-cdr">
<rect key="frame" x="0.0" y="396.33333333333337" width="345" height="21"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="21" id="0mU-Ak-mkv"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cutomFont">
<integer key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="fontSize">
<real key="value" value="32"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="nGG-WJ-GW4">
<rect key="frame" x="0.0" y="433.33333333333337" width="345" height="40.666666666666686"/>
<constraints>
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="36" id="1yO-Ve-n27"/>
</constraints>
<string key="text">1.77 times higher learning efficiency
than other apps</string>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.54469600340000002" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cutomFont">
<integer key="value" value="1"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="fontSize">
<real key="value" value="16"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="4Mv-bg-BZ6" secondAttribute="bottom" id="Xlq-Tv-Rkt"/>
<constraint firstItem="4Mv-bg-BZ6" firstAttribute="leading" secondItem="flT-gf-4KY" secondAttribute="leading" constant="24" id="XrQ-oe-N5i"/>
<constraint firstAttribute="trailing" secondItem="4Mv-bg-BZ6" secondAttribute="trailing" constant="24" id="sWc-0f-WrL"/>
<constraint firstItem="4Mv-bg-BZ6" firstAttribute="top" secondItem="flT-gf-4KY" secondAttribute="top" id="zpH-X8-flH"/>
</constraints>
</view>
</subviews>
</stackView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="d0L-QK-MCE" secondAttribute="bottom" id="F6g-UP-JHf"/>
<constraint firstAttribute="trailing" secondItem="d0L-QK-MCE" secondAttribute="trailing" id="Sr9-JT-bGz"/>
<constraint firstItem="d0L-QK-MCE" firstAttribute="leading" secondItem="Vmb-QG-1Wg" secondAttribute="leading" id="pQb-B1-GJL"/>
<constraint firstItem="d0L-QK-MCE" firstAttribute="top" secondItem="Vmb-QG-1Wg" secondAttribute="top" id="sL8-7H-4Zj"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="Vmb-QG-1Wg" firstAttribute="width" secondItem="xKo-Ae-XDM" secondAttribute="width" multiplier="3" id="0J6-mY-0bD"/>
<constraint firstAttribute="bottom" secondItem="Vmb-QG-1Wg" secondAttribute="bottom" id="5qf-0e-D5N"/>
<constraint firstItem="Vmb-QG-1Wg" firstAttribute="centerY" secondItem="xKo-Ae-XDM" secondAttribute="centerY" id="KnU-Mq-XQA"/>
<constraint firstItem="Vmb-QG-1Wg" firstAttribute="top" secondItem="xKo-Ae-XDM" secondAttribute="top" id="Tx7-WN-RDY"/>
<constraint firstAttribute="trailing" secondItem="Vmb-QG-1Wg" secondAttribute="trailing" id="WGv-k6-2vq"/>
<constraint firstItem="Vmb-QG-1Wg" firstAttribute="leading" secondItem="xKo-Ae-XDM" secondAttribute="leading" id="uCD-hn-r0W"/>
</constraints>
</scrollView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="asw-k4-NNo" customClass="SpeakEleButton" customModule="SpeakEasyLearnEnglish" customModuleProvider="target">
<rect key="frame" x="24" y="676" width="345" height="60"/>
<constraints>
<constraint firstAttribute="height" constant="60" id="hHE-fd-Hpb"/>
</constraints>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Next"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cutomFont">
<integer key="value" value="1"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="fontSize">
<real key="value" value="16"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="SpeakNextTaps:" destination="-1" eventType="touchUpInside" id="qq9-BJ-yXD"/>
</connections>
</button>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="asw-k4-NNo" firstAttribute="top" secondItem="xKo-Ae-XDM" secondAttribute="bottom" constant="64" id="6Yl-fX-Lye"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="asw-k4-NNo" secondAttribute="trailing" constant="24" id="BSe-1H-qff"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="xKo-Ae-XDM" secondAttribute="trailing" id="INw-mT-OjO"/>
<constraint firstItem="asw-k4-NNo" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="24" id="SrZ-DS-HaF"/>
<constraint firstItem="xKo-Ae-XDM" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="gZf-Gx-37g"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="asw-k4-NNo" secondAttribute="bottom" constant="48" id="s3n-1c-0yg"/>
<constraint firstItem="xKo-Ae-XDM" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="20" id="sql-Iq-k2y"/>
</constraints>
<point key="canvasLocation" x="98" y="-11"/>
</view>
</objects>
<resources>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
//
// SpeakEleQAViewCtr.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/11.
//
import UIKit
class SpeakEleQAViewCtr: SpeakEleBaseViewCtr {
override func viewDidLoad() {
super.viewDidLoad()
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SpeakEleQAViewCtr" customModule="SpeakEasyLearnEnglish" customModuleProvider="target">
<connections>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemYellowColor"/>
<point key="canvasLocation" x="131" y="-11"/>
</view>
</objects>
<resources>
<systemColor name="systemYellowColor">
<color red="1" green="0.80000000000000004" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
</resources>
</document>
//
// SpeakEleThrDaysFreeViewCtr.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/11.
//
import UIKit
class SpeakEleThrDaysFreeViewCtr: SpeakEleBaseViewCtr {
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.toIAP()
}
}
private func toIAP() -> Void {
let iap = SpeakEleIAPViewCtr()
iap.modalPresentationStyle = .overFullScreen
self.present(iap, animated: true)
iap.callback = { [weak self] in
let QAndA = SpeakEleQAViewCtr()
var array = self?.navigationController?.viewControllers
array?.removeLast()
array?.append(QAndA)
self?.navigationController?.viewControllers = array ?? [QAndA]
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SpeakEleThrDaysFreeViewCtr" customModule="SpeakEasyLearnEnglish" customModuleProvider="target">
<connections>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sp-bg" translatesAutoresizingMaskIntoConstraints="NO" id="jcB-qj-g6R">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
</imageView>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="jcB-qj-g6R" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="61k-g6-J8G"/>
<constraint firstAttribute="bottom" secondItem="jcB-qj-g6R" secondAttribute="bottom" id="E95-TJ-thC"/>
<constraint firstItem="jcB-qj-g6R" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="aOm-ot-wJc"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="jcB-qj-g6R" secondAttribute="trailing" id="qA1-03-HaG"/>
</constraints>
<point key="canvasLocation" x="130.53435114503816" y="-11.267605633802818"/>
</view>
</objects>
<resources>
<image name="sp-bg" width="402" height="874"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
//
// SpeakEleIAPViewCtr.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/11.
//
import UIKit
class SpeakEleIAPViewCtr: UIViewController {
var callback:(()->Void)?
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func SpeakCloseTaps(_ sender: Any) {
self.dismiss(animated: true) {
guard let call = self.callback else { return }
call()
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SpeakEleIAPViewCtr" customModule="SpeakEasyLearnEnglish" customModuleProvider="target">
<connections>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sp-bg" translatesAutoresizingMaskIntoConstraints="NO" id="5SM-Lp-0MM">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
</imageView>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="aYT-y7-hf8">
<rect key="frame" x="0.0" y="172" width="393" height="680"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="8r0-nd-l8p">
<rect key="frame" x="0.0" y="0.0" width="393" height="500"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Get Unlimited Access" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="GRD-E5-C2J">
<rect key="frame" x="24" y="0.0" width="345" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cutomFont">
<integer key="value" value="1"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="fontSize">
<real key="value" value="32"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Learning, progress, improvement" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ynQ-dm-w6L">
<rect key="frame" x="24" y="29" width="345" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.54490858843537415" colorSpace="custom" customColorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cutomFont">
<integer key="value" value="0"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="fontSize">
<real key="value" value="16"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
</subviews>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="GRD-E5-C2J" secondAttribute="trailing" constant="24" id="0vo-MP-eBw"/>
<constraint firstItem="GRD-E5-C2J" firstAttribute="top" secondItem="8r0-nd-l8p" secondAttribute="top" id="2VJ-32-x63"/>
<constraint firstItem="ynQ-dm-w6L" firstAttribute="trailing" secondItem="GRD-E5-C2J" secondAttribute="trailing" id="68D-Of-BIX"/>
<constraint firstItem="ynQ-dm-w6L" firstAttribute="top" secondItem="GRD-E5-C2J" secondAttribute="bottom" constant="8" id="V6V-5R-QUq"/>
<constraint firstAttribute="height" constant="500" id="e3h-5s-LJ6"/>
<constraint firstItem="GRD-E5-C2J" firstAttribute="leading" secondItem="8r0-nd-l8p" secondAttribute="leading" constant="24" id="rse-Mz-7Hy"/>
<constraint firstItem="ynQ-dm-w6L" firstAttribute="leading" secondItem="GRD-E5-C2J" secondAttribute="leading" id="zoX-2m-2s1"/>
</constraints>
</view>
</subviews>
<constraints>
<constraint firstItem="8r0-nd-l8p" firstAttribute="centerX" secondItem="aYT-y7-hf8" secondAttribute="centerX" id="5ZZ-mf-Xwc"/>
<constraint firstAttribute="bottom" secondItem="8r0-nd-l8p" secondAttribute="bottom" id="CAb-1g-bE5"/>
<constraint firstItem="8r0-nd-l8p" firstAttribute="top" secondItem="aYT-y7-hf8" secondAttribute="top" id="Ghg-am-K9w"/>
<constraint firstAttribute="trailing" secondItem="8r0-nd-l8p" secondAttribute="trailing" id="Ksc-8n-Ukp"/>
<constraint firstItem="8r0-nd-l8p" firstAttribute="leading" secondItem="aYT-y7-hf8" secondAttribute="leading" id="jfp-Mc-j5g"/>
</constraints>
</scrollView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Khu-4S-MSZ">
<rect key="frame" x="24" y="122" width="40" height="40"/>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" image="sp-Close"/>
<connections>
<action selector="SpeakCloseTaps:" destination="-1" eventType="touchUpInside" id="Ehx-8a-Yrb"/>
</connections>
</button>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="aYT-y7-hf8" secondAttribute="trailing" id="1vp-dD-GTQ"/>
<constraint firstItem="5SM-Lp-0MM" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="5Fy-iV-kqk"/>
<constraint firstItem="5SM-Lp-0MM" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="AjH-kD-Mkl"/>
<constraint firstItem="5SM-Lp-0MM" firstAttribute="trailing" secondItem="fnl-2z-Ty3" secondAttribute="trailing" id="OXa-HW-56J"/>
<constraint firstItem="aYT-y7-hf8" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="P4U-QH-Kwb"/>
<constraint firstAttribute="bottom" secondItem="5SM-Lp-0MM" secondAttribute="bottom" id="jDz-gg-Zym"/>
<constraint firstItem="Khu-4S-MSZ" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="4" id="pkS-QV-Hi6"/>
<constraint firstAttribute="bottom" secondItem="aYT-y7-hf8" secondAttribute="bottom" id="pp9-E9-aLs"/>
<constraint firstItem="Khu-4S-MSZ" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="24" id="vI0-jI-GOv"/>
<constraint firstItem="aYT-y7-hf8" firstAttribute="top" secondItem="Khu-4S-MSZ" secondAttribute="bottom" constant="10" id="xKg-ic-aWl"/>
</constraints>
<point key="canvasLocation" x="11.450381679389313" y="-11.267605633802818"/>
</view>
</objects>
<resources>
<image name="sp-Close" width="40" height="40"/>
<image name="sp-bg" width="402" height="874"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
//
// SpeakEleLaunchViewCtr.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/10.
//
import UIKit
class SpeakEleLaunchViewCtr: SpeakEleBaseViewCtr {
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.toLogin()
}
}
private func toLogin() -> Void {
let nav = SpeakEleBaseNavigationCtr(rootViewController: SpeakEleLoginGuideCtr())
window.switchToController(nav)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SpeakEleLaunchViewCtr" customModule="SpeakEasyLearnEnglish" customModuleProvider="target">
<connections>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sp-bg" translatesAutoresizingMaskIntoConstraints="NO" id="54Z-sK-TQW">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RFi-CT-Wya">
<rect key="frame" x="120" y="289" width="0.0" height="0.0"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="54Z-sK-TQW" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="REW-HW-rid"/>
<constraint firstAttribute="bottom" secondItem="54Z-sK-TQW" secondAttribute="bottom" id="TeG-QM-KHl"/>
<constraint firstItem="54Z-sK-TQW" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="YhQ-ck-r5O"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="54Z-sK-TQW" secondAttribute="trailing" id="lOd-cz-dJp"/>
</constraints>
<point key="canvasLocation" x="130.53435114503816" y="-11.267605633802818"/>
</view>
</objects>
<resources>
<image name="sp-bg" width="402" height="874"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
//
// SpeakEleCreatAViewCtr.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/11.
//
import UIKit
class SpeakEleCreatAViewCtr: SpeakEleBaseViewCtr {
override func viewDidLoad() {
super.viewDidLoad()
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="13142" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12042"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SpeakEleCreatAViewCtr" customModuleProvider="target">
<connections>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
</view>
</objects>
</document>
//
// SpeakEleLoginGuideCtr.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/10.
//
import UIKit
import YYText
class SpeakEleLoginGuideCtr: SpeakEleBaseViewCtr {
@IBOutlet weak var SpeakDescLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setDescription()
}
@IBAction func SpeakLogin(_ sender: Any) {
let login = SpeakEleCreatAViewCtr()
self.navigationController?.pushViewController(login, animated: true)
}
@IBAction func SpeakSkip(_ sender: Any) {
let guide = SpeakEleGuideViewCtr()
self.navigationController?.pushViewController(guide, animated: true)
}
private func TermsOfService() -> Void {
}
private func PrivacyPolicy() -> Void {
}
private func setDescription() -> Void {
SpeakDescLabel.AddTextTap(["Privacy Policy","Terms of Service."])
let privacy = "Privacy Policy".attributed().font(UIFont.montserrat(.medium,size: 10)).underline(.single).build()
let terms = "Terms of Service.".attributed().font(UIFont.montserrat(.medium,size: 10)).underline(.single).build()
let att = "Proceeding further indicates your agreement to our ".combined(with: [privacy," and ", terms])
SpeakDescLabel.attributedText = att
// let range1 = (att.string as NSString).range(of: "Privacy Policy")
// let highlight1 = YYTextHighlight()
//
// highlight1.tapAction = { containerView, text, range, rect in
// print("用户点击了'点击这里'")
// // 处理点击事件
// }
//
// // 应用高亮到文本
// SpeakDescLabel.yy_setTextHighlight(highlight1, range: range1)
//
// // 同样设置"官网"为可点击文本
// let range2 = (text as NSString).range(of: "官网")
// let highlight2 = YYTextHighlight()
// highlight2.setColor(UIColor.blue)
// highlight2.setBackgroundColor(UIColor.lightGray.withAlphaComponent(0.3))
//
// highlight2.tapAction = { containerView, text, range, rect in
// print("用户点击了'官网'")
// // 处理点击事件
// }
// attributedText.yy_setTextHighlight(highlight2, range: range2)
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SpeakEleLoginGuideCtr" customModule="SpeakEasyLearnEnglish" customModuleProvider="target">
<connections>
<outlet property="SpeakDescLabel" destination="jGO-Du-a3k" id="mxV-nA-Nwk"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="16" translatesAutoresizingMaskIntoConstraints="NO" id="veF-PY-V1F">
<rect key="frame" x="24" y="589.66666666666663" width="345" height="170.33333333333337"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="equalSpacing" spacing="8" translatesAutoresizingMaskIntoConstraints="NO" id="pwZ-Zv-JRo">
<rect key="frame" x="0.0" y="0.0" width="345" height="128"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="GOS-gl-Ilh">
<rect key="frame" x="0.0" y="0.0" width="345" height="60"/>
<constraints>
<constraint firstAttribute="height" constant="60" id="Ccj-Nr-OXL"/>
</constraints>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Log in">
<color key="titleColor" red="0.41960784309999999" green="0.4431372549" blue="0.89019607840000003" alpha="1" colorSpace="calibratedRGB"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="fontSize">
<real key="value" value="16"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="cutomFont">
<integer key="value" value="1"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="SpeakLogin:" destination="-1" eventType="touchUpInside" id="TmI-IN-b3c"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Zwf-M5-Hrt" customClass="SpeakEleButton" customModule="SpeakEasyLearnEnglish" customModuleProvider="target">
<rect key="frame" x="0.0" y="68" width="345" height="60"/>
<constraints>
<constraint firstAttribute="height" constant="60" id="QTC-Yr-pWU"/>
</constraints>
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
<state key="normal" title="Let’s go">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="fontSize">
<real key="value" value="16"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="cutomFont">
<integer key="value" value="1"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
<connections>
<action selector="SpeakSkip:" destination="-1" eventType="touchUpInside" id="ieP-HU-a56"/>
</connections>
</button>
</subviews>
</stackView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Proceeding further indicates your agreement to our Privacy Policy and Terms of Service." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jGO-Du-a3k">
<rect key="frame" x="0.0" y="144" width="345" height="26.333333333333343"/>
<fontDescription key="fontDescription" type="system" pointSize="11"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="0.53736181972789121" colorSpace="custom" customColorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="cutomFont">
<integer key="value" value="0"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="fontSize">
<real key="value" value="10"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
</subviews>
</stackView>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="veF-PY-V1F" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" constant="24" id="0oh-4u-Nzo"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="veF-PY-V1F" secondAttribute="trailing" constant="24" id="9ao-KJ-und"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="bottom" secondItem="veF-PY-V1F" secondAttribute="bottom" constant="24" id="NIU-Ch-1i2"/>
</constraints>
<point key="canvasLocation" x="131" y="-12"/>
</view>
</objects>
<resources>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
//
// SpeakEleButton.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/10.
//
import UIKit
class SpeakEleButton: UIButton {
override func awakeFromNib() {
super.awakeFromNib()
}
override func layoutSubviews() {
super.layoutSubviews()
self.layoutIfNeeded()
self.corners = 20
self.gradient(colors: [.init(hex: 0x6B71E3) ,.init(hex: 0x8D6AD3)])
}
}
//
// SpeakEleExt.swift
// SpeakEasyLearnEnglish
//
// Created by edy on 2025/7/10.
//
import UIKit
extension UIFont {
enum MontsStyle:String {
case regular = "-Regular"
case medium = "-Medium"
case semiBold = "-SemiBold"
case bold = "-Bold"
}
class func montserrat(_ type:MontsStyle = .regular ,size:CGFloat = 12) -> UIFont {
let fontName = "Montserrat" + type.rawValue
return UIFont(name: fontName, size: size) ?? UIFont.systemFont(ofSize: size)
}
}
...@@ -2,6 +2,13 @@ ...@@ -2,6 +2,13 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>UIAppFonts</key>
<array>
<string>Montserrat-Bold.otf</string>
<string>Montserrat-Medium.otf</string>
<string>Montserrat-Regular.otf</string>
<string>Montserrat-SemiBold.otf</string>
</array>
<key>UIApplicationSceneManifest</key> <key>UIApplicationSceneManifest</key>
<dict> <dict>
<key>UIApplicationSupportsMultipleScenes</key> <key>UIApplicationSupportsMultipleScenes</key>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment