├── demo ├── .DS_Store ├── gif │ ├── landscape.gif │ └── portrait.gif ├── Assets.xcassets │ ├── .DS_Store │ └── AppIcon.appiconset │ │ └── Contents.json ├── ViewController.h ├── AppDelegate.h ├── EnglishKeyboardView.h ├── main.m ├── EnglishKeyboardView.m ├── Info.plist ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── AppDelegate.m └── ViewController.m ├── WJLicensePlateKeyBoard ├── WJLicensePlateKeyboard.bundle │ ├── icon_delete@2x.png │ ├── icon_delete@3x.png │ ├── icon_delete_highlight@2x.png │ ├── icon_delete_highlight@3x.png │ └── UIDeviceModel.plist ├── WJLicensePlateEnglishView.h ├── WJLicensePlateProvinceView.h ├── WJKeyBoardHeader.h ├── WJConst.m ├── WJLicensePlateKeyView.h ├── UIDevice+Extension.h ├── WJConst.h ├── WJLicensePlateKeyboard.h ├── WJLicensePlateProvinceView.m ├── WJLicensePlateEnglishView.m ├── WJLicensePlateKBBaseView.h ├── UIDevice+Extension.m ├── WJLicensePlateKeyView.m ├── WJLicensePlateKBBaseView.m └── WJLicensePlateKeyboard.m ├── WJLicensePlateKeyboard.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── project.pbxproj ├── LICENSE ├── .gitignore ├── WJLicensePlateKeyboard.podspec └── README.md /demo/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loyalwind/WJLicensePlateKeyboard/HEAD/demo/.DS_Store -------------------------------------------------------------------------------- /demo/gif/landscape.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loyalwind/WJLicensePlateKeyboard/HEAD/demo/gif/landscape.gif -------------------------------------------------------------------------------- /demo/gif/portrait.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loyalwind/WJLicensePlateKeyboard/HEAD/demo/gif/portrait.gif -------------------------------------------------------------------------------- /demo/Assets.xcassets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loyalwind/WJLicensePlateKeyboard/HEAD/demo/Assets.xcassets/.DS_Store -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJLicensePlateKeyboard.bundle/icon_delete@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loyalwind/WJLicensePlateKeyboard/HEAD/WJLicensePlateKeyBoard/WJLicensePlateKeyboard.bundle/icon_delete@2x.png -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJLicensePlateKeyboard.bundle/icon_delete@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loyalwind/WJLicensePlateKeyboard/HEAD/WJLicensePlateKeyBoard/WJLicensePlateKeyboard.bundle/icon_delete@3x.png -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJLicensePlateKeyboard.bundle/icon_delete_highlight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loyalwind/WJLicensePlateKeyboard/HEAD/WJLicensePlateKeyBoard/WJLicensePlateKeyboard.bundle/icon_delete_highlight@2x.png -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJLicensePlateKeyboard.bundle/icon_delete_highlight@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loyalwind/WJLicensePlateKeyboard/HEAD/WJLicensePlateKeyBoard/WJLicensePlateKeyboard.bundle/icon_delete_highlight@3x.png -------------------------------------------------------------------------------- /demo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // WJLicensePlateKeyBoard 4 | // 5 | // Created by 彭维剑 on 2017/1/20. 6 | // Copyright © 2017年 pengweijian. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /WJLicensePlateKeyboard.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WJLicensePlateKeyboard.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJLicensePlateEnglishView.h: -------------------------------------------------------------------------------- 1 | // 2 | // WJLicensePlateEnglishView.h 3 | // WJLicensePlateKeyboard 4 | // 5 | // Created by 彭维剑 on 2017/1/16. 6 | // Copyright © 2017年 pengweijian. All rights reserved. 7 | // 8 | 9 | #import "WJLicensePlateKBBaseView.h" 10 | 11 | @interface WJLicensePlateEnglishView : WJLicensePlateKBBaseView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJLicensePlateProvinceView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LicensePlateProvinceView.h 3 | // LicensePlateKeyboard 4 | // 5 | // Created by 彭维剑 on 2017/1/16. 6 | // Copyright © 2017年 pengweijian. All rights reserved. 7 | // 8 | 9 | #import "WJLicensePlateKBBaseView.h" 10 | 11 | @interface WJLicensePlateProvinceView : WJLicensePlateKBBaseView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /demo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // WJLicensePlateKeyBoard 4 | // 5 | // Created by 彭维剑 on 2017/1/20. 6 | // Copyright © 2017年 pengweijian. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /demo/EnglishKeyboardView.h: -------------------------------------------------------------------------------- 1 | // 2 | // EnglishKeyboardView.h 3 | // WJLicensePlateKeyBoard 4 | // 5 | // Created by Loyalwind on 2021/7/29. 6 | // Copyright © 2021 pengweijian. All rights reserved. 7 | // 8 | 9 | #import "WJLicensePlateEnglishView.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface EnglishKeyboardView : WJLicensePlateEnglishView 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /demo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // WJLicensePlateKeyBoard 4 | // 5 | // Created by 彭维剑 on 2017/1/20. 6 | // Copyright © 2017年 pengweijian. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJKeyBoardHeader.h: -------------------------------------------------------------------------------- 1 | // 2 | // WJKeyBoardHeader.h 3 | // WJLicensePlateKeyBoard 4 | // 5 | // Created by  彭维剑 on 2021/7/29. 6 | // Copyright © 2021 pengweijian. All rights reserved. 7 | // 8 | 9 | #ifndef WJKeyBoardHeader_h 10 | #define WJKeyBoardHeader_h 11 | 12 | #import "WJLicensePlateKeyboard.h" 13 | #import "WJLicensePlateKBBaseView.h" 14 | #import "WJLicensePlateEnglishView.h" 15 | #import "WJLicensePlateProvinceView.h" 16 | #import "WJLicensePlateKeyView.h" 17 | #import "WJConst.h" 18 | 19 | #endif /* WJKeyBoardHeader_h */ 20 | -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJConst.m: -------------------------------------------------------------------------------- 1 | // 2 | // WJConst.m 3 | // LicensePlateKeyboard 4 | // 5 | // Created by 彭维剑 on 2017/1/17. 6 | // Copyright © 2017年 pengweijian. All rights reserved. 7 | // 8 | 9 | #import "WJConst.h" 10 | 11 | CGFloat const kPaopaoAndKeyViewCornerRedius = 4.0; 12 | CGFloat const kKeyViewMarginH = 3.0; 13 | CGFloat const kKeyViewMarginV = 5.0; 14 | NSInteger const kEnglishColumn = 10; 15 | NSInteger const kProvinceColumn = 9; 16 | NSInteger const kKBRow = 4; 17 | CGFloat const kKBHeight = 216.0; 18 | CGFloat const kFringeBottomPadding = 20.0; 19 | CGFloat const kFringeTopPadding = 30.0; 20 | CGFloat const kFineTuningSafePadding = 8.0; 21 | -------------------------------------------------------------------------------- /demo/EnglishKeyboardView.m: -------------------------------------------------------------------------------- 1 | // 2 | // EnglishKeyboardView.m 3 | // WJLicensePlateKeyBoard 4 | // 5 | // Created by Loyalwind on 2021/7/29. 6 | // Copyright © 2021 pengweijian. All rights reserved. 7 | // 8 | 9 | #import "EnglishKeyboardView.h" 10 | 11 | @implementation EnglishKeyboardView 12 | 13 | - (NSArray *)characters { 14 | if (!_characters) { 15 | _characters = @[@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"0",@"Q",@"W",@"E",@"R",@"T",@"Y",@"U",@"P", 16 | @"A",@"S",@"D",@"F",@"G",@"H",@"J",@"K",@"L",]; 17 | } 18 | return _characters; 19 | } 20 | 21 | - (NSInteger)rows { 22 | return 3; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJLicensePlateKeyView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LicensePlateKeyView.h 3 | // LicensePlateKeyboard 4 | // 5 | // Created by 彭维剑 on 2017/1/16. 6 | // Copyright © 2017年 pengweijian. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface WJLicensePlateKeyView : UIView 12 | /** 标题 label */ 13 | @property (nonatomic, weak, readonly) UILabel *titleLabel; 14 | /** 设置泡泡显示和隐藏 (默认 YES)*/ 15 | @property (nonatomic, assign, getter=isPaopaoHidden) BOOL paopaoHidden; 16 | /** 文字 */ 17 | @property (nonatomic, copy)IBInspectable NSString *text; 18 | /** 文字大小 (19)*/ 19 | @property (nonatomic, strong) UIFont *titleFont; 20 | /** 泡泡文字大小(40) */ 21 | @property (nonatomic, strong) UIFont *paopaoFont; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/UIDevice+Extension.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIDevice+Extension.h 3 | // 4 | // 5 | // Created by 彭维剑 on 2018/5/8. 6 | // 7 | 8 | #import 9 | 10 | /// NOTE: 以后苹果发布了新机型,需要在 UIDeviceModel.plist 添加进去 11 | 12 | @interface UIDevice (WJExtension) 13 | /** 设置自定义设备模型plist文件 14 | * 内容格式参考 WJLicensePlateKeyboard.bundle/UIDeviceModel.plist 里面的 15 | * 16 | * - Parameter path: plist文件路径 17 | */ 18 | + (void)setupDeviceModelFile:(NSString *)path; 19 | /** 设置自定义设备模型字典 20 | * 内容格式参考 WJLicensePlateKeyboard.bundle/UIDeviceModel.plist 里面的 21 | * 22 | * - Parameter dict: 设备模型字典 23 | */ 24 | + (void)setupDeviceModelDict:(NSDictionary *)dict; 25 | /** 设备的硬件字符串 26 | 27 | * 例如:"iPod3,1"、 @"iPad8,8"、 @"iPhone13,1" 等等 28 | */ 29 | + (NSString *)platformName; 30 | 31 | /** 是否为刘海屏 */ 32 | + (BOOL)isFringeScreen; 33 | 34 | /** 设备名 35 | 36 | * 例如:iPhone 6, iPad Pro, iPad Mini, iPod touch 37 | */ 38 | + (NSString *)deviceModel; 39 | @end 40 | -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJConst.h: -------------------------------------------------------------------------------- 1 | // 2 | // WJConst.h 3 | // LicensePlateKeyboard 4 | // 5 | // Created by 彭维剑 on 2017/1/17. 6 | // Copyright © 2017年 pengweijian. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** paopao 和 keyView 的圆角 (4) */ 12 | UIKIT_EXTERN CGFloat const kPaopaoAndKeyViewCornerRedius; 13 | /** 键盘每个按键水平方向间距 (3)*/ 14 | UIKIT_EXTERN CGFloat const kKeyViewMarginH; 15 | /** 键盘每个按键垂直方向间距 (5) */ 16 | UIKIT_EXTERN CGFloat const kKeyViewMarginV; 17 | /** 英文键盘的列数 (10) */ 18 | UIKIT_EXTERN NSInteger const kEnglishColumn; 19 | /** 汉字键盘的列数 (9) */ 20 | UIKIT_EXTERN NSInteger const kProvinceColumn; 21 | /** 键盘的行数 (4)*/ 22 | UIKIT_EXTERN NSInteger const kKBRow; 23 | /** 键盘的高度 (216)*/ 24 | UIKIT_EXTERN CGFloat const kKBHeight; 25 | /** 刘海屏键盘的底部padding (20)*/ 26 | UIKIT_EXTERN CGFloat const kFringeBottomPadding; 27 | /** 刘海屏键盘的顶部padding(30)*/ 28 | UIKIT_EXTERN CGFloat const kFringeTopPadding; 29 | /** 刘海屏 横屏时键盘的水平微调整padding (8)*/ 30 | UIKIT_EXTERN CGFloat const kFineTuningSafePadding; 31 | -------------------------------------------------------------------------------- /demo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ios-marketing", 45 | "scale" : "1x", 46 | "size" : "1024x1024" 47 | } 48 | ], 49 | "info" : { 50 | "author" : "xcode", 51 | "version" : 1 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 loyalwind 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | #mac 31 | *.DS_Store 32 | .DS_Store 33 | 34 | # CocoaPods 35 | # 36 | # We recommend against adding the Pods directory to your .gitignore. However 37 | # you should judge for yourself, the pros and cons are mentioned at: 38 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 39 | # 40 | # Pods/ 41 | 42 | # Carthage 43 | # 44 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 45 | # Carthage/Checkouts 46 | 47 | Carthage/Build 48 | 49 | # fastlane 50 | # 51 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 52 | # screenshots whenever they are needed. 53 | # For more information about the recommended setup visit: 54 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 55 | 56 | fastlane/report.xml 57 | fastlane/screenshots 58 | 59 | #Code Injection 60 | # 61 | # After new code Injection tools there's a generated folder /iOSInjectionProject 62 | # https://github.com/johnno1962/injectionforxcode 63 | 64 | iOSInjectionProject/ 65 | -------------------------------------------------------------------------------- /WJLicensePlateKeyboard.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint WJLicensePlateKeyboard.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see https://guides.cocoapods.org/syntax/podspec.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |spec| 10 | 11 | spec.name = "WJLicensePlateKeyboard" 12 | spec.version = "1.5.0" 13 | spec.summary = "自定义的车牌号码输入键盘,支持横竖屏模式,支持省份简称汉字,英文字母,数字的输入,输入时可以播放音效" 14 | spec.homepage = "https://github.com/loyalwind/WJLicensePlateKeyboard" 15 | # spec.screenshots = "https://github.com/loyalwind/WJLicensePlateKeyboard/tree/master/demo/gif/landscape.gif", "https://github.com/loyalwind/WJLicensePlateKeyboard/tree/master/demo/gif/portrait.gif" 16 | spec.license = "MIT" 17 | spec.author = { "PengWeiJian" => "loyalwind@163.com" } 18 | spec.platform = :ios, "12.0" 19 | spec.source = { :git => "https://github.com/loyalwind/WJLicensePlateKeyboard.git", :tag => "#{spec.version}" } 20 | spec.source_files = "WJLicensePlateKeyBoard/**/*.{h,m}" 21 | spec.resource = 'WJLicensePlateKeyBoard/WJLicensePlateKeyBoard.bundle' 22 | # spec.resources = "WJLicensePlateKeyBoard/WJLicensePlateKeyBoard.bundle" 23 | spec.requires_arc = true 24 | # spec.framework = "UIKit" 25 | # spec.frameworks = "SomeFramework", "AnotherFramework" 26 | 27 | # spec.library = "iconv" 28 | # spec.libraries = "iconv", "xml2" 29 | # spec.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" } 30 | # spec.dependency "JSONKit", "~> 1.4" 31 | 32 | end 33 | -------------------------------------------------------------------------------- /demo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJLicensePlateKeyboard.h: -------------------------------------------------------------------------------- 1 | // 2 | // WJLicensePlateKeyboard.h 3 | // WJLicensePlateKeyboard 4 | // 5 | // Created by 彭维剑 on 2017/1/16. 6 | // Copyright © 2017年 pengweijian. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "WJLicensePlateProvinceView.h" 11 | #import "WJLicensePlateEnglishView.h" 12 | 13 | typedef NS_ENUM(NSInteger,KeyboardSubKBFrameType) { 14 | KeyboardSubKBFrameTypeFill = 0,/**< 填充型 ,横屏时键盘与刘海的padding = 键盘与home键的padding */ 15 | KeyboardSubKBFrameTypeSymmetric /**< 对称型 ,横屏时键盘与屏幕的左边padding = 键盘与屏幕的右边padding, 且刚好等于 kFringeTopPadding */ 16 | }; 17 | 18 | @interface WJLicensePlateKeyboard : UIView 19 | 20 | /// 根据中文、英文字符集进行初始化构造,便于自定义调整字符集 和 顺序 21 | /// @param zhCharacters 中文字符集 22 | /// @param enCharacters 英文字符集 23 | - (instancetype)initWithZhCharacters:(NSArray *)zhCharacters 24 | enCharacters:(NSArray *)enCharacters; 25 | /// 便于一些自定义中文字符集和调整顺序 26 | /// @param chineseCharacters 中文字符 27 | - (void)setChineseCharacters:(NSArray *)chineseCharacters; 28 | 29 | /// 便于一些自定义英文字符集和调整顺序 30 | /// @param englishCharacters 英文字符 31 | - (void)setEnglishCharacters:(NSArray *)englishCharacters; 32 | 33 | /// 根据中文键盘,英文键盘初始化总键盘 34 | /// @param chineseView 中文键盘 多态类型 (WJLicensePlateProvinceView子类来自定义) 35 | /// @param englishView 英文键盘 多态类型(WJLicensePlateEnglishView子类来自定义) 36 | - (instancetype)initWithChineseView:(WJLicensePlateKBBaseView *)chineseView 37 | englishView:(WJLicensePlateKBBaseView *)englishView; 38 | 39 | /** 输入的 View */ 40 | @property (nonatomic, weak) UIView * inputTextView; 41 | /** 文字大小 (19)*/ 42 | @property (nonatomic, strong) UIFont *titleFont; 43 | /** 泡泡文字大小(40) */ 44 | @property (nonatomic, strong) UIFont *paopaoFont; 45 | /** 子键盘布局类型(默认 KeyboardSubKBFrameTypeFill)为了适配刘海屏 */ 46 | @property (nonatomic, assign) KeyboardSubKBFrameType subKBFrameType; 47 | 48 | @end 49 | 50 | -------------------------------------------------------------------------------- /demo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // WJLicensePlateKeyBoard 4 | // 5 | // Created by 彭维剑 on 2017/1/20. 6 | // Copyright © 2017年 pengweijian. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WJLicensePlateKeyboard 2 | 自定义的车牌号码输入键盘,支持横竖屏模式,支持省份简称汉字,英文字母,数字的输入,输入时可以播放音效。 3 | 4 | 5 | ### 如何使用 6 | 7 | ```objc 8 | #import "ViewController.h" 9 | #import "WJLicensePlateKeyboard.h" 10 | 11 | @interface ViewController () 12 | @property (weak, nonatomic) IBOutlet UITextField *inputField2; 13 | @property (strong, nonatomic) WJLicensePlateKeyboard *keyBaord; 14 | @end 15 | 16 | @implementation ViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | // 方式1 21 | WJLicensePlateKeyboard *keyBaord = [[WJLicensePlateKeyboard alloc] init]; 22 | 23 | // 方式2 自定义中英文字符集和顺序 24 | /* 25 | NSArray *chinese = @[@"警",@"宁",@"新",@"琼",@"皖",@"鄂",@"豫",@"陕",@"渝",@"粤",@"桂",@"吉",@"黑",@"鲁", 26 | @"苏",@"冀",@"晋",@"赣",@"沪",@"京",@"津",@"辽",@"浙",@"湘",@"川", 27 | @"云",@"贵",@"蒙",@"闽",@"甘",@"青",@"藏"]; 28 | NSArray *english = @[@"1",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"0",@"Q",@"W",@"E",@"R",@"T",@"Y",@"U",@"P", 29 | @"A",@"S",@"D",@"F",@"G",@"H",@"J",@"K",@"L",@"Z",@"X",@"C",@"V",@"X",@"B",@"N",@"M"]; 30 | WJLicensePlateKeyboard *keyBaord = [[WJLicensePlateKeyboard alloc] initWithZhCharacters:chinese enCharacters:english]; 31 | */ 32 | 33 | // 方式3 自定义键盘 34 | /* 35 | WJLicensePlateProvinceView *provinceView = [[WJLicensePlateProvinceView alloc] init]; 36 | // 继承关系:EnglishKeyboardView --> WJLicensePlateEnglishView --> WJLicensePlateKBBaseView 37 | EnglishKeyboardView *englishView = [[EnglishKeyboardView alloc] init]; 38 | WJLicensePlateKeyboard *keyBaord = [[WJLicensePlateKeyboard alloc] initWithChineseView:provinceView englishView:englishView]; 39 | */ 40 | 41 | keyBaord.inputTextView = _inputField2; 42 | _keyBaord = keyBaord; 43 | } 44 | @end 45 | ``` 46 | 47 | + 方式1.下载源码,把`WJLicensePlateKeyBoard`文件夹拖到项目中, 48 | + `Destination` 勾选 `Cope items if needed` 49 | + `Added folders` 选择 `Create groups` 50 | 51 | + 方式2. 通过 `Cocoapods` 安装 52 | 53 | ```ruby 54 | platform :ios, '8.0' 55 | target 'Your Target' do 56 | 57 | pod 'WJLicensePlateKeyboard' 58 | 59 | end 60 | ``` 61 | 62 | ### 效果图 63 | 64 | ![竖屏](https://github.com/loyalwind/WJLicensePlateKeyboard/blob/master/demo/gif/portrait.gif) 65 | 66 | ![横屏](https://github.com/loyalwind/WJLicensePlateKeyboard/blob/master/demo/gif/landscape.gif) 67 | 68 | -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJLicensePlateProvinceView.m: -------------------------------------------------------------------------------- 1 | // 2 | // WJLicensePlateProvinceView.m 3 | // WJLicensePlateKeyboard 4 | // 5 | // Created by 彭维剑 on 2017/1/16. 6 | // Copyright © 2017年 pengweijian. All rights reserved. 7 | // 8 | 9 | #import "WJLicensePlateProvinceView.h" 10 | #import "WJLicensePlateKeyView.h" 11 | #import "WJConst.h" 12 | 13 | @implementation WJLicensePlateProvinceView 14 | 15 | - (NSArray *)characters 16 | { 17 | if (!_characters) { 18 | _characters = @[@"琼",@"皖",@"鄂",@"豫",@"陕",@"渝",@"粤",@"桂",@"吉",@"黑",@"鲁", 19 | @"苏",@"冀",@"晋",@"赣",@"沪",@"京",@"津",@"辽",@"浙",@"湘",@"川", 20 | @"云",@"贵",@"蒙",@"闽",@"甘",@"青",@"宁",@"新",@"藏",@"警"]; 21 | } 22 | return _characters; 23 | } 24 | - (NSString *)switchText { 25 | return @"英文"; 26 | } 27 | - (NSInteger)rows 28 | { 29 | return kKBRow; 30 | } 31 | - (NSInteger)columns 32 | { 33 | return kProvinceColumn; 34 | } 35 | - (WJLicensePlateKeyboardType)switch2KeyBoardType 36 | { 37 | return WJLicensePlateKeyboardTypeEnglish; 38 | } 39 | - (BOOL)needSwitchKBAfterTouchEnd 40 | { 41 | return YES; 42 | } 43 | 44 | //- (void)layoutSubviews 45 | //{ 46 | // [super layoutSubviews]; 47 | // 48 | // CGFloat buttonW = (self.frame.size.width - (kProvinceColumn-1)*kKeyViewMarginH)/kProvinceColumn; 49 | // CGFloat buttonH = (self.frame.size.height - (kKBRow-1)*kKeyViewMarginV)/kKBRow; 50 | // CGFloat buttonX = 0; 51 | // CGFloat buttonY = 0; 52 | // 53 | // NSUInteger totalCount = self.keyViews.count; 54 | // for (NSUInteger index = 0;index *)characters 16 | { 17 | if (!_characters) { 18 | NSString *str = @"1234567890QWERTYUPASDFGHJKLZXCVBNM"; 19 | NSMutableArray *temArray = [NSMutableArray array]; 20 | for (int i=0; i *)touches withEvent:(UIEvent *)event { 70 | 71 | // Dispose of any resources that can be recreated. 72 | [self.view endEditing:YES]; 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJLicensePlateKBBaseView.h: -------------------------------------------------------------------------------- 1 | // 2 | // WJLicensePlateKBaseView.h 3 | // WJLicensePlateKeyboard 4 | // 5 | // Created by 彭维剑 on 2017/1/17. 6 | // Copyright © 2017年 pengweijian. All rights reserved. 7 | // 8 | 9 | #import 10 | @class WJLicensePlateKBBaseView,WJLicensePlateKeyView; 11 | 12 | /** 13 | 功能按钮类型 14 | - WJFunctionButtonTypeDelete: 回删按钮类型 15 | - WJFunctionButtonTypeSwitch: 切换键盘按钮类型 16 | - WJFunctionButtonTypeFinish: 完成按钮类型 17 | */ 18 | 19 | typedef NS_ENUM(NSInteger, WJFunctionButtonType) { 20 | WJFunctionButtonTypeDelete = 50, // 回删按钮 sss 21 | WJFunctionButtonTypeSwitch = 100, 22 | WJFunctionButtonTypeFinish = 150, 23 | }; 24 | 25 | /** 26 | 键盘类型 27 | - WJLicensePlateKeyboardTypeProvince: 汉字省份键盘 28 | - WJLicensePlateKeyboardTypeEnglish: 英文和数字键盘 29 | */ 30 | typedef NS_ENUM(NSInteger, WJLicensePlateKeyboardType) { 31 | WJLicensePlateKeyboardTypeProvince = 1, 32 | WJLicensePlateKeyboardTypeEnglish = 2 33 | }; 34 | 35 | /** 36 | 代理协议 37 | */ 38 | @protocol LicensePlateKBBaseViewDelegate 39 | @optional 40 | /** 41 | 通知代理切换键盘 42 | @param switch2KBType 切换到哪种键盘类型 43 | @param playInput 是否需要播放切换声音 44 | */ 45 | - (void)licensePlateKBBaseView:(WJLicensePlateKBBaseView *)kbBaseView 46 | didSwitch2KBType:(WJLicensePlateKeyboardType)switch2KBType 47 | playInput:(BOOL)playInput; 48 | /** 49 | 通知代理插入文字 50 | @param text 插入的文字 51 | */ 52 | - (void)licensePlateKBBaseView:(WJLicensePlateKBBaseView *)kbBaseView didInsertText:(NSString *)text; 53 | 54 | /** 55 | 通知代理开始回删文字 56 | */ 57 | - (void)licensePlateKBBaseViewStartDeleteBackward:(WJLicensePlateKBBaseView *)kbBaseView; 58 | 59 | /** 60 | 通知代理结束回删文字 61 | */ 62 | - (void)licensePlateKBBaseViewEndDeleteBackward:(WJLicensePlateKBBaseView *)kbBaseView; 63 | 64 | /** 65 | 通知代理点击完成 66 | */ 67 | - (void)licensePlateKBBaseViewDidFinish:(WJLicensePlateKBBaseView *)kbBaseView; 68 | 69 | @end 70 | 71 | @interface WJLicensePlateKBBaseView : UIView 72 | { 73 | @protected 74 | NSArray *_characters; 75 | } 76 | 77 | /// 根据给定字符集合初始化 78 | /// @param characters 给定字符集合 79 | - (instancetype)initWithCharacters:(NSArray *)characters; 80 | /** 字符集 */ 81 | @property (nonatomic, strong) NSArray *characters; 82 | /** 完成字符文字 (完成) */ 83 | @property (nonatomic, strong, readonly) NSString *doneText; 84 | /** 切换字符文字(中文, 英文) */ 85 | @property (nonatomic, strong, readonly) NSString *switchText; 86 | /** 按键集合 */ 87 | @property (nonatomic, strong, readonly) NSArray <__kindof UIView *> *keyViews; 88 | /** 行数 */ 89 | @property (nonatomic, assign, readonly) NSInteger rows; 90 | /** 列数 */ 91 | @property (nonatomic, assign, readonly) NSInteger columns; 92 | /** 切换键盘时,切换的键盘类型 */ 93 | @property (nonatomic, assign,readonly) WJLicensePlateKeyboardType switch2KeyBoardType; 94 | /** 在触摸结束后是否需要切换键盘 */ 95 | @property (nonatomic, assign,readonly) BOOL needSwitchKBAfterTouchEnd; 96 | /** 代理 */ 97 | @property (nonatomic, weak) id delegate; 98 | /** 当前的显示的按键 */ 99 | //@property (nonatomic, weak, readonly) LicensePlateKeyView *currentKeyView; 100 | /** 处理离开屏幕或者屏幕旋转 */ 101 | - (void)handleRotateScreenOrOn2OffScreen; 102 | 103 | - (UIImage *)imageFromColor:(UIColor *)color; 104 | 105 | - (UIButton *)createButtonWithTitle:(NSString *)title imageName:(NSString *)imageName; 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/UIDevice+Extension.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIDevice+PKExtension.m 3 | // 4 | // 5 | // Created by 彭维剑 on 2018/5/8. 6 | // 7 | 8 | #import "UIDevice+Extension.h" 9 | #import 10 | /** 11 | // iPhone X 12 | @"iPhone10,3", @"iPhone10,6", 13 | // iPhone XS MAX, iPhone XS, iPhone XR 14 | @"iPhone11,2", @"iPhone11,4", @"iPhone11,6", @"iPhone11,8", 15 | // iPhone 11, iPhone 11 Pro, iPhone 11 Pro Max 16 | @"iPhone12,1", @"iPhone12,3", @"iPhone12,5", 17 | // iPhone 12 MINI, iPhone 12, iPhone 12 Pro, iPhone 12 Pro Max 18 | @"iPhone13,1", @"iPhone13,2", @"iPhone13,3", @"iPhone13,4", 19 | */ 20 | static NSDictionary * __devicesMap = nil; 21 | 22 | #if TARGET_IPHONE_SIMULATOR 23 | static CGSize __fringeScreenSizes[] = { 24 | {375.f, 812.f},{812.f, 375.f},/// iPhone X, iPhone XS, iPhone 12 Mini, iPhone 14, iPhone 15 25 | {414.f, 896.f},{896.f, 414.f},/// iPhone XR,iPhone XS MAX,iPhone 11, iPhone 11 Pro Max 26 | {390.f, 844.f},{844.f, 390.f},/// iPhone 12,iPhone 12 Pro, iPhone 13, iPhone 13 Pro 27 | {428.f, 926.f},{926.f, 428.f},/// iPhone 12 Pro MAX, iPhone 13 Pro MAX, iPhone 14 Plus, iPhone 15 Plus 28 | {393.f, 852.f},{852.f, 393.f},/// iPhone 14 Pro, iPhone 15 Pro, iPhone 16 29 | {402.f, 874.f},{874.f, 401.f},/// iPhone 16 Pro, iPhone 16 Pro Max, 30 | {430.f, 932.f},{932.f, 430.f},/// iPhone 14 Pro Max, iPhone 15 Pro Max, iPhone 16 Plus 31 | }; 32 | #endif 33 | 34 | @implementation UIDevice (WJExtension) 35 | 36 | + (void)initialize 37 | { 38 | NSString *path = [[NSBundle mainBundle] pathForResource:@"WJLicensePlateKeyboard.bundle/UIDeviceModel" ofType:@"plist"]; 39 | __devicesMap = [NSDictionary dictionaryWithContentsOfFile:path]; 40 | } 41 | 42 | + (void)setupDeviceModelFile:(NSString *)path { 43 | BOOL isDir = NO; 44 | if (path.length && [NSFileManager.defaultManager fileExistsAtPath:path isDirectory:&isDir] && !isDir) { 45 | NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; 46 | if (dict) __devicesMap = dict; 47 | } 48 | } 49 | 50 | + (void)setupDeviceModelDict:(NSDictionary *)dict { 51 | if (dict) __devicesMap = dict; 52 | } 53 | 54 | + (NSString *)platformName 55 | { 56 | struct utsname systemInfo; 57 | uname(&systemInfo); 58 | return [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; 59 | } 60 | 61 | + (BOOL)isFringeScreen 62 | { 63 | static BOOL result = NO; 64 | static dispatch_once_t onceToken; 65 | dispatch_once(&onceToken, ^{ 66 | #if TARGET_IPHONE_SIMULATOR //模拟器 67 | CGSize size = [UIScreen mainScreen].bounds.size; 68 | int cout = sizeof(__fringeScreenSizes) / sizeof(__fringeScreenSizes[0]); 69 | for (int i=0; i *)touches withEvent:(UIEvent *)event 176 | { 177 | self.paopaoHidden = NO; 178 | [[UIDevice currentDevice] playInputClick]; 179 | [super touchesBegan:touches withEvent:event]; 180 | } 181 | 182 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 183 | { 184 | self.paopaoHidden = YES; 185 | [super touchesEnded:touches withEvent:event]; 186 | } 187 | 188 | - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { 189 | 190 | if (@available(iOS 12.0, *)) { 191 | [self setupColor]; 192 | } else { 193 | [super traitCollectionDidChange:previousTraitCollection]; 194 | } 195 | } 196 | 197 | @end 198 | -------------------------------------------------------------------------------- /demo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJLicensePlateKBBaseView.m: -------------------------------------------------------------------------------- 1 | // 2 | // WJLicensePlateKBaseView.m 3 | // WJLicensePlateKeyboard 4 | // 5 | // Created by 彭维剑 on 2017/1/17. 6 | // Copyright © 2017年 pengweijian. All rights reserved. 7 | // 8 | 9 | #import "WJLicensePlateKBBaseView.h" 10 | #import "WJLicensePlateKeyView.h" 11 | #import "WJConst.h" 12 | 13 | @interface WJLicensePlateKBBaseView () 14 | { 15 | /** 按钮集合 */ 16 | NSMutableArray <__kindof UIView *> *_keyViews; 17 | } 18 | /** 当前显示的按键 view */ 19 | @property (nonatomic, weak) WJLicensePlateKeyView *currentKeyView; 20 | @end 21 | 22 | @implementation WJLicensePlateKBBaseView 23 | - (instancetype)initWithCharacters:(NSArray *)characters { 24 | _characters = characters; 25 | if (self = [super init]) { 26 | } 27 | return self; 28 | } 29 | - (instancetype)initWithFrame:(CGRect)frame { 30 | if (self = [super initWithFrame:frame]) { 31 | [self setupKeyViews]; 32 | } 33 | return self; 34 | } 35 | 36 | - (void)setupKeyViews { 37 | NSUInteger totalCharacter = self.characters.count; 38 | NSInteger rows = self.rows; 39 | NSInteger colunms = self.columns; 40 | _keyViews = [NSMutableArray array]; 41 | NSString *bundle = [[NSBundle mainBundle] pathForResource:@"WJLicensePlateKeyboard.bundle" ofType:nil]; 42 | for (NSUInteger index = 0; index < totalCharacter; index++) { 43 | NSString *character = self.characters[index]; 44 | WJLicensePlateKeyView *keyView = [[WJLicensePlateKeyView alloc] init]; 45 | keyView.titleLabel.text = character; 46 | [self addSubview:keyView]; 47 | [_keyViews addObject:keyView]; 48 | 49 | if (index == colunms * (rows-1)-2) { // 删除按钮、切换输入按钮 50 | NSString *fileName = [NSString stringWithFormat:@"%@/icon_delete",bundle]; 51 | UIButton *delButton = [self createButtonWithTitle:nil imageName:fileName]; 52 | delButton.tag = WJFunctionButtonTypeDelete; 53 | [delButton addTarget:self action:@selector(functionButtonTouchUpInside:) forControlEvents:UIControlEventTouchUpInside]; 54 | [delButton addTarget:self action:@selector(functionButtonTouchDown:) forControlEvents:UIControlEventTouchDown]; 55 | 56 | [_keyViews addObject:delButton]; 57 | [self addSubview:delButton]; 58 | 59 | UIButton *switchButton = [self createButtonWithTitle:self.switchText imageName:nil]; 60 | [switchButton addTarget:self action:@selector(functionButtonTouchDown:) forControlEvents:UIControlEventTouchDown]; 61 | switchButton.tag = WJFunctionButtonTypeSwitch; 62 | [_keyViews addObject:switchButton]; 63 | [self addSubview:switchButton]; 64 | 65 | }else if (index == totalCharacter-1) { 66 | 67 | UIButton *doneButton = [self createButtonWithTitle:self.doneText imageName:nil]; 68 | [doneButton addTarget:self action:@selector(functionButtonTouchDown:) forControlEvents:UIControlEventTouchDown]; 69 | 70 | doneButton.tag = WJFunctionButtonTypeFinish; 71 | [_keyViews addObject:doneButton]; 72 | [self addSubview:doneButton]; 73 | } 74 | } 75 | } 76 | - (void)setCharacters:(NSArray *)characters { 77 | if ([self needResetCharacters:characters]) { 78 | _characters = characters; 79 | 80 | // 移除旧的的 81 | for (UIView *view in _keyViews) { 82 | [view removeFromSuperview]; 83 | } 84 | [_keyViews removeAllObjects]; 85 | 86 | // 重新创建新的 87 | [self setupKeyViews]; 88 | } 89 | } 90 | 91 | 92 | - (BOOL)needResetCharacters:(NSArray *)characters { 93 | NSInteger count1 = characters.count; 94 | NSInteger count2 = _characters.count; 95 | if (count1 == 0 || count2 == 0 || (count1 != count2)) { 96 | return YES; 97 | } 98 | 99 | BOOL needReset = NO; // 是否需要重置 100 | for (int i = 0; i < count1; i++) { 101 | if (characters[i] != _characters[i]) { // 内容相同 102 | needReset = YES; 103 | break; 104 | } 105 | } 106 | 107 | return needReset; 108 | } 109 | 110 | - (void)layoutSubviews 111 | { 112 | [super layoutSubviews]; 113 | NSInteger column = self.columns; 114 | NSInteger rows = self.rows; 115 | 116 | if (column<3 || rows <3)return; 117 | 118 | CGFloat viewW = (self.frame.size.width - (column-1)*kKeyViewMarginH)/column; 119 | CGFloat viewH = (self.frame.size.height - (rows-1)*kKeyViewMarginV)/rows; 120 | CGFloat viewX = 0; 121 | CGFloat viewY = 0; 122 | NSUInteger totalCount = self.keyViews.count; 123 | for (NSUInteger index = 0;index *)touches withEvent:(UIEvent *)event 174 | { 175 | self.userInteractionEnabled = NO; 176 | CGPoint location = [touches.anyObject locationInView:self]; 177 | 178 | for (UIView *view in self.keyViews) { 179 | // 不是这种按键类型,直接下一次循环 180 | if (![view isKindOfClass:WJLicensePlateKeyView.class]) continue; 181 | 182 | if(CGRectContainsPoint(view.frame, location)){ 183 | self.currentKeyView = (WJLicensePlateKeyView *)view; 184 | break; 185 | } 186 | } 187 | } 188 | 189 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 190 | { 191 | CGPoint location = [touches.anyObject locationInView:self]; 192 | for (UIView *view in self.keyViews) { 193 | // 不是这种按键类型,直接下一次循环 194 | if (![view isKindOfClass:WJLicensePlateKeyView.class]) continue; 195 | WJLicensePlateKeyView *keyView = (WJLicensePlateKeyView *)view; 196 | // 当前移动触摸点在按键上,就进行显示 paopao 197 | if(CGRectContainsPoint(keyView.frame, location)){ 198 | keyView.paopaoHidden = NO; 199 | self.currentKeyView = keyView; 200 | }else{ 201 | if (keyView.paopaoHidden == NO){ 202 | keyView.paopaoHidden = YES; 203 | } 204 | } 205 | } 206 | } 207 | 208 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 209 | { 210 | // 插入文字处理,方式1和方式2都可以,不过方式1更靠谱些, 211 | // 方式1 212 | for (UIView *view in self.keyViews) { 213 | // 不是这种按键类型,直接下一次循环 214 | if (![view isKindOfClass:WJLicensePlateKeyView.class])continue; 215 | WJLicensePlateKeyView *keyView = (WJLicensePlateKeyView *)view; 216 | // 当前按键的paopao 是没有隐藏,就进行隐藏 217 | if (keyView.paopaoHidden == NO){ 218 | keyView.paopaoHidden = YES; 219 | } 220 | if(self.currentKeyView.isPaopaoHidden == NO){ 221 | self.currentKeyView.paopaoHidden = YES; 222 | } 223 | // 当前结束触摸点在按键上,就进行插入文字处理 224 | CGPoint location = [touches.anyObject locationInView:self]; 225 | if (CGRectContainsPoint(keyView.frame, location)){ 226 | if([self.delegate respondsToSelector:@selector(licensePlateKBBaseView:didInsertText:)]){ 227 | [self.delegate licensePlateKBBaseView:self didInsertText:keyView.titleLabel.text]; 228 | } 229 | break; 230 | } 231 | } 232 | // 方式2 233 | // CGPoint location = [touches.anyObject locationInView:self.currentKeyView]; 234 | // if (CGRectContainsPoint(self.currentKeyView.bounds, location)){ 235 | // self.currentKeyView.paopaoHidden = YES; 236 | // if([self.delegate respondsToSelector:@selector(licensePlateKBBaseView:didInsertText:)]){ 237 | // [self.delegate licensePlateKBBaseView:self didInsertText:self.currentKeyView.titleLabel.text]; 238 | // } 239 | // } 240 | 241 | // 是否需要切换键盘 242 | if (self.needSwitchKBAfterTouchEnd) { 243 | if([self.delegate respondsToSelector:@selector(licensePlateKBBaseView:didSwitch2KBType:playInput:)]){ 244 | [self.delegate licensePlateKBBaseView:self didSwitch2KBType:WJLicensePlateKeyboardTypeEnglish playInput:NO]; 245 | } 246 | } 247 | self.userInteractionEnabled = YES; 248 | } 249 | - (void)touchesCancelled:(NSSet *)touches withEvent:(nullable UIEvent *)event; 250 | { 251 | CGPoint location = [touches.anyObject locationInView:self]; 252 | 253 | NSLog(@"%s",__func__); 254 | for (UIView *view in self.keyViews) { 255 | if ([view isKindOfClass:WJLicensePlateKeyView.class] && CGRectContainsPoint(view.frame, location)){ 256 | WJLicensePlateKeyView *keyView = (WJLicensePlateKeyView *)view; 257 | if (keyView.paopaoHidden == NO){ 258 | keyView.paopaoHidden = YES; 259 | break; 260 | } 261 | } 262 | } 263 | self.userInteractionEnabled = YES; 264 | } 265 | 266 | - (UIImage *)imageFromColor:(UIColor *)color { 267 | CGRect rect = CGRectMake(0, 0, 1, 1); 268 | UIGraphicsBeginImageContext(rect.size); 269 | CGContextRef context = UIGraphicsGetCurrentContext(); 270 | CGContextSetFillColorWithColor(context, [color CGColor]); 271 | CGContextFillRect(context, rect); 272 | UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); 273 | UIGraphicsEndImageContext(); 274 | return img; 275 | } 276 | - (UIButton *)createButtonWithTitle:(NSString *)title imageName:(NSString *)imageName 277 | { 278 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 279 | [button setTitle:title forState:UIControlStateNormal]; 280 | [button setTitleColor:UIColor.blackColor forState:UIControlStateNormal]; 281 | 282 | [button setImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal]; 283 | NSString *lightImgName = [imageName stringByAppendingString:@"_highlight"]; 284 | [button setImage:[UIImage imageNamed:lightImgName] forState:UIControlStateHighlighted]; 285 | 286 | [button setBackgroundImage:[self imageFromColor:UIColor.lightGrayColor] forState:UIControlStateNormal]; 287 | [button setBackgroundImage:[self imageFromColor:UIColor.whiteColor] forState:UIControlStateHighlighted]; 288 | button.titleLabel.font = [UIFont systemFontOfSize:18]; 289 | button.titleLabel.adjustsFontSizeToFitWidth = YES; 290 | button.layer.cornerRadius = kPaopaoAndKeyViewCornerRedius; 291 | button.layer.masksToBounds = YES; 292 | return button; 293 | } 294 | 295 | - (void)handleRotateScreenOrOn2OffScreen 296 | { 297 | if (self.currentKeyView.paopaoHidden == NO) { 298 | self.currentKeyView.paopaoHidden = YES; 299 | } 300 | self.userInteractionEnabled = YES; 301 | } 302 | - (NSArray *)characters 303 | { 304 | return nil; 305 | } 306 | 307 | - (NSString *)doneText { 308 | return @"完成"; 309 | } 310 | - (NSString *)switchText { 311 | return @"切换"; 312 | } 313 | - (NSInteger)rows 314 | { 315 | return -1; 316 | } 317 | - (NSInteger)columns 318 | { 319 | return -1; 320 | } 321 | - (WJLicensePlateKeyboardType)switch2KeyBoardType 322 | { 323 | return WJLicensePlateKeyboardTypeProvince; 324 | } 325 | - (BOOL)needSwitchKBAfterTouchEnd 326 | { 327 | return NO; 328 | } 329 | @end 330 | -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJLicensePlateKeyboard.bundle/UIDeviceModel.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AllDevices 6 | 7 | AppleTV1,1 8 | APPLE_TV_1G 9 | AppleTV2,1 10 | APPLE_TV_2G 11 | AppleTV3,1 12 | APPLE_TV_3G 13 | AppleTV3,2 14 | APPLE_TV_3_2G 15 | AppleTV5,3 16 | APPLE_TV_4G 17 | Watch1,1 18 | APPLE_WATCH_38 19 | Watch1,2 20 | APPLE_WATCH_42 21 | Watch2,3 22 | APPLE_WATCH_SERIES_2_38 23 | Watch2,4 24 | APPLE_WATCH_SERIES_2_42 25 | Watch2,6 26 | APPLE_WATCH_SERIES_1_38 27 | Watch2,7 28 | APPLE_WATCH_SERIES_1_42 29 | i386 30 | iPhone i386 Simulator 31 | x86_64 32 | iPhone x64 Simulator 33 | iPod1,1 34 | iPod Touch 1G 35 | iPod2,1 36 | iPod Touch 2G 37 | iPod3,1 38 | iPod Touch 3G 39 | iPod4,1 40 | iPod Touch 4G 41 | iPod5,1 42 | iPod Touch 5G 43 | iPod7,1 44 | iPod Touch 6G 45 | iPod9,1 46 | iPod Touch 7G 47 | iPad1,1 48 | iPad 49 | iPad1,2 50 | iPad 3G 51 | iPad2,1 52 | iPad 2 WIFI 53 | iPad2,2 54 | iPad 2 55 | iPad2,3 56 | iPad 2 CDMA 57 | iPad2,4 58 | iPad 2 59 | iPad2,5 60 | iPad Mini WIFI 61 | iPad2,6 62 | iPad Mini 63 | iPad2,7 64 | iPad Mini WIFI_CDMA 65 | iPad3,1 66 | iPad 3 WIFI 67 | iPad3,2 68 | iPad 3 WIFI_CDMA 69 | iPad3,3 70 | iPad 3 71 | iPad3,4 72 | iPad 4 WIFI 73 | iPad3,5 74 | iPad 4 75 | iPad3,6 76 | iPad 4 GSM_CDMA 77 | iPad4,1 78 | iPad Air WIFI 79 | iPad4,2 80 | iPad Air WIFI_GSM 81 | iPad4,3 82 | iPad Air WIFI_CDMA 83 | iPad4,4 84 | iPad Mini RETINA_WIFI 85 | iPad4,5 86 | iPad Mini RETINA_WIFI_CDMA 87 | iPad4,6 88 | iPad Mini RETINA_WIFI_CELLULAR_CN 89 | iPad4,7 90 | iPad Mini 3 WIFI 91 | iPad4,8 92 | iPad Mini 3 WIFI_CELLULAR 93 | iPad4,9 94 | iPad Mini 3 WIFI_CELLULAR_CN 95 | iPad5,1 96 | iPad Mini 4 WIFI 97 | iPad5,2 98 | iPad Mini 4 WIFI_CELLULAR 99 | iPad5,3 100 | iPad Air 2 WIFI 101 | iPad5,4 102 | iPad Air 2 WIFI_CELLULAR 103 | iPad6,11 104 | iPad 5 WIFI 105 | iPad6,12 106 | iPad 5 WIFI_CELLULAR 107 | iPad6,3 108 | iPad Pro 9.7 WIFI 109 | iPad6,4 110 | iPad Pro 9.7 WIFI_CELLULAR 111 | iPad6,7 112 | iPad Pro WIFI 113 | iPad6,8 114 | iPad Pro WIFI_CELLULAR 115 | iPad7,1 116 | iPad Pro 2G WIFI 117 | iPad7,11 118 | iPad 7 (WiFi) 119 | iPad7,12 120 | iPad 7 (WiFi/Cellular) 121 | iPad7,2 122 | iPad Pro 2G WIFI_CELLULAR 123 | iPad7,3 124 | iPad Pro 10.5 WIFI 125 | iPad7,4 126 | iPad Pro 10.5 WIFI_CELLULAR 127 | iPad7,5 128 | iPad 6 (WiFi) 129 | iPad7,6 130 | iPad 6 (WiFi/Cellular) 131 | iPad8,1 132 | iPad Pro 11-inch 1st-gen (WiFi) 133 | iPad8,10 134 | iPad Pro 11-inch 2nd-gen (WiFi/Cellular) 135 | iPad8,11 136 | iPad Pro 12.9-inch 4th-gen (WiFi) 137 | iPad8,12 138 | iPad Pro 12.9-inch 4th-gen (WiFi/Cellular) 139 | iPad8,2 140 | iPad Pro 11-inch 1st-gen (WiFi) 141 | iPad8,3 142 | iPad Pro 11-inch 1st-gen (WiFi/Cellular) 143 | iPad8,4 144 | iPad Pro 11-inch 1st-gen (WiFi/Cellular) 145 | iPad8,5 146 | iPad Pro 12.9-inch 3rd-gen (WiFi) 147 | iPad8,6 148 | iPad Pro 12.9-inch 3rd-gen (WiFi) 149 | iPad8,7 150 | iPad Pro 12.9-inch 3rd-gen (WiFi/Cellular) 151 | iPad8,8 152 | iPad Pro 12.9-inch 3rd-gen (WiFi/Cellular) 153 | iPad8,9 154 | iPad Pro 11-inch 2nd-gen (WiFi) 155 | iPad11,1 156 | iPad Mini 5 (WiFi) 157 | iPad11,2 158 | iPad Mini 5 (WiFi/Cellular) 159 | iPad11,3 160 | iPad Air 3 (WiFi) 161 | iPad11,4 162 | iPad Air 3 (WiFi/Cellular) 163 | iPad11,6 164 | iPad 8 (WiFi) 165 | iPad11,7 166 | iPad 8 (WiFi/Cellular) 167 | iPad12,1 168 | iPad 9 (WiFi) 169 | iPad12,2 170 | iPad 9 (WiFi/Cellular) 171 | iPad13,1 172 | iPad Air 4 (WiFi) 173 | iPad13,2 174 | iPad Air 4 (WiFi/Cellular) 175 | iPad13,4 176 | iPad Pro 11-inch 3rd-gen (WiFi) 177 | iPad13,5 178 | iPad Pro 11-inch 3rd-gen (WiFi/Cellular) 179 | iPad13,6 180 | iPad Pro 11-inch 3rd-gen (WiFi) 181 | iPad13,7 182 | iPad Pro 11-inch 3rd-gen (WiFi/Cellular) 183 | iPad13,8 184 | iPad Pro 12.9-inch 5th-gen (WiFi) 185 | iPad13,9 186 | iPad Pro 12.9-inch 5th-gen (WiFi/Cellular) 187 | iPad13,10 188 | iPad Pro 12.9-inch 5th-gen (WiFi) 189 | iPad13,11 190 | iPad Pro 12.9-inch 5th-gen (WiFi/Cellular) 191 | iPad13,16 192 | iPad Air 5 (WiFi) 193 | iPad13,17 194 | iPad Air 5 (WiFi/Cellular) 195 | iPad13,18 196 | iPad 10 (WiFi) 197 | iPad13,19 198 | iPad 10 (WiFi/Cellular) 199 | iPad14,1 200 | iPad mini 6 (WiFi) 201 | iPad14,2 202 | iPad mini 6 (WiFi/Cellular) 203 | iPad14,3 204 | iPad Pro 11-inch 4th-gen (WiFi) 205 | iPad14,4 206 | iPad Pro 11-inch 4th-gen (WiFi/Cellular) 207 | iPad14,5 208 | iPad Pro 12.9-inch 6th-gen (WiFi) 209 | iPad14,6 210 | iPad Pro 12.9-inch 6th-gen (WiFi/Cellular) 211 | iPad14,8 212 | iPad Air M2 11-inch (WiFi) 213 | iPad14,9 214 | iPad Air M2 11-inch (WiFi/Cellular) 215 | iPad14,10 216 | iPad Air M2 13-inch (WiFi) 217 | iPad14,11 218 | iPad Air M2 13-inch (WiFi/Cellular) 219 | iPad16,3 220 | iPad Pro M4 11-inch (WiFi) 221 | iPad16,4 222 | iPad Pro M4 11-inch (WiFi/Cellular) 223 | iPad16,5 224 | iPad Pro M4 13-inch (WiFi) 225 | iPad16,6 226 | iPad Pro M4 13-inch (WiFi/Cellular) 227 | iPhone1,1 228 | iPhone 2G 229 | iPhone1,2 230 | iPhone 3G 231 | iPhone2,1 232 | iPhone 3GS 233 | iPhone3,1 234 | iPhone 4 235 | iPhone3,2 236 | iPhone 4 237 | iPhone3,3 238 | iPhone 4 CDMA 239 | iPhone4,1 240 | iPhone 4s 241 | iPhone5,1 242 | iPhone 5 243 | iPhone5,2 244 | iPhone 5 CDMA_GSM 245 | iPhone5,3 246 | iPhone 5c 247 | iPhone5,4 248 | iPhone 5c CDMA_GSM 249 | iPhone6,1 250 | iPhone 5s 251 | iPhone6,2 252 | iPhone 5s CDMA_GSM 253 | iPhone7,1 254 | iPhone 6 Plus 255 | iPhone7,2 256 | iPhone 6 257 | iPhone8,1 258 | iPhone 6s 259 | iPhone8,2 260 | iPhone 6s Plus 261 | iPhone8,4 262 | iPhone SE 263 | iPhone9,1 264 | iPhone 7 265 | iPhone9,2 266 | iPhone 7 Plus 267 | iPhone9,3 268 | iPhone 7 GSM 269 | iPhone9,4 270 | iPhone 7 Plus_GSM 271 | iPhone10,1 272 | iPhone 8 CN 273 | iPhone10,2 274 | iPhone 8 Plus_CN 275 | iPhone10,3 276 | iPhone X CN 277 | iPhone10,4 278 | iPhone 8 279 | iPhone10,5 280 | iPhone 8 Plus 281 | iPhone10,6 282 | iPhone X 283 | iPhone11,2 284 | iPhone Xs 285 | iPhone11,4 286 | iPhone Xs_Max 287 | iPhone11,6 288 | iPhone Xs_Max 289 | iPhone11,8 290 | iPhone Xr 291 | iPhone12,1 292 | iPhone 11 293 | iPhone12,3 294 | iPhone 11 Pro 295 | iPhone12,5 296 | iPhone 11 Pro Max 297 | iPhone12,8 298 | iPhone SE 2nd-gen 299 | iPhone13,1 300 | iPhone 12 mini 301 | iPhone13,2 302 | iPhone 12 303 | iPhone13,3 304 | iPhone 12 Pro 305 | iPhone13,4 306 | iPhone 12 Pro Max 307 | iPhone14,2 308 | iPhone 13 Pro 309 | iPhone14,3 310 | iPhone 13 Pro Max 311 | iPhone14,4 312 | iPhone 13 mini 313 | iPhone14,5 314 | iPhone 13 315 | iPhone14,6 316 | iPhone SE 3rd-gen 317 | iPhone14,7 318 | iPhone 14 319 | iPhone14,8 320 | iPhone 14 Plus 321 | iPhone15,2 322 | iPhone 14 Pro 323 | iPhone15,3 324 | iPhone 14 Pro Max 325 | iPhone15,4 326 | iPhone 15 327 | iPhone15,5 328 | iPhone 15 Plus 329 | iPhone16,1 330 | iPhone 15 Pro 331 | iPhone16,2 332 | iPhone 15 Pro Max 333 | iPhone16,1 334 | iPhone 15 Pro 335 | iPhone16,2 336 | iPhone 15 Pro Max 337 | iPhone17,1 338 | iPhone 16 Pro 339 | iPhone17,2 340 | iPhone 16 Pro Max 341 | iPhone17,3 342 | iPhone 16 343 | iPhone17,4 344 | iPhone 16 Plus 345 | 346 | FringeDevices 347 | 348 | iPhone10,3 349 | iPhone10,6 350 | iPhone11,2 351 | iPhone11,4 352 | iPhone11,6 353 | iPhone11,8 354 | iPhone12,1 355 | iPhone12,3 356 | iPhone12,5 357 | iPhone13,1 358 | iPhone13,2 359 | iPhone13,3 360 | iPhone13,4 361 | iPhone14,2 362 | iPhone14,3 363 | iPhone14,4 364 | iPhone14,5 365 | iPhone14,7 366 | iPhone14,8 367 | iPhone15,2 368 | iPhone15,3 369 | iPhone15,4 370 | iPhone15,5 371 | iPhone16,1 372 | iPhone16,2 373 | iPhone17,1 374 | iPhone17,2 375 | iPhone17,3 376 | iPhone17,4 377 | 378 | version 379 | 2.0 380 | 381 | 382 | -------------------------------------------------------------------------------- /WJLicensePlateKeyBoard/WJLicensePlateKeyboard.m: -------------------------------------------------------------------------------- 1 | // 2 | // WJLicensePlateKeyboard.m 3 | // WJLicensePlateKeyboard 4 | // 5 | // Created by 彭维剑 on 2017/1/16. 6 | // Copyright © 2017年 pengweijian. All rights reserved. 7 | // 8 | 9 | #import "WJLicensePlateKeyboard.h" 10 | #import "WJLicensePlateEnglishView.h" 11 | #import "WJLicensePlateProvinceView.h" 12 | #import "WJLicensePlateKeyView.h" 13 | #import "WJConst.h" 14 | #import "UIDevice+Extension.h" 15 | #import 16 | 17 | #define kScreenWidth UIScreen.mainScreen.bounds.size.width 18 | 19 | @interface WJLicensePlateKeyboard () 20 | { 21 | @private 22 | NSArray *_zhCharacters; 23 | NSArray *_enCharacters; 24 | } 25 | /** 中文省份键盘 */ 26 | @property (nonatomic, weak) WJLicensePlateKBBaseView *provinceView; 27 | /** 英文字符数字键盘 */ 28 | @property (nonatomic, weak) WJLicensePlateKBBaseView *englishView; 29 | /** 当前显示的键盘 */ 30 | @property (nonatomic, weak) WJLicensePlateKBBaseView *currentKBBaseView; 31 | /** 定时器 */ 32 | @property (nonatomic, strong) CADisplayLink *deleteBackwordLink; 33 | /** 幂 */ 34 | @property (nonatomic, assign) NSUInteger power; 35 | /** 是否为刘海屏 */ 36 | @property (nonatomic, assign, getter=isFringeScreen) BOOL fringeScreen; 37 | @end 38 | 39 | 40 | @implementation WJLicensePlateKeyboard 41 | 42 | - (instancetype)initWithFrame:(CGRect)frame 43 | { 44 | CGRect keyBoardFrame = CGRectMake(0, 0, kScreenWidth, kKBHeight); 45 | if (self = [super initWithFrame:keyBoardFrame]) { 46 | [self setupSubKeyBoardWithZhCharacters:_zhCharacters enCharacters:_enCharacters]; 47 | } 48 | return self; 49 | } 50 | 51 | - (instancetype)initWithZhCharacters:(NSArray *)zhCharacters 52 | enCharacters:(NSArray *)enCharacters { 53 | CGRect keyBoardFrame = CGRectMake(0, 0, kScreenWidth, kKBHeight); 54 | if (self = [super initWithFrame:keyBoardFrame]) { 55 | _zhCharacters = zhCharacters; 56 | _enCharacters = enCharacters; 57 | [self setupSubKeyBoardWithZhCharacters:zhCharacters enCharacters:enCharacters]; 58 | } 59 | return self; 60 | } 61 | 62 | - (instancetype)initWithChineseView:(WJLicensePlateKBBaseView *)chineseView 63 | englishView:(WJLicensePlateKBBaseView *)englishView { 64 | CGRect keyBoardFrame = CGRectMake(0, 0, kScreenWidth, kKBHeight); 65 | if (self = [super initWithFrame:keyBoardFrame]) { 66 | [self setupSubKeyBoardWithChineseView:chineseView englishView:englishView]; 67 | } 68 | return self; 69 | } 70 | 71 | - (void)setChineseCharacters:(NSArray *)chineseCharacters { 72 | _zhCharacters = chineseCharacters; 73 | _provinceView.characters = chineseCharacters; 74 | } 75 | 76 | - (void)setEnglishCharacters:(NSArray *)englishCharacters { 77 | _enCharacters = englishCharacters; 78 | _englishView.characters = englishCharacters; 79 | } 80 | 81 | - (void)setupSubKeyBoardWithZhCharacters:(NSArray *)zhCharacters 82 | enCharacters:(NSArray *)enCharacters 83 | { 84 | // 省份键盘 85 | WJLicensePlateProvinceView *chineseView = [[WJLicensePlateProvinceView alloc] initWithCharacters:zhCharacters]; 86 | // 英文数字键盘 87 | WJLicensePlateEnglishView *englishView = [[WJLicensePlateEnglishView alloc] initWithCharacters:enCharacters]; 88 | [self setupSubKeyBoardWithChineseView:chineseView englishView:englishView]; 89 | } 90 | - (void)setupSubKeyBoardWithChineseView:(WJLicensePlateKBBaseView *)chineseView 91 | englishView:(WJLicensePlateKBBaseView *)englishView 92 | { 93 | // 省份键盘 94 | [chineseView removeFromSuperview]; 95 | [self addSubview:chineseView]; 96 | chineseView.hidden = NO; 97 | chineseView.delegate = self; 98 | _provinceView = chineseView; 99 | 100 | // 英文数字键盘 101 | [englishView removeFromSuperview]; 102 | [self addSubview:englishView]; 103 | englishView.hidden = YES; 104 | englishView.delegate = self; 105 | _englishView = englishView; 106 | 107 | // 记录当前显示省份键盘 108 | _currentKBBaseView = _provinceView; 109 | 110 | // 是否为刘海屏 111 | self.fringeScreen = [UIDevice isFringeScreen]; 112 | 113 | // 监听屏幕方向变化 114 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(screenOrientationDidChanged:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; 115 | } 116 | 117 | - (void)setInputTextView:(UIView *)inputTextView 118 | { 119 | _inputTextView = inputTextView; 120 | 121 | if ([inputTextView isKindOfClass:[UITextView class]]){ 122 | 123 | [(UITextView *)inputTextView setInputView:self]; 124 | }else if ([inputTextView isKindOfClass:[UITextField class]]){ 125 | 126 | [(UITextField *)inputTextView setInputView:self]; 127 | } 128 | } 129 | - (void)setTitleFont:(UIFont *)titleFont 130 | { 131 | _titleFont = titleFont; 132 | for (UIView *view in self.provinceView.keyViews) { 133 | if ([view isKindOfClass:[WJLicensePlateKeyView class]]) { 134 | WJLicensePlateKeyView *keyView = (WJLicensePlateKeyView *)view; 135 | keyView.titleFont = titleFont; 136 | } 137 | } 138 | for (UIView *view in self.englishView.keyViews) { 139 | if ([view isKindOfClass:[WJLicensePlateKeyView class]]) { 140 | WJLicensePlateKeyView *keyView = (WJLicensePlateKeyView *)view; 141 | keyView.titleFont = titleFont; 142 | } 143 | } 144 | } 145 | 146 | - (void)setPaopaoFont:(UIFont *)paopaoFont 147 | { 148 | _paopaoFont = paopaoFont; 149 | for (UIView *view in self.provinceView.keyViews) { 150 | if ([view isKindOfClass:[WJLicensePlateKeyView class]]) { 151 | WJLicensePlateKeyView *keyView = (WJLicensePlateKeyView *)view; 152 | keyView.paopaoFont = paopaoFont; 153 | } 154 | } 155 | for (UIView *view in self.englishView.keyViews) { 156 | if ([view isKindOfClass:[WJLicensePlateKeyView class]]) { 157 | WJLicensePlateKeyView *keyView = (WJLicensePlateKeyView *)view; 158 | keyView.paopaoFont = paopaoFont; 159 | } 160 | } 161 | } 162 | 163 | - (CADisplayLink *)deleteBackwordLink 164 | { 165 | if (!_deleteBackwordLink) { 166 | _deleteBackwordLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(startDeleteBackword)]; 167 | _deleteBackwordLink.paused = YES; 168 | // 初始定时为0.2秒(1.0/60*12) 169 | _deleteBackwordLink.frameInterval = 12; 170 | [_deleteBackwordLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; 171 | } 172 | return _deleteBackwordLink; 173 | } 174 | 175 | - (void)awakeFromNib 176 | { 177 | [super awakeFromNib]; 178 | self.frame = CGRectMake(0, 0, kScreenWidth, kKBHeight); 179 | [self setupSubKeyBoardWithZhCharacters:_zhCharacters enCharacters:_enCharacters]; 180 | } 181 | 182 | - (void)layoutSubviews 183 | { 184 | [super layoutSubviews]; 185 | CGRect frame; 186 | if (self.isFringeScreen) { 187 | frame = [self _subKeyBoardViewFrame]; 188 | }else{ 189 | frame = self.bounds; 190 | } 191 | 192 | CGRect subViewFrame = CGRectInset(frame, kKeyViewMarginH, kKeyViewMarginH); 193 | self.provinceView.frame = subViewFrame; 194 | self.englishView.frame = subViewFrame; 195 | } 196 | 197 | #pragma mark - LicensePlateKBBaseViewDelegate 198 | - (void)licensePlateKBBaseView:(WJLicensePlateKBBaseView *)kbBaseView didSwitch2KBType:(WJLicensePlateKeyboardType)switch2KBType playInput:(BOOL)playInput 199 | { 200 | if (playInput) [[UIDevice currentDevice] playInputClick]; 201 | 202 | switch (switch2KBType) { 203 | case WJLicensePlateKeyboardTypeEnglish: 204 | self.provinceView.hidden = YES; 205 | self.englishView.hidden = NO; 206 | _currentKBBaseView = self.englishView; 207 | break; 208 | case WJLicensePlateKeyboardTypeProvince: 209 | self.provinceView.hidden = NO; 210 | self.englishView.hidden = YES; 211 | _currentKBBaseView = self.provinceView; 212 | break; 213 | default: 214 | break; 215 | } 216 | } 217 | - (void)licensePlateKBBaseView:(WJLicensePlateKBBaseView *)kbBaseView didInsertText:(NSString *)text 218 | { 219 | [self.inputTextView insertText:text]; 220 | } 221 | 222 | - (void)licensePlateKBBaseViewStartDeleteBackward:(WJLicensePlateKBBaseView *)kbBaseView 223 | { 224 | if(self.inputTextView.hasText && self._canDeleteBackword){ 225 | self.deleteBackwordLink.paused = NO; 226 | }else{ 227 | [[UIDevice currentDevice] playInputClick]; 228 | } 229 | } 230 | - (void)licensePlateKBBaseViewEndDeleteBackward:(WJLicensePlateKBBaseView *)kbBaseView 231 | { 232 | [self stopDeleteBackward]; 233 | } 234 | 235 | - (void)licensePlateKBBaseViewDidFinish:(WJLicensePlateKBBaseView *)kbBaseView 236 | { 237 | [[UIDevice currentDevice] playInputClick]; 238 | [self.inputTextView resignFirstResponder]; 239 | } 240 | #pragma mark - 定时器 241 | - (void)startDeleteBackword 242 | { 243 | [[UIDevice currentDevice] playInputClick]; 244 | [_inputTextView deleteBackward]; 245 | if(self.inputTextView.hasText && self._canDeleteBackword){ 246 | // 0.2--0.183--0.166--0.15--0.083---0.05---0.033 247 | // 12----11----10----8-----4------3------1.5 248 | // 12--(12-2^0)--(12-2^1)---(12-2^2)----(12-2^3)----2 249 | if (_power > 3) { 250 | _deleteBackwordLink.frameInterval = 2; 251 | }else{ 252 | _deleteBackwordLink.frameInterval = 12-powl(2,_power); 253 | _power++; 254 | } 255 | }else{ 256 | [self stopDeleteBackward]; 257 | } 258 | } 259 | - (void)stopDeleteBackward 260 | { 261 | [_deleteBackwordLink invalidate]; 262 | _deleteBackwordLink = nil; 263 | _power = 0; 264 | } 265 | 266 | #pragma mark - UIInputViewAudioFeedback 267 | - (BOOL)enableInputClicksWhenVisible 268 | { 269 | return YES; 270 | } 271 | 272 | - (void)screenOrientationDidChanged:(NSNotification *)note 273 | { 274 | [self.currentKBBaseView handleRotateScreenOrOn2OffScreen]; 275 | UIDeviceOrientation orientation = [UIDevice currentDevice].orientation; 276 | if (self.isFringeScreen && UIDeviceOrientationIsLandscape(orientation)){ 277 | [self setNeedsLayout]; 278 | } 279 | // LicensePlateKBBaseView *currentKBBaseView = self.currentKBBaseView; 280 | // currentKBBaseView.userInteractionEnabled = YES; 281 | // for (UIView *view in currentKBBaseView.keyViews) { 282 | // if ([view isKindOfClass:[WJLicensePlateKeyView class]]) { 283 | // WJLicensePlateKeyView *keyView = (WJLicensePlateKeyView *)view; 284 | // if (keyView.paopaoHidden == NO) { 285 | // keyView.paopaoHidden = YES; 286 | // break; 287 | // } 288 | // } 289 | // } 290 | } 291 | - (void)willMoveToSuperview:(UIView *)newSuperview 292 | { 293 | [self.currentKBBaseView handleRotateScreenOrOn2OffScreen]; 294 | // LicensePlateKBBaseView *currentKBBaseView = self.currentKBBaseView; 295 | // currentKBBaseView.userInteractionEnabled = YES; 296 | // NSLog(@"%s---%@",__func__,newSuperview); 297 | // if (newSuperview) return; 298 | // for (UIView *view in currentKBBaseView.keyViews) { 299 | // if ([view isKindOfClass:[WJLicensePlateKeyView class]]) { 300 | // WJLicensePlateKeyView *keyView = (WJLicensePlateKeyView *)view; 301 | // if (keyView.paopaoHidden == NO) { 302 | // keyView.paopaoHidden = YES; 303 | // break; 304 | // } 305 | // } 306 | // } 307 | } 308 | 309 | #pragma mark - 私有方法 310 | /** 是否可回删文字 */ 311 | - (BOOL)_canDeleteBackword 312 | { 313 | // 选中的文字不为空,可直接删除 314 | BOOL empty = self.inputTextView.selectedTextRange.empty; 315 | if (!empty) return YES; 316 | UITextPosition *startP = self.inputTextView.selectedTextRange.start; 317 | UITextPosition *endP = self.inputTextView.selectedTextRange.end; 318 | if([startP isKindOfClass:NSClassFromString(@"_UITextKitTextPosition")]&&[endP isKindOfClass:NSClassFromString(@"_UITextKitTextPosition")]){ 319 | long long startL = [[startP valueForKeyPath:@"_offset"] longLongValue]; 320 | long long endL = [[endP valueForKeyPath:@"_offset"] longLongValue]; 321 | //说明光标在(0,0)位置,没有可删除的 322 | return (0!=startL || 0!=endL); 323 | }else{ 324 | return YES; 325 | } 326 | } 327 | /** 328 | 子键盘对称性的的frame,横屏时键盘与屏幕的左边padding = 键盘与屏幕的右边padding, 且刚好等于 kFringeTopPadding 329 | */ 330 | - (CGRect)_subKeyBoardViewFrame 331 | { 332 | CGRect frame = self.bounds; 333 | UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; 334 | frame.size.height -= kFringeBottomPadding; 335 | BOOL isFill = (self.subKBFrameType == KeyboardSubKBFrameTypeFill); 336 | switch (orientation) { 337 | case UIInterfaceOrientationPortrait: 338 | // NSLog(@"竖屏向下"); 339 | break; 340 | case UIInterfaceOrientationLandscapeLeft: 341 | frame.origin.x = isFill ? kFineTuningSafePadding : kFringeTopPadding; 342 | frame.size.width -= (isFill ? kFringeTopPadding+2*kFineTuningSafePadding : 2*kFringeTopPadding); 343 | // NSLog(@"横屏向左"); 344 | break; 345 | case UIInterfaceOrientationLandscapeRight: 346 | frame.origin.x = (isFill ? kFineTuningSafePadding + kFringeTopPadding : kFringeTopPadding); 347 | frame.size.width -= (isFill ? kFringeTopPadding+2*kFineTuningSafePadding : 2*kFringeTopPadding); 348 | // NSLog(@"横屏向右"); 349 | break; 350 | default: 351 | break; 352 | } 353 | return frame; 354 | } 355 | 356 | - (void)dealloc 357 | { 358 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 359 | } 360 | @end 361 | -------------------------------------------------------------------------------- /WJLicensePlateKeyboard.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 5F5F866E26B1DA280022BE5C /* EnglishKeyboardView.m in Sources */ = {isa = PBXBuildFile; fileRef = 5F5F866D26B1DA280022BE5C /* EnglishKeyboardView.m */; }; 11 | A06D009B25BFC2C80050ECED /* UIDevice+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = A06D009925BFC2C80050ECED /* UIDevice+Extension.m */; }; 12 | A7BF801A1E31ECEF00677E16 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A7BF800F1E31ECEF00677E16 /* AppDelegate.m */; }; 13 | A7BF801B1E31ECEF00677E16 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A7BF80101E31ECEF00677E16 /* Assets.xcassets */; }; 14 | A7BF801C1E31ECEF00677E16 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A7BF80121E31ECEF00677E16 /* LaunchScreen.storyboard */; }; 15 | A7BF801D1E31ECEF00677E16 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A7BF80141E31ECEF00677E16 /* Main.storyboard */; }; 16 | A7BF801F1E31ECEF00677E16 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = A7BF80171E31ECEF00677E16 /* main.m */; }; 17 | A7BF80201E31ECEF00677E16 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A7BF80191E31ECEF00677E16 /* ViewController.m */; }; 18 | A7BF80341E31EE8700677E16 /* WJLicensePlateEnglishView.m in Sources */ = {isa = PBXBuildFile; fileRef = A7BF80281E31EE8700677E16 /* WJLicensePlateEnglishView.m */; }; 19 | A7BF80351E31EE8700677E16 /* WJLicensePlateKBBaseView.m in Sources */ = {isa = PBXBuildFile; fileRef = A7BF802A1E31EE8700677E16 /* WJLicensePlateKBBaseView.m */; }; 20 | A7BF80361E31EE8700677E16 /* WJLicensePlateKeyboard.m in Sources */ = {isa = PBXBuildFile; fileRef = A7BF802C1E31EE8700677E16 /* WJLicensePlateKeyboard.m */; }; 21 | A7BF80371E31EE8700677E16 /* WJLicensePlateKeyView.m in Sources */ = {isa = PBXBuildFile; fileRef = A7BF802E1E31EE8700677E16 /* WJLicensePlateKeyView.m */; }; 22 | A7BF80381E31EE8700677E16 /* WJLicensePlateProvinceView.m in Sources */ = {isa = PBXBuildFile; fileRef = A7BF80301E31EE8700677E16 /* WJLicensePlateProvinceView.m */; }; 23 | A7BF80391E31EE8700677E16 /* WJConst.m in Sources */ = {isa = PBXBuildFile; fileRef = A7BF80321E31EE8700677E16 /* WJConst.m */; }; 24 | A7BF803A1E31F13700677E16 /* ViewController.m in Resources */ = {isa = PBXBuildFile; fileRef = A7BF80191E31ECEF00677E16 /* ViewController.m */; }; 25 | A7BF803C1E31F2D900677E16 /* WJLicensePlateKeyboard.bundle in Resources */ = {isa = PBXBuildFile; fileRef = A7BF803B1E31F2D900677E16 /* WJLicensePlateKeyboard.bundle */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 5F5F866C26B1DA280022BE5C /* EnglishKeyboardView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EnglishKeyboardView.h; sourceTree = ""; }; 30 | 5F5F866D26B1DA280022BE5C /* EnglishKeyboardView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EnglishKeyboardView.m; sourceTree = ""; }; 31 | A06D009825BFC2C80050ECED /* UIDevice+Extension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIDevice+Extension.h"; sourceTree = ""; }; 32 | A06D009925BFC2C80050ECED /* UIDevice+Extension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIDevice+Extension.m"; sourceTree = ""; }; 33 | A0DFB8C626B28070009F420D /* WJKeyBoardHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WJKeyBoardHeader.h; sourceTree = ""; }; 34 | A7BF7FF31E31EA3100677E16 /* WJLicensePlateKeyBoard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WJLicensePlateKeyBoard.app; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | A7BF800E1E31ECEF00677E16 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 36 | A7BF800F1E31ECEF00677E16 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 37 | A7BF80101E31ECEF00677E16 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 38 | A7BF80131E31ECEF00677E16 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = LaunchScreen.storyboard; sourceTree = ""; }; 39 | A7BF80151E31ECEF00677E16 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Main.storyboard; sourceTree = ""; }; 40 | A7BF80161E31ECEF00677E16 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | A7BF80171E31ECEF00677E16 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 42 | A7BF80181E31ECEF00677E16 /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 43 | A7BF80191E31ECEF00677E16 /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 44 | A7BF80271E31EE8700677E16 /* WJLicensePlateEnglishView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WJLicensePlateEnglishView.h; sourceTree = ""; }; 45 | A7BF80281E31EE8700677E16 /* WJLicensePlateEnglishView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WJLicensePlateEnglishView.m; sourceTree = ""; }; 46 | A7BF80291E31EE8700677E16 /* WJLicensePlateKBBaseView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WJLicensePlateKBBaseView.h; sourceTree = ""; }; 47 | A7BF802A1E31EE8700677E16 /* WJLicensePlateKBBaseView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WJLicensePlateKBBaseView.m; sourceTree = ""; }; 48 | A7BF802B1E31EE8700677E16 /* WJLicensePlateKeyboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WJLicensePlateKeyboard.h; sourceTree = ""; }; 49 | A7BF802C1E31EE8700677E16 /* WJLicensePlateKeyboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WJLicensePlateKeyboard.m; sourceTree = ""; }; 50 | A7BF802D1E31EE8700677E16 /* WJLicensePlateKeyView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WJLicensePlateKeyView.h; sourceTree = ""; }; 51 | A7BF802E1E31EE8700677E16 /* WJLicensePlateKeyView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WJLicensePlateKeyView.m; sourceTree = ""; }; 52 | A7BF802F1E31EE8700677E16 /* WJLicensePlateProvinceView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WJLicensePlateProvinceView.h; sourceTree = ""; }; 53 | A7BF80301E31EE8700677E16 /* WJLicensePlateProvinceView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WJLicensePlateProvinceView.m; sourceTree = ""; }; 54 | A7BF80311E31EE8700677E16 /* WJConst.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WJConst.h; sourceTree = ""; }; 55 | A7BF80321E31EE8700677E16 /* WJConst.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WJConst.m; sourceTree = ""; }; 56 | A7BF803B1E31F2D900677E16 /* WJLicensePlateKeyboard.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = WJLicensePlateKeyboard.bundle; sourceTree = ""; }; 57 | /* End PBXFileReference section */ 58 | 59 | /* Begin PBXFrameworksBuildPhase section */ 60 | A7BF7FF01E31EA3100677E16 /* Frameworks */ = { 61 | isa = PBXFrameworksBuildPhase; 62 | buildActionMask = 2147483647; 63 | files = ( 64 | ); 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | /* End PBXFrameworksBuildPhase section */ 68 | 69 | /* Begin PBXGroup section */ 70 | A7BF7FEA1E31EA3100677E16 = { 71 | isa = PBXGroup; 72 | children = ( 73 | A7BF7FF51E31EA3100677E16 /* WJLicensePlateKeyboard */, 74 | A7BF800D1E31EC9700677E16 /* demo */, 75 | A7BF7FF41E31EA3100677E16 /* Products */, 76 | ); 77 | sourceTree = ""; 78 | }; 79 | A7BF7FF41E31EA3100677E16 /* Products */ = { 80 | isa = PBXGroup; 81 | children = ( 82 | A7BF7FF31E31EA3100677E16 /* WJLicensePlateKeyBoard.app */, 83 | ); 84 | name = Products; 85 | sourceTree = ""; 86 | }; 87 | A7BF7FF51E31EA3100677E16 /* WJLicensePlateKeyboard */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | A06D009825BFC2C80050ECED /* UIDevice+Extension.h */, 91 | A06D009925BFC2C80050ECED /* UIDevice+Extension.m */, 92 | A7BF80311E31EE8700677E16 /* WJConst.h */, 93 | A7BF80321E31EE8700677E16 /* WJConst.m */, 94 | A7BF80271E31EE8700677E16 /* WJLicensePlateEnglishView.h */, 95 | A7BF80281E31EE8700677E16 /* WJLicensePlateEnglishView.m */, 96 | A7BF80291E31EE8700677E16 /* WJLicensePlateKBBaseView.h */, 97 | A7BF802A1E31EE8700677E16 /* WJLicensePlateKBBaseView.m */, 98 | A7BF803B1E31F2D900677E16 /* WJLicensePlateKeyboard.bundle */, 99 | A7BF802B1E31EE8700677E16 /* WJLicensePlateKeyboard.h */, 100 | A7BF802C1E31EE8700677E16 /* WJLicensePlateKeyboard.m */, 101 | A7BF802D1E31EE8700677E16 /* WJLicensePlateKeyView.h */, 102 | A7BF802E1E31EE8700677E16 /* WJLicensePlateKeyView.m */, 103 | A7BF802F1E31EE8700677E16 /* WJLicensePlateProvinceView.h */, 104 | A7BF80301E31EE8700677E16 /* WJLicensePlateProvinceView.m */, 105 | A0DFB8C626B28070009F420D /* WJKeyBoardHeader.h */, 106 | ); 107 | name = WJLicensePlateKeyboard; 108 | path = WJLicensePlateKeyBoard; 109 | sourceTree = ""; 110 | }; 111 | A7BF7FF61E31EA3100677E16 /* Supporting Files */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | ); 115 | name = "Supporting Files"; 116 | path = ../WJLicensePlateKeyBoard; 117 | sourceTree = ""; 118 | }; 119 | A7BF800D1E31EC9700677E16 /* demo */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | A7BF800E1E31ECEF00677E16 /* AppDelegate.h */, 123 | A7BF800F1E31ECEF00677E16 /* AppDelegate.m */, 124 | A7BF80181E31ECEF00677E16 /* ViewController.h */, 125 | A7BF80191E31ECEF00677E16 /* ViewController.m */, 126 | A7BF80101E31ECEF00677E16 /* Assets.xcassets */, 127 | A7BF80111E31ECEF00677E16 /* Base.lproj */, 128 | A7BF80161E31ECEF00677E16 /* Info.plist */, 129 | A7BF80171E31ECEF00677E16 /* main.m */, 130 | A7BF7FF61E31EA3100677E16 /* Supporting Files */, 131 | 5F5F866C26B1DA280022BE5C /* EnglishKeyboardView.h */, 132 | 5F5F866D26B1DA280022BE5C /* EnglishKeyboardView.m */, 133 | ); 134 | path = demo; 135 | sourceTree = ""; 136 | }; 137 | A7BF80111E31ECEF00677E16 /* Base.lproj */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | A7BF80121E31ECEF00677E16 /* LaunchScreen.storyboard */, 141 | A7BF80141E31ECEF00677E16 /* Main.storyboard */, 142 | ); 143 | path = Base.lproj; 144 | sourceTree = ""; 145 | }; 146 | /* End PBXGroup section */ 147 | 148 | /* Begin PBXNativeTarget section */ 149 | A7BF7FF21E31EA3100677E16 /* WJLicensePlateKeyBoard */ = { 150 | isa = PBXNativeTarget; 151 | buildConfigurationList = A7BF800A1E31EA3200677E16 /* Build configuration list for PBXNativeTarget "WJLicensePlateKeyBoard" */; 152 | buildPhases = ( 153 | A7BF7FEF1E31EA3100677E16 /* Sources */, 154 | A7BF7FF01E31EA3100677E16 /* Frameworks */, 155 | A7BF7FF11E31EA3100677E16 /* Resources */, 156 | ); 157 | buildRules = ( 158 | ); 159 | dependencies = ( 160 | ); 161 | name = WJLicensePlateKeyBoard; 162 | productName = WJLicensePlateKeyBoard; 163 | productReference = A7BF7FF31E31EA3100677E16 /* WJLicensePlateKeyBoard.app */; 164 | productType = "com.apple.product-type.application"; 165 | }; 166 | /* End PBXNativeTarget section */ 167 | 168 | /* Begin PBXProject section */ 169 | A7BF7FEB1E31EA3100677E16 /* Project object */ = { 170 | isa = PBXProject; 171 | attributes = { 172 | LastUpgradeCheck = 0820; 173 | ORGANIZATIONNAME = pengweijian; 174 | TargetAttributes = { 175 | A7BF7FF21E31EA3100677E16 = { 176 | CreatedOnToolsVersion = 8.2.1; 177 | ProvisioningStyle = Automatic; 178 | }; 179 | }; 180 | }; 181 | buildConfigurationList = A7BF7FEE1E31EA3100677E16 /* Build configuration list for PBXProject "WJLicensePlateKeyboard" */; 182 | compatibilityVersion = "Xcode 3.2"; 183 | developmentRegion = English; 184 | hasScannedForEncodings = 0; 185 | knownRegions = ( 186 | English, 187 | en, 188 | Base, 189 | ); 190 | mainGroup = A7BF7FEA1E31EA3100677E16; 191 | productRefGroup = A7BF7FF41E31EA3100677E16 /* Products */; 192 | projectDirPath = ""; 193 | projectRoot = ""; 194 | targets = ( 195 | A7BF7FF21E31EA3100677E16 /* WJLicensePlateKeyBoard */, 196 | ); 197 | }; 198 | /* End PBXProject section */ 199 | 200 | /* Begin PBXResourcesBuildPhase section */ 201 | A7BF7FF11E31EA3100677E16 /* Resources */ = { 202 | isa = PBXResourcesBuildPhase; 203 | buildActionMask = 2147483647; 204 | files = ( 205 | A7BF803C1E31F2D900677E16 /* WJLicensePlateKeyboard.bundle in Resources */, 206 | A7BF803A1E31F13700677E16 /* ViewController.m in Resources */, 207 | A7BF801B1E31ECEF00677E16 /* Assets.xcassets in Resources */, 208 | A7BF801D1E31ECEF00677E16 /* Main.storyboard in Resources */, 209 | A7BF801C1E31ECEF00677E16 /* LaunchScreen.storyboard in Resources */, 210 | ); 211 | runOnlyForDeploymentPostprocessing = 0; 212 | }; 213 | /* End PBXResourcesBuildPhase section */ 214 | 215 | /* Begin PBXSourcesBuildPhase section */ 216 | A7BF7FEF1E31EA3100677E16 /* Sources */ = { 217 | isa = PBXSourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | A7BF80371E31EE8700677E16 /* WJLicensePlateKeyView.m in Sources */, 221 | A06D009B25BFC2C80050ECED /* UIDevice+Extension.m in Sources */, 222 | A7BF80201E31ECEF00677E16 /* ViewController.m in Sources */, 223 | A7BF80361E31EE8700677E16 /* WJLicensePlateKeyboard.m in Sources */, 224 | A7BF801F1E31ECEF00677E16 /* main.m in Sources */, 225 | A7BF80351E31EE8700677E16 /* WJLicensePlateKBBaseView.m in Sources */, 226 | A7BF80341E31EE8700677E16 /* WJLicensePlateEnglishView.m in Sources */, 227 | A7BF801A1E31ECEF00677E16 /* AppDelegate.m in Sources */, 228 | 5F5F866E26B1DA280022BE5C /* EnglishKeyboardView.m in Sources */, 229 | A7BF80391E31EE8700677E16 /* WJConst.m in Sources */, 230 | A7BF80381E31EE8700677E16 /* WJLicensePlateProvinceView.m in Sources */, 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | }; 234 | /* End PBXSourcesBuildPhase section */ 235 | 236 | /* Begin PBXVariantGroup section */ 237 | A7BF80121E31ECEF00677E16 /* LaunchScreen.storyboard */ = { 238 | isa = PBXVariantGroup; 239 | children = ( 240 | A7BF80131E31ECEF00677E16 /* Base */, 241 | ); 242 | name = LaunchScreen.storyboard; 243 | sourceTree = ""; 244 | }; 245 | A7BF80141E31ECEF00677E16 /* Main.storyboard */ = { 246 | isa = PBXVariantGroup; 247 | children = ( 248 | A7BF80151E31ECEF00677E16 /* Base */, 249 | ); 250 | name = Main.storyboard; 251 | sourceTree = ""; 252 | }; 253 | /* End PBXVariantGroup section */ 254 | 255 | /* Begin XCBuildConfiguration section */ 256 | A7BF80081E31EA3200677E16 /* Debug */ = { 257 | isa = XCBuildConfiguration; 258 | buildSettings = { 259 | ALWAYS_SEARCH_USER_PATHS = NO; 260 | CLANG_ANALYZER_NONNULL = YES; 261 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 262 | CLANG_CXX_LIBRARY = "libc++"; 263 | CLANG_ENABLE_MODULES = YES; 264 | CLANG_ENABLE_OBJC_ARC = YES; 265 | CLANG_WARN_BOOL_CONVERSION = YES; 266 | CLANG_WARN_CONSTANT_CONVERSION = YES; 267 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 268 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 269 | CLANG_WARN_EMPTY_BODY = YES; 270 | CLANG_WARN_ENUM_CONVERSION = YES; 271 | CLANG_WARN_INFINITE_RECURSION = YES; 272 | CLANG_WARN_INT_CONVERSION = YES; 273 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 274 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 275 | CLANG_WARN_UNREACHABLE_CODE = YES; 276 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 277 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 278 | COPY_PHASE_STRIP = NO; 279 | DEBUG_INFORMATION_FORMAT = dwarf; 280 | ENABLE_STRICT_OBJC_MSGSEND = YES; 281 | ENABLE_TESTABILITY = YES; 282 | GCC_C_LANGUAGE_STANDARD = gnu99; 283 | GCC_DYNAMIC_NO_PIC = NO; 284 | GCC_NO_COMMON_BLOCKS = YES; 285 | GCC_OPTIMIZATION_LEVEL = 0; 286 | GCC_PREPROCESSOR_DEFINITIONS = ( 287 | "DEBUG=1", 288 | "$(inherited)", 289 | ); 290 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 291 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 292 | GCC_WARN_UNDECLARED_SELECTOR = YES; 293 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 294 | GCC_WARN_UNUSED_FUNCTION = YES; 295 | GCC_WARN_UNUSED_VARIABLE = YES; 296 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 297 | MTL_ENABLE_DEBUG_INFO = YES; 298 | ONLY_ACTIVE_ARCH = YES; 299 | SDKROOT = iphoneos; 300 | }; 301 | name = Debug; 302 | }; 303 | A7BF80091E31EA3200677E16 /* Release */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | ALWAYS_SEARCH_USER_PATHS = NO; 307 | CLANG_ANALYZER_NONNULL = YES; 308 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 309 | CLANG_CXX_LIBRARY = "libc++"; 310 | CLANG_ENABLE_MODULES = YES; 311 | CLANG_ENABLE_OBJC_ARC = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_CONSTANT_CONVERSION = YES; 314 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 315 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 316 | CLANG_WARN_EMPTY_BODY = YES; 317 | CLANG_WARN_ENUM_CONVERSION = YES; 318 | CLANG_WARN_INFINITE_RECURSION = YES; 319 | CLANG_WARN_INT_CONVERSION = YES; 320 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 321 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 322 | CLANG_WARN_UNREACHABLE_CODE = YES; 323 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 324 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 325 | COPY_PHASE_STRIP = NO; 326 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 327 | ENABLE_NS_ASSERTIONS = NO; 328 | ENABLE_STRICT_OBJC_MSGSEND = YES; 329 | GCC_C_LANGUAGE_STANDARD = gnu99; 330 | GCC_NO_COMMON_BLOCKS = YES; 331 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 332 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 333 | GCC_WARN_UNDECLARED_SELECTOR = YES; 334 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 335 | GCC_WARN_UNUSED_FUNCTION = YES; 336 | GCC_WARN_UNUSED_VARIABLE = YES; 337 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 338 | MTL_ENABLE_DEBUG_INFO = NO; 339 | SDKROOT = iphoneos; 340 | VALIDATE_PRODUCT = YES; 341 | }; 342 | name = Release; 343 | }; 344 | A7BF800B1E31EA3200677E16 /* Debug */ = { 345 | isa = XCBuildConfiguration; 346 | buildSettings = { 347 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 348 | CODE_SIGN_IDENTITY = "iPhone Developer"; 349 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 350 | CODE_SIGN_STYLE = Automatic; 351 | DEVELOPMENT_TEAM = ""; 352 | INFOPLIST_FILE = "$(SRCROOT)/demo/Info.plist"; 353 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 354 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 355 | PRODUCT_BUNDLE_IDENTIFIER = com.loyalwind; 356 | PRODUCT_NAME = "$(TARGET_NAME)"; 357 | PROVISIONING_PROFILE = "475859dc-8e03-4ec1-843e-731c1abf35e6"; 358 | PROVISIONING_PROFILE_SPECIFIER = ""; 359 | TARGETED_DEVICE_FAMILY = "1,2"; 360 | }; 361 | name = Debug; 362 | }; 363 | A7BF800C1E31EA3200677E16 /* Release */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 367 | CODE_SIGN_IDENTITY = "iPhone Developer"; 368 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 369 | CODE_SIGN_STYLE = Automatic; 370 | DEVELOPMENT_TEAM = ""; 371 | INFOPLIST_FILE = "$(SRCROOT)/demo/Info.plist"; 372 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 373 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 374 | PRODUCT_BUNDLE_IDENTIFIER = com.loyalwind; 375 | PRODUCT_NAME = "$(TARGET_NAME)"; 376 | PROVISIONING_PROFILE_SPECIFIER = ""; 377 | TARGETED_DEVICE_FAMILY = "1,2"; 378 | }; 379 | name = Release; 380 | }; 381 | /* End XCBuildConfiguration section */ 382 | 383 | /* Begin XCConfigurationList section */ 384 | A7BF7FEE1E31EA3100677E16 /* Build configuration list for PBXProject "WJLicensePlateKeyboard" */ = { 385 | isa = XCConfigurationList; 386 | buildConfigurations = ( 387 | A7BF80081E31EA3200677E16 /* Debug */, 388 | A7BF80091E31EA3200677E16 /* Release */, 389 | ); 390 | defaultConfigurationIsVisible = 0; 391 | defaultConfigurationName = Release; 392 | }; 393 | A7BF800A1E31EA3200677E16 /* Build configuration list for PBXNativeTarget "WJLicensePlateKeyBoard" */ = { 394 | isa = XCConfigurationList; 395 | buildConfigurations = ( 396 | A7BF800B1E31EA3200677E16 /* Debug */, 397 | A7BF800C1E31EA3200677E16 /* Release */, 398 | ); 399 | defaultConfigurationIsVisible = 0; 400 | defaultConfigurationName = Release; 401 | }; 402 | /* End XCConfigurationList section */ 403 | }; 404 | rootObject = A7BF7FEB1E31EA3100677E16 /* Project object */; 405 | } 406 | --------------------------------------------------------------------------------