Browse Source

节拍器效果

Steven 2 years ago
parent
commit
88cd08ecaa
58 changed files with 1214 additions and 19 deletions
  1. 78 0
      KulexiuForStudent/KulexiuForStudent.xcodeproj/project.pbxproj
  2. BIN
      KulexiuForStudent/KulexiuForStudent.xcworkspace/xcuserdata/wangzhi.xcuserdatad/UserInterfaceState.xcuserstate
  3. 0 16
      KulexiuForStudent/KulexiuForStudent.xcworkspace/xcuserdata/wangzhi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
  4. 6 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/Contents.json
  5. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/eighth_node.imageset/Contents.json
  6. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/eighth_node.imageset/eighth_node@2x.png
  7. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/eighth_node.imageset/eighth_node@3x.png
  8. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/half_node.imageset/Contents.json
  9. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/half_node.imageset/half_node@2x.png
  10. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/half_node.imageset/half_node@3x.png
  11. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/metronome_bg.imageset/Contents.json
  12. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/metronome_bg.imageset/metronome_bg@2x.png
  13. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/metronome_bg.imageset/metronome_bg@3x.png
  14. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/quarter_node.imageset/Contents.json
  15. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/quarter_node.imageset/quarter_node@2x.png
  16. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/quarter_node.imageset/quarter_node@3x.png
  17. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/sixteenth_node.imageset/Contents.json
  18. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/sixteenth_node.imageset/sixteenth_node@2x.png
  19. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/sixteenth_node.imageset/sixteenth_node@3x.png
  20. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/slider_image.imageset/Contents.json
  21. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/slider_image.imageset/slider_image@2x.png
  22. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/slider_image.imageset/slider_image@3x.png
  23. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_add.imageset/Contents.json
  24. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_add.imageset/speed_add@2x.png
  25. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_add.imageset/speed_add@3x.png
  26. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_background.imageset/Contents.json
  27. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_background.imageset/speed_background@2x.png
  28. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_background.imageset/speed_background@3x.png
  29. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_button_bg.imageset/Contents.json
  30. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_button_bg.imageset/speed_button_bg@2x.png
  31. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_button_bg.imageset/speed_button_bg@3x.png
  32. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_dot.imageset/Contents.json
  33. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_dot.imageset/speed_dot@2x.png
  34. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_dot.imageset/speed_dot@3x.png
  35. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_minus.imageset/Contents.json
  36. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_minus.imageset/speed_minus@2x.png
  37. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_minus.imageset/speed_minus@3x.png
  38. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/volume_down.imageset/Contents.json
  39. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/volume_down.imageset/volume_down@2x.png
  40. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/volume_down.imageset/volume_down@3x.png
  41. 22 0
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/volume_up.imageset/Contents.json
  42. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/volume_up.imageset/volume_up@2x.png
  43. BIN
      KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/volume_up.imageset/volume_up@3x.png
  44. 11 3
      KulexiuForStudent/KulexiuForStudent/Module/Home/Controller/HomeViewController.m
  45. 16 0
      KulexiuForStudent/KulexiuForStudent/Module/Widget/Controller/WidgetViewController.h
  46. 157 0
      KulexiuForStudent/KulexiuForStudent/Module/Widget/Controller/WidgetViewController.m
  47. 32 0
      KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetDotView.h
  48. 29 0
      KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetDotView.m
  49. 22 0
      KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetDotView.xib
  50. 35 0
      KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetFunctionView.h
  51. 76 0
      KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetFunctionView.m
  52. 95 0
      KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetFunctionView.xib
  53. 18 0
      KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetNavView.h
  54. 26 0
      KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetNavView.m
  55. 64 0
      KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetNavView.xib
  56. 41 0
      KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetSpeedView.h
  57. 141 0
      KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetSpeedView.m
  58. 81 0
      KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetSpeedView.xib

+ 78 - 0
KulexiuForStudent/KulexiuForStudent.xcodeproj/project.pbxproj

@@ -457,6 +457,15 @@
 		BC4CF27128D0283300961C61 /* HomeQualityMusicCollectionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC4CF26F28D0283300961C61 /* HomeQualityMusicCollectionCell.xib */; };
 		BC4CF27428D0285400961C61 /* HomeQualityMusicCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC4CF27328D0285400961C61 /* HomeQualityMusicCellView.m */; };
 		BC4CF27628D0285A00961C61 /* HomeQualityMusicCellView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC4CF27528D0285A00961C61 /* HomeQualityMusicCellView.xib */; };
+		BC4CF28E28D072C000961C61 /* WidgetViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC4CF28D28D072C000961C61 /* WidgetViewController.m */; };
+		BC4CF29128D072EF00961C61 /* WidgetNavView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC4CF29028D072EF00961C61 /* WidgetNavView.m */; };
+		BC4CF29328D072F600961C61 /* WidgetNavView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC4CF29228D072F600961C61 /* WidgetNavView.xib */; };
+		BC4CF29628D074DC00961C61 /* WidgetDotView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC4CF29528D074DC00961C61 /* WidgetDotView.m */; };
+		BC4CF29828D074E700961C61 /* WidgetDotView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC4CF29728D074E700961C61 /* WidgetDotView.xib */; };
+		BC4CF29B28D0757800961C61 /* WidgetSpeedView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC4CF29A28D0757800961C61 /* WidgetSpeedView.m */; };
+		BC4CF29D28D0758700961C61 /* WidgetSpeedView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC4CF29C28D0758700961C61 /* WidgetSpeedView.xib */; };
+		BC4CF2A028D075CC00961C61 /* WidgetFunctionView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC4CF29F28D075CC00961C61 /* WidgetFunctionView.m */; };
+		BC4CF2A228D075D400961C61 /* WidgetFunctionView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC4CF2A128D075D400961C61 /* WidgetFunctionView.xib */; };
 		BC50171227FC0D5600F8BCBC /* SubjectChooseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC50171127FC0D5600F8BCBC /* SubjectChooseViewController.m */; };
 		BC50171527FC0D8300F8BCBC /* SubjectChooseBodyView.m in Sources */ = {isa = PBXBuildFile; fileRef = BC50171427FC0D8300F8BCBC /* SubjectChooseBodyView.m */; };
 		BC50171727FC0D8E00F8BCBC /* SubjectChooseBodyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC50171627FC0D8D00F8BCBC /* SubjectChooseBodyView.xib */; };
@@ -1768,6 +1777,20 @@
 		BC4CF27228D0285400961C61 /* HomeQualityMusicCellView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HomeQualityMusicCellView.h; sourceTree = "<group>"; };
 		BC4CF27328D0285400961C61 /* HomeQualityMusicCellView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HomeQualityMusicCellView.m; sourceTree = "<group>"; };
 		BC4CF27528D0285A00961C61 /* HomeQualityMusicCellView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HomeQualityMusicCellView.xib; sourceTree = "<group>"; };
+		BC4CF28C28D072C000961C61 /* WidgetViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WidgetViewController.h; sourceTree = "<group>"; };
+		BC4CF28D28D072C000961C61 /* WidgetViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WidgetViewController.m; sourceTree = "<group>"; };
+		BC4CF28F28D072EF00961C61 /* WidgetNavView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WidgetNavView.h; sourceTree = "<group>"; };
+		BC4CF29028D072EF00961C61 /* WidgetNavView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WidgetNavView.m; sourceTree = "<group>"; };
+		BC4CF29228D072F600961C61 /* WidgetNavView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = WidgetNavView.xib; sourceTree = "<group>"; };
+		BC4CF29428D074DC00961C61 /* WidgetDotView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WidgetDotView.h; sourceTree = "<group>"; };
+		BC4CF29528D074DC00961C61 /* WidgetDotView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WidgetDotView.m; sourceTree = "<group>"; };
+		BC4CF29728D074E700961C61 /* WidgetDotView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = WidgetDotView.xib; sourceTree = "<group>"; };
+		BC4CF29928D0757800961C61 /* WidgetSpeedView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WidgetSpeedView.h; sourceTree = "<group>"; };
+		BC4CF29A28D0757800961C61 /* WidgetSpeedView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WidgetSpeedView.m; sourceTree = "<group>"; };
+		BC4CF29C28D0758700961C61 /* WidgetSpeedView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = WidgetSpeedView.xib; sourceTree = "<group>"; };
+		BC4CF29E28D075CC00961C61 /* WidgetFunctionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WidgetFunctionView.h; sourceTree = "<group>"; };
+		BC4CF29F28D075CC00961C61 /* WidgetFunctionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WidgetFunctionView.m; sourceTree = "<group>"; };
+		BC4CF2A128D075D400961C61 /* WidgetFunctionView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = WidgetFunctionView.xib; sourceTree = "<group>"; };
 		BC50171027FC0D5600F8BCBC /* SubjectChooseViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SubjectChooseViewController.h; sourceTree = "<group>"; };
 		BC50171127FC0D5600F8BCBC /* SubjectChooseViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SubjectChooseViewController.m; sourceTree = "<group>"; };
 		BC50171327FC0D8300F8BCBC /* SubjectChooseBodyView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SubjectChooseBodyView.h; sourceTree = "<group>"; };
@@ -2781,6 +2804,7 @@
 		275FA1F027E7356A00CFEA2E /* Module */ = {
 			isa = PBXGroup;
 			children = (
+				BC4CF28828D058E600961C61 /* Widget */,
 				BC71D1342887CD470010F14B /* AnimationLaunch */,
 				BC8A4545283DC33400094BBB /* CloudEngine */,
 				BCB6357327F6D2AB00ACFDCF /* Classroom */,
@@ -4408,6 +4432,51 @@
 			path = QualityMusic;
 			sourceTree = "<group>";
 		};
+		BC4CF28828D058E600961C61 /* Widget */ = {
+			isa = PBXGroup;
+			children = (
+				BC4CF28928D058FA00961C61 /* Controller */,
+				BC4CF28A28D058FB00961C61 /* Model */,
+				BC4CF28B28D058FB00961C61 /* View */,
+			);
+			path = Widget;
+			sourceTree = "<group>";
+		};
+		BC4CF28928D058FA00961C61 /* Controller */ = {
+			isa = PBXGroup;
+			children = (
+				BC4CF28C28D072C000961C61 /* WidgetViewController.h */,
+				BC4CF28D28D072C000961C61 /* WidgetViewController.m */,
+			);
+			path = Controller;
+			sourceTree = "<group>";
+		};
+		BC4CF28A28D058FB00961C61 /* Model */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			path = Model;
+			sourceTree = "<group>";
+		};
+		BC4CF28B28D058FB00961C61 /* View */ = {
+			isa = PBXGroup;
+			children = (
+				BC4CF28F28D072EF00961C61 /* WidgetNavView.h */,
+				BC4CF29028D072EF00961C61 /* WidgetNavView.m */,
+				BC4CF29228D072F600961C61 /* WidgetNavView.xib */,
+				BC4CF29428D074DC00961C61 /* WidgetDotView.h */,
+				BC4CF29528D074DC00961C61 /* WidgetDotView.m */,
+				BC4CF29728D074E700961C61 /* WidgetDotView.xib */,
+				BC4CF29928D0757800961C61 /* WidgetSpeedView.h */,
+				BC4CF29A28D0757800961C61 /* WidgetSpeedView.m */,
+				BC4CF29C28D0758700961C61 /* WidgetSpeedView.xib */,
+				BC4CF29E28D075CC00961C61 /* WidgetFunctionView.h */,
+				BC4CF29F28D075CC00961C61 /* WidgetFunctionView.m */,
+				BC4CF2A128D075D400961C61 /* WidgetFunctionView.xib */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
 		BC60E3C3287D552800B05441 /* DeleteAccount */ = {
 			isa = PBXGroup;
 			children = (
@@ -6031,6 +6100,7 @@
 				BCC583CB28A9EC6400BAB4CF /* cloud_animation_7.png in Resources */,
 				BC71D1052881A2420010F14B /* TencentOpenApi_IOS_Bundle.bundle in Resources */,
 				BC802DBF28BC8E350079E350 /* HomeHotLiveCourseView.xib in Resources */,
+				BC4CF29828D074E700961C61 /* WidgetDotView.xib in Resources */,
 				BC71D15D2887F9DB0010F14B /* launchAni.json in Resources */,
 				275E8AB827E18F8B00DD3F6E /* LaunchScreen.storyboard in Resources */,
 				275FA1EF27E7351900CFEA2E /* KSUpdateAlert.xib in Resources */,
@@ -6091,6 +6161,7 @@
 				BC11928C280FB44300A716F7 /* HomeworkVideoView.xib in Resources */,
 				BCFDA64D28BCA2000022B497 /* live_animation_1.png in Resources */,
 				BCD457A2286313D70010B493 /* NotiferNavView.xib in Resources */,
+				BC4CF29328D072F600961C61 /* WidgetNavView.xib in Resources */,
 				275E8AB527E18F8B00DD3F6E /* Assets.xcassets in Resources */,
 				BCFDA65028BCA2000022B497 /* live_animation_3.png in Resources */,
 				BC71D252288804CD0010F14B /* img_29.png in Resources */,
@@ -6193,6 +6264,7 @@
 				BC71D26D288804CD0010F14B /* img_18.png in Resources */,
 				BCB6348127F6D29600ACFDCF /* LiveSeatApplyCell.xib in Resources */,
 				BC8A45A4283DC33400094BBB /* KSCloudSettingView.xib in Resources */,
+				BC4CF2A228D075D400961C61 /* WidgetFunctionView.xib in Resources */,
 				2723B62D27F157D500E0B90B /* GroupApplyMemberCell.xib in Resources */,
 				BCB6347427F6D29600ACFDCF /* BaseEmoji.plist in Resources */,
 				BCB9091928530EA500F5FF69 /* KSShopCardView.xib in Resources */,
@@ -6253,6 +6325,7 @@
 				BCC583BD28A9EC6400BAB4CF /* cloud_animation_25.png in Resources */,
 				BCC583BC28A9EC6400BAB4CF /* cloud_animation_19.png in Resources */,
 				BC8A459F283DC33400094BBB /* SettingPageView.xib in Resources */,
+				BC4CF29D28D0758700961C61 /* WidgetSpeedView.xib in Resources */,
 				BC71D262288804CD0010F14B /* img_54.png in Resources */,
 				BC8C2C5A2823F57100FBA5D5 /* areainfo.json in Resources */,
 				BCFDA64E28BCA2000022B497 /* musicRoom_animation_3.png in Resources */,
@@ -6572,6 +6645,7 @@
 				2723B62C27F157D500E0B90B /* ApplyBottomView.m in Sources */,
 				BC8A4595283DC33400094BBB /* GCDTimer.m in Sources */,
 				BCB6356127F6D2A300ACFDCF /* SongDownloadCallbackMessage.m in Sources */,
+				BC4CF29128D072EF00961C61 /* WidgetNavView.m in Sources */,
 				277935BA27E324A90010E277 /* FSCalendarWeekdayView.m in Sources */,
 				BCB6354427F6D2A300ACFDCF /* RecentSharedView.m in Sources */,
 				2723B66C27F15CFC00E0B90B /* SettingBodyView.m in Sources */,
@@ -6633,6 +6707,7 @@
 				27F9032927E87C2E00C08A19 /* NetworkingCheckController.m in Sources */,
 				BCFE53EC2812897600AD6786 /* HomeLiveCouseCell.m in Sources */,
 				277935A527E324A80010E277 /* MSSBrowseLoadingImageView.m in Sources */,
+				BC4CF29628D074DC00961C61 /* WidgetDotView.m in Sources */,
 				2779353E27E324A60010E277 /* UIDevice+TFDevice.m in Sources */,
 				2723B5C027F157B100E0B90B /* ChatAddressHeaderView.m in Sources */,
 				2723B68127F15D3D00E0B90B /* ModifyNameViewController.m in Sources */,
@@ -6678,6 +6753,7 @@
 				2779359A27E324A80010E277 /* TZPhotoPreviewController.m in Sources */,
 				2779355E27E324A70010E277 /* KSAudioRecordFileManager.m in Sources */,
 				2779357A27E324A70010E277 /* PIckView.m in Sources */,
+				BC4CF29B28D0757800961C61 /* WidgetSpeedView.m in Sources */,
 				BC119234280ED97C00A716F7 /* CourseForLiveCell.m in Sources */,
 				BCB6346027F6D29600ACFDCF /* KSLiveChatroomKickOut.m in Sources */,
 				2779354127E324A60010E277 /* UIView+ShowProgress.m in Sources */,
@@ -6819,6 +6895,7 @@
 				277935D327E324A90010E277 /* ALCalendarPicker.m in Sources */,
 				BC542E5828409EC900633781 /* InstrumentChooseCell.m in Sources */,
 				BCB6359427F6D2AB00ACFDCF /* NewClassRoomViewController.m in Sources */,
+				BC4CF2A028D075CC00961C61 /* WidgetFunctionView.m in Sources */,
 				BCFDA62E28BC99410022B497 /* HomeBannerCell.m in Sources */,
 				BCB6356027F6D2A300ACFDCF /* WhiteboardMessage.m in Sources */,
 				2779354F27E324A70010E277 /* VoLRUManager.m in Sources */,
@@ -6896,6 +6973,7 @@
 				2779354B27E324A60010E277 /* KSVideoEditor.m in Sources */,
 				277935A327E324A80010E277 /* TZGifPhotoPreviewController.m in Sources */,
 				277935A127E324A80010E277 /* TZImagePickerController.m in Sources */,
+				BC4CF28E28D072C000961C61 /* WidgetViewController.m in Sources */,
 				BCB6353627F6D2A300ACFDCF /* TimeStampCell.m in Sources */,
 				BCB6354D27F6D2A300ACFDCF /* EmptyView.m in Sources */,
 				2723B63327F157D500E0B90B /* ChatComplainBodyView.m in Sources */,

BIN
KulexiuForStudent/KulexiuForStudent.xcworkspace/xcuserdata/wangzhi.xcuserdatad/UserInterfaceState.xcuserstate


+ 0 - 16
KulexiuForStudent/KulexiuForStudent.xcworkspace/xcuserdata/wangzhi.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist

@@ -16,21 +16,5 @@
             stopOnStyle = "1">
          </BreakpointContent>
       </BreakpointProxy>
-      <BreakpointProxy
-         BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
-         <BreakpointContent
-            uuid = "6EA5B8EB-FEC6-4AB3-82E0-842B306278EB"
-            shouldBeEnabled = "No"
-            ignoreCount = "0"
-            continueAfterRunningActions = "No"
-            filePath = "KulexiuForStudent/Module/Home/Controller/HomeViewController.m"
-            startingColumnNumber = "9223372036854775807"
-            endingColumnNumber = "9223372036854775807"
-            startingLineNumber = "861"
-            endingLineNumber = "861"
-            landmarkName = "-refreshViewLocation"
-            landmarkType = "7">
-         </BreakpointContent>
-      </BreakpointProxy>
    </Breakpoints>
 </Bucket>

+ 6 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/eighth_node.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "eighth_node@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "eighth_node@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/eighth_node.imageset/eighth_node@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/eighth_node.imageset/eighth_node@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/half_node.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "half_node@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "half_node@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/half_node.imageset/half_node@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/half_node.imageset/half_node@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/metronome_bg.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "metronome_bg@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "metronome_bg@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/metronome_bg.imageset/metronome_bg@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/metronome_bg.imageset/metronome_bg@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/quarter_node.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "quarter_node@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "quarter_node@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/quarter_node.imageset/quarter_node@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/quarter_node.imageset/quarter_node@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/sixteenth_node.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "sixteenth_node@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "sixteenth_node@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/sixteenth_node.imageset/sixteenth_node@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/sixteenth_node.imageset/sixteenth_node@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/slider_image.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "slider_image@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "slider_image@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/slider_image.imageset/slider_image@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/slider_image.imageset/slider_image@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_add.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "speed_add@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "speed_add@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_add.imageset/speed_add@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_add.imageset/speed_add@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_background.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "speed_background@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "speed_background@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_background.imageset/speed_background@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_background.imageset/speed_background@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_button_bg.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "speed_button_bg@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "speed_button_bg@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_button_bg.imageset/speed_button_bg@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_button_bg.imageset/speed_button_bg@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_dot.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "speed_dot@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "speed_dot@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_dot.imageset/speed_dot@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_dot.imageset/speed_dot@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_minus.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "speed_minus@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "speed_minus@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_minus.imageset/speed_minus@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/speed_minus.imageset/speed_minus@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/volume_down.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "volume_down@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "volume_down@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/volume_down.imageset/volume_down@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/volume_down.imageset/volume_down@3x.png


+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/volume_up.imageset/Contents.json

@@ -0,0 +1,22 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "volume_up@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "volume_up@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/volume_up.imageset/volume_up@2x.png


BIN
KulexiuForStudent/KulexiuForStudent/Assets.xcassets/Home/metronome/volume_up.imageset/volume_up@3x.png


+ 11 - 3
KulexiuForStudent/KulexiuForStudent/Module/Home/Controller/HomeViewController.m

@@ -67,6 +67,7 @@
 #import "TeacherStyleModel.h"
 #import "HomeTeacherLiveModel.h"
 
+#import "WidgetViewController.h"
 
 #define BUTTONWIDTH (65)
 #define BUTTONHEIGHT (80)
@@ -947,9 +948,16 @@
     if ([self checkIsLoginToLoginView:YES]) {
         HomeMessageModel *model = self.buttonArray[index];
         if (![NSString isEmptyString:model.linkUrl]) {
-            KSBaseWKWebViewController *webCtrl = [[KSBaseWKWebViewController alloc] init];
-            webCtrl.url = model.linkUrl;
-            [self.navigationController pushViewController:webCtrl animated:YES];
+            if ([model.linkUrl isEqualToString:@"native-metronome"]) {
+                WidgetViewController *ctrl = [[WidgetViewController alloc] init];
+                [self.navigationController pushViewController:ctrl animated:YES];
+            }
+            else {
+                KSBaseWKWebViewController *webCtrl = [[KSBaseWKWebViewController alloc] init];
+                webCtrl.url = model.linkUrl;
+                [self.navigationController pushViewController:webCtrl animated:YES];
+            }
+            
         }
     }
 }

+ 16 - 0
KulexiuForStudent/KulexiuForStudent/Module/Widget/Controller/WidgetViewController.h

@@ -0,0 +1,16 @@
+//
+//  WidgetViewController.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/9/13.
+//
+
+#import "KSBaseViewController.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface WidgetViewController : KSBaseViewController
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 157 - 0
KulexiuForStudent/KulexiuForStudent/Module/Widget/Controller/WidgetViewController.m

@@ -0,0 +1,157 @@
+//
+//  WidgetViewController.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/9/13.
+//
+
+#import "WidgetViewController.h"
+#import "WidgetNavView.h"
+#import "WidgetDotView.h"
+#import "WidgetSpeedView.h"
+#import "WidgetFunctionView.h"
+
+@interface WidgetViewController ()<MetronomeControlViewDelegate,MetronomeFunctionDelegate>
+
+@property (nonatomic, strong) WidgetNavView *navView;
+
+@property (nonatomic, strong) WidgetDotView *dotView;
+
+@property (nonatomic, strong) WidgetSpeedView *speedView;
+
+@property (nonatomic, strong) WidgetFunctionView *functionView;
+
+@property (nonatomic, assign) int speed;
+
+
+@end
+
+@implementation WidgetViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    // Do any additional setup after loading the view.
+    self.ks_prefersNavigationBarHidden = YES;
+    [self configUI];
+    self.speed = 90;
+    [self updateSpeedUI];
+}
+
+
+- (void)configUI {
+    [self.scrollView removeFromSuperview];
+//    self.view.backgroundColor = [UIColor whiteColor];
+    
+    CAGradientLayer *layer = [self createGradientLayerFromColor:HexRGB(0x2DC7AA) startPoint:CGPointMake(0.5, 0) endColor:HexRGB(0xA0A0A0) endPoint:CGPointMake(0.5, 1) bounds:CGRectMake(0, 0, KPortraitWidth, KPortraitHeight)];
+//    layer.masksToBounds = YES;
+//    [self.view.layer addSublayer:layer];
+    
+    [self.view addSubview:self.navView];
+    [self.navView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.top.mas_equalTo(self.view);
+        make.height.mas_equalTo(kNaviBarHeight);
+    }];
+    
+    [self.view addSubview:self.dotView];
+    [self.dotView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.mas_equalTo(self.view);
+        make.top.mas_equalTo(self.navView.mas_bottom);
+        make.height.mas_equalTo(44);
+    }];
+    
+    [self.view addSubview:self.speedView];
+    [self.speedView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.mas_equalTo(self.view);
+        make.top.mas_equalTo(self.dotView.mas_bottom);
+        make.height.mas_equalTo(300);
+    }];
+    
+    [self.view addSubview:self.functionView];
+    [self.functionView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.left.right.mas_equalTo(self.view);
+        make.top.mas_equalTo(self.speedView.mas_bottom);
+        make.height.mas_equalTo(115);
+    }];
+}
+
+
+#pragma mark --- delegate
+- (void)clickChangeBeat {
+    // 显示节拍选择弹窗
+    
+}
+
+- (void)clickChangeSpeed:(int)speed {
+    self.speed = speed;
+    // 更新UI
+    [self updateSpeedUI];
+}
+
+- (void)changeSpeedWithIsAdd:(BOOL)isAdd speed:(int)speed {
+    if (isAdd) {
+        self.speed = MIN(self.speed +speed, 240);
+    }else{
+        self.speed = MAX(self.speed -speed, 50);
+    }
+    
+    // 更新UI
+    [self updateSpeedUI];
+}
+
+- (void)updateSpeedUI {
+    self.speedView.speed = self.speed;
+    self.functionView.speed = self.speed;
+}
+
+#pragma mark --- lazying
+- (WidgetNavView *)navView {
+    if (!_navView) {
+        _navView = [WidgetNavView shareInstance];
+    }
+    return _navView;
+}
+
+- (WidgetDotView *)dotView {
+    if (!_dotView) {
+        _dotView = [WidgetDotView shareInstance];
+    }
+    return _dotView;
+}
+
+- (WidgetSpeedView *)speedView {
+    if (!_speedView) {
+        _speedView = [WidgetSpeedView shareInstance];
+        _speedView.delegate = self;
+    }
+    return _speedView;
+}
+
+- (WidgetFunctionView *)functionView {
+    if (!_functionView) {
+        _functionView = [WidgetFunctionView shareInstance];
+        _functionView.delegate = self;
+    }
+    return _functionView;
+}
+
+
+- (CAGradientLayer *)createGradientLayerFromColor:(UIColor *)fromColor startPoint:(CGPoint)startPoint endColor:(UIColor *)endColor endPoint:(CGPoint)endPoint bounds:(CGRect)bounds {
+    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
+    gradientLayer.colors = @[(__bridge id)fromColor.CGColor, (__bridge id)endColor.CGColor];
+    gradientLayer.startPoint = startPoint;
+    gradientLayer.endPoint = endPoint;
+    gradientLayer.frame = bounds;
+    gradientLayer.locations = @[@(0),@(1.0f)];
+    return gradientLayer;
+}
+/*
+#pragma mark - Navigation
+
+// In a storyboard-based application, you will often want to do a little preparation before navigation
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    // Get the new view controller using [segue destinationViewController].
+    // Pass the selected object to the new view controller.
+}
+*/
+
+@end

+ 32 - 0
KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetDotView.h

@@ -0,0 +1,32 @@
+//
+//  WidgetDotView.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/9/13.
+//
+
+#import <UIKit/UIKit.h>
+
+// 节拍器节拍选择
+typedef NS_ENUM(NSInteger, KSMetronomeType) {
+    KSMetronomeType1V4 =0,     // 1/4
+    KSMetronomeType2V4,        // 2/4
+    KSMetronomeType3V4,        // 3/4
+    KSMetronomeType4V4,        // 4/4
+    KSMetronomeType6V8         // 6/8
+};
+
+
+
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface WidgetDotView : UIView
+
++ (instancetype)shareInstance;
+
+
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 29 - 0
KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetDotView.m

@@ -0,0 +1,29 @@
+//
+//  WidgetDotView.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/9/13.
+//
+
+#import "WidgetDotView.h"
+
+@interface WidgetDotView ()
+
+
+
+@end
+
+@implementation WidgetDotView
++ (instancetype)shareInstance {
+    WidgetDotView *view = [[[NSBundle mainBundle] loadNibNamed:@"WidgetDotView" owner:nil options:nil] firstObject];
+    return view;
+}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 22 - 0
KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetDotView.xib

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina6_1" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="WidgetDotView">
+            <rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <point key="canvasLocation" x="131.8840579710145" y="-3.0133928571428572"/>
+        </view>
+    </objects>
+</document>

+ 35 - 0
KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetFunctionView.h

@@ -0,0 +1,35 @@
+//
+//  WidgetFunctionView.h
+//  ;ForStudent
+//
+//  Created by 王智 on 2022/9/13.
+//
+
+#import <UIKit/UIKit.h>
+
+@protocol MetronomeFunctionDelegate <NSObject>
+
+/** 加减号改变频率 */
+- (void)clickChangeSpeed:(int)speed;
+
+- (void)clickChangeBeat;
+
+@end
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface WidgetFunctionView : UIView
+
+@property (nonatomic, assign) int speed;
+
+@property (weak, nonatomic) IBOutlet UIButton *signatureButton;
+
+@property (nonatomic, assign) CGFloat volumeRate;
+
++ (instancetype)shareInstance;
+/** 代理 */
+@property (nonatomic, weak) id <MetronomeFunctionDelegate> delegate;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 76 - 0
KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetFunctionView.m

@@ -0,0 +1,76 @@
+//
+//  WidgetFunctionView.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/9/13.
+//
+
+#import "WidgetFunctionView.h"
+
+@interface WidgetFunctionView ()
+
+@property (weak, nonatomic) IBOutlet UIButton *speedMinusButton;
+
+@property (weak, nonatomic) IBOutlet UIButton *speedAddButton;
+
+
+@property (weak, nonatomic) IBOutlet UISlider *volumeSlider;
+
+
+@end
+
+@implementation WidgetFunctionView
+
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    [self.volumeSlider setThumbImage:[UIImage imageNamed:@"slider_image"] forState:UIControlStateNormal];
+    [self.volumeSlider setThumbImage:[UIImage imageNamed:@"slider_image"] forState:UIControlStateFocused];
+}
+
++ (instancetype)shareInstance {
+    WidgetFunctionView *view = [[[NSBundle mainBundle] loadNibNamed:@"WidgetFunctionView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (IBAction)changeBeatAction:(id)sender {
+    if (self.delegate && [self.delegate respondsToSelector:@selector(clickChangeBeat)]) {
+        [self.delegate clickChangeBeat];
+    }
+}
+
+
+- (IBAction)onReduceButtonClick:(id)sender {
+    if (self.speed > 50) {
+        self.speed --;
+    }else{
+        self.speed = 50;
+    }
+    [self updateSpeed];
+}
+
+
+- (IBAction)onAddButtonClick:(id)sender {
+    if (self.speed < 240) {
+        self.speed ++;
+    }else{
+        self.speed = 240;
+    }
+    [self updateSpeed];
+}
+
+- (void)updateSpeed {
+    
+    if (self.delegate && [self.delegate respondsToSelector:@selector(clickChangeSpeed:)]) {
+        [self.delegate clickChangeSpeed:self.speed];
+    }
+}
+
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 95 - 0
KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetFunctionView.xib

@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina6_1" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="WidgetFunctionView">
+            <rect key="frame" x="0.0" y="0.0" width="414" height="115"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Vgr-v5-aHg">
+                    <rect key="frame" x="69.5" y="0.0" width="66" height="74"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="74" id="Lsq-An-xLd"/>
+                        <constraint firstAttribute="width" constant="66" id="ZRc-yd-VZu"/>
+                    </constraints>
+                    <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                    <state key="normal" image="speed_minus" backgroundImage="speed_button_bg"/>
+                    <connections>
+                        <action selector="onReduceButtonClick:" destination="iN0-l3-epB" eventType="touchUpInside" id="DTz-pP-VFz"/>
+                    </connections>
+                </button>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="8S7-tR-fpt">
+                    <rect key="frame" x="140.5" y="0.0" width="133" height="74"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="74" id="G2q-Lb-C9F"/>
+                        <constraint firstAttribute="width" constant="133" id="GvT-n8-eSh"/>
+                    </constraints>
+                    <fontDescription key="fontDescription" type="system" weight="medium" pointSize="16"/>
+                    <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                    <state key="normal" title="6/4" backgroundImage="metronome_bg">
+                        <color key="titleColor" red="0.10196078431372549" green="0.10196078431372549" blue="0.10196078431372549" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    </state>
+                    <connections>
+                        <action selector="changeBeatAction:" destination="iN0-l3-epB" eventType="touchUpInside" id="iQs-c2-I9L"/>
+                    </connections>
+                </button>
+                <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" adjustsImageWhenHighlighted="NO" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="xxw-kt-6aa">
+                    <rect key="frame" x="278.5" y="0.0" width="66" height="74"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="74" id="Sxb-x5-Zj0"/>
+                        <constraint firstAttribute="width" constant="66" id="TLd-GR-oiI"/>
+                    </constraints>
+                    <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                    <state key="normal" image="speed_add" backgroundImage="speed_button_bg"/>
+                    <connections>
+                        <action selector="onAddButtonClick:" destination="iN0-l3-epB" eventType="touchUpInside" id="dyG-1d-skC"/>
+                    </connections>
+                </button>
+                <slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" minimumValueImage="volume_down" maximumValueImage="volume_up" translatesAutoresizingMaskIntoConstraints="NO" id="n9V-6j-N8n">
+                    <rect key="frame" x="67.5" y="79" width="279" height="31"/>
+                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <color key="minimumTrackTintColor" red="0.1764705882352941" green="0.7803921568627451" blue="0.66666666666666663" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    <color key="maximumTrackTintColor" red="0.87450980392156863" green="0.87450980392156863" blue="0.87450980392156863" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    <color key="thumbTintColor" red="0.1764705882" green="0.78039215689999997" blue="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                </slider>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstItem="8S7-tR-fpt" firstAttribute="leading" secondItem="Vgr-v5-aHg" secondAttribute="trailing" constant="5" id="8Sy-9T-tOM"/>
+                <constraint firstItem="xxw-kt-6aa" firstAttribute="leading" secondItem="8S7-tR-fpt" secondAttribute="trailing" constant="5" id="Dro-Aa-AjB"/>
+                <constraint firstItem="8S7-tR-fpt" firstAttribute="centerY" secondItem="Vgr-v5-aHg" secondAttribute="centerY" id="KLA-a2-frd"/>
+                <constraint firstItem="xxw-kt-6aa" firstAttribute="centerY" secondItem="Vgr-v5-aHg" secondAttribute="centerY" id="Rbr-as-gF3"/>
+                <constraint firstItem="n9V-6j-N8n" firstAttribute="leading" secondItem="Vgr-v5-aHg" secondAttribute="leading" id="VYP-Bw-aUN"/>
+                <constraint firstItem="8S7-tR-fpt" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" id="dZt-n0-mcE"/>
+                <constraint firstItem="8S7-tR-fpt" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="fwC-U3-xfC"/>
+                <constraint firstItem="n9V-6j-N8n" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="wUi-jX-bDm"/>
+                <constraint firstItem="n9V-6j-N8n" firstAttribute="top" secondItem="Vgr-v5-aHg" secondAttribute="bottom" constant="5" id="xV7-rF-gtp"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="signatureButton" destination="8S7-tR-fpt" id="Lic-ec-FEc"/>
+                <outlet property="speedAddButton" destination="xxw-kt-6aa" id="WQE-Gf-zIz"/>
+                <outlet property="speedMinusButton" destination="Vgr-v5-aHg" id="zux-FN-7kX"/>
+                <outlet property="volumeSlider" destination="n9V-6j-N8n" id="c0q-59-r5I"/>
+            </connections>
+            <point key="canvasLocation" x="131.8840579710145" y="6.3616071428571423"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="metronome_bg" width="133" height="74"/>
+        <image name="speed_add" width="14" height="14"/>
+        <image name="speed_button_bg" width="66" height="74"/>
+        <image name="speed_minus" width="14" height="14"/>
+        <image name="volume_down" width="12" height="12"/>
+        <image name="volume_up" width="12" height="12"/>
+    </resources>
+</document>

+ 18 - 0
KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetNavView.h

@@ -0,0 +1,18 @@
+//
+//  WidgetNavView.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/9/13.
+//
+
+#import <UIKit/UIKit.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface WidgetNavView : UIView
+
++ (instancetype)shareInstance;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 26 - 0
KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetNavView.m

@@ -0,0 +1,26 @@
+//
+//  WidgetNavView.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/9/13.
+//
+
+#import "WidgetNavView.h"
+
+@implementation WidgetNavView
+
+
++ (instancetype)shareInstance {
+    WidgetNavView *view = [[[NSBundle mainBundle] loadNibNamed:@"WidgetNavView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 64 - 0
KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetNavView.xib

@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+    <device id="retina6_1" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="WidgetNavView">
+            <rect key="frame" x="0.0" y="0.0" width="414" height="92"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="SUk-Ag-K6M">
+                    <rect key="frame" x="0.0" y="48" width="414" height="44"/>
+                    <subviews>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="back_black" translatesAutoresizingMaskIntoConstraints="NO" id="DDF-Ml-1qT">
+                            <rect key="frame" x="14" y="12" width="12" height="20"/>
+                        </imageView>
+                        <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="yeM-eb-aeH">
+                            <rect key="frame" x="0.0" y="0.0" width="44" height="44"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="44" id="j2f-oU-zP6"/>
+                            </constraints>
+                            <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/>
+                        </button>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="节拍器" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="yk0-dS-WZy">
+                            <rect key="frame" x="179" y="11" width="56" height="22"/>
+                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="18"/>
+                            <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="calibratedRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                    </subviews>
+                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <constraints>
+                        <constraint firstItem="yk0-dS-WZy" firstAttribute="centerX" secondItem="SUk-Ag-K6M" secondAttribute="centerX" id="0i1-EH-ueL"/>
+                        <constraint firstItem="DDF-Ml-1qT" firstAttribute="centerY" secondItem="SUk-Ag-K6M" secondAttribute="centerY" id="9S9-KI-omf"/>
+                        <constraint firstItem="yeM-eb-aeH" firstAttribute="leading" secondItem="SUk-Ag-K6M" secondAttribute="leading" id="MBb-cm-NxT"/>
+                        <constraint firstItem="yk0-dS-WZy" firstAttribute="centerY" secondItem="SUk-Ag-K6M" secondAttribute="centerY" id="MK3-Qc-twi"/>
+                        <constraint firstItem="DDF-Ml-1qT" firstAttribute="leading" secondItem="SUk-Ag-K6M" secondAttribute="leading" constant="14" id="U6P-oC-62I"/>
+                        <constraint firstAttribute="bottom" secondItem="yeM-eb-aeH" secondAttribute="bottom" id="VHC-dZ-gcV"/>
+                        <constraint firstAttribute="height" constant="44" id="de5-7W-Mcn"/>
+                        <constraint firstItem="yeM-eb-aeH" firstAttribute="top" secondItem="SUk-Ag-K6M" secondAttribute="top" id="gln-eQ-4h0"/>
+                    </constraints>
+                </view>
+            </subviews>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstItem="SUk-Ag-K6M" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="4il-Fu-RKX"/>
+                <constraint firstAttribute="trailing" secondItem="SUk-Ag-K6M" secondAttribute="trailing" id="Dcf-Gp-3NN"/>
+                <constraint firstAttribute="bottom" secondItem="SUk-Ag-K6M" secondAttribute="bottom" id="piy-Th-6Ak"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <point key="canvasLocation" x="131.8840579710145" y="-167.41071428571428"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="back_black" width="12" height="20"/>
+    </resources>
+</document>

+ 41 - 0
KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetSpeedView.h

@@ -0,0 +1,41 @@
+//
+//  WidgetSpeedView.h
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/9/13.
+//
+
+#import <UIKit/UIKit.h>
+
+// 代理
+@protocol MetronomeControlViewDelegate <NSObject>
+
+/**
+ 改变频率
+
+ @param isAdd 增加频率还是减小频率
+ @param speed 增加或减小的值
+ */
+- (void)changeSpeedWithIsAdd:(BOOL)isAdd speed:(int)speed;
+
+
+@end
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface WidgetSpeedView : UIView
+
++ (instancetype)shareInstance;
+
+/** 节拍类型 */
+//@property (nonatomic, assign) KSMetronomeType currentType;
+
+/** 代理 */
+@property (nonatomic, weak) id <MetronomeControlViewDelegate> delegate;
+
+/** 播放速率,范围50~240 */
+@property (nonatomic, assign) int speed;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 141 - 0
KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetSpeedView.m

@@ -0,0 +1,141 @@
+//
+//  WidgetSpeedView.m
+//  KulexiuForStudent
+//
+//  Created by 王智 on 2022/9/13.
+//
+
+#import "WidgetSpeedView.h"
+
+@interface WidgetSpeedView ()
+{
+    CGFloat _lastPointAngle;//上一个点相对于x轴角度
+    CGPoint _centerPoint;
+}
+
+@property (weak, nonatomic) IBOutlet UIImageView *nodeImage;
+
+@property (weak, nonatomic) IBOutlet UILabel *speedLabel;
+
+@property (weak, nonatomic) IBOutlet UIView *bgView;
+
+/** 控制频率View */
+@property (nonatomic, strong) UIImageView *controlSpeedView;
+
+@end
+
+@implementation WidgetSpeedView
+- (void)awakeFromNib {
+    [super awakeFromNib];
+    [self createUI];
+}
+
++ (instancetype)shareInstance {
+    WidgetSpeedView *view = [[[NSBundle mainBundle] loadNibNamed:@"WidgetSpeedView" owner:nil options:nil] firstObject];
+    return view;
+}
+
+- (void)createUI {
+    _centerPoint = CGPointMake(300 / 2, kScreenWidth / 2);//中心点
+    
+    self.controlSpeedView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"speed_dot"]];
+    [self.bgView addSubview:self.controlSpeedView];
+    [self.controlSpeedView mas_makeConstraints:^(MASConstraintMaker *make) {
+        make.top.right.bottom.left.mas_equalTo(self.bgView);
+    }];
+    
+}
+
+- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
+    
+    UITouch *touch = [touches anyObject];
+    CGPoint point = [touch locationInView:self];
+    //计算上一个点相对于x轴的角度
+    CGFloat lastPointRadius = sqrt(pow(point.y - _centerPoint.y, 2) + pow(point.x - _centerPoint.x, 2));
+    if (lastPointRadius == 0) {
+        return;
+    }
+    _lastPointAngle = acos((point.x - _centerPoint.x) / lastPointRadius);
+    if (point.y > _centerPoint.y) {
+        _lastPointAngle = 2 * M_PI - _lastPointAngle;
+    }
+}
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
+
+    UITouch *touch = [touches anyObject];
+    CGPoint currentPoint = [touch locationInView:self];
+    
+    //1.计算当前点相对于x轴的角度
+    CGFloat currentPointRadius = sqrt(pow(currentPoint.y - _centerPoint.y, 2) + pow(currentPoint.x - _centerPoint.x, 2));
+    if (currentPointRadius == 0) {//当点在中心点时,被除数不能为0
+        return;
+    }
+    CGFloat curentPointAngle = acos((currentPoint.x - _centerPoint.x) / currentPointRadius);
+    if (currentPoint.y > _centerPoint.y) {
+        curentPointAngle = 2 * M_PI - curentPointAngle;
+    }
+    //2.变化的角度
+    CGFloat angle = _lastPointAngle - curentPointAngle;
+    // 小点点的位置
+    self.controlSpeedView.transform = CGAffineTransformRotate(self.controlSpeedView.transform, angle);
+    _lastPointAngle = curentPointAngle;
+    if (angle > 0) {
+        if (self.delegate && [self.delegate respondsToSelector:@selector(changeSpeedWithIsAdd:speed:)]) {
+
+            [self.delegate changeSpeedWithIsAdd:YES speed:MIN(1, MAX(angle *2, 1))];
+        }
+    }else {
+        if (self.delegate && [self.delegate respondsToSelector:@selector(changeSpeedWithIsAdd:speed:)]) {
+            [self.delegate changeSpeedWithIsAdd:NO speed:MIN(1, MAX(angle *2, 1))];
+        }
+    }
+}
+
+- (void)setSpeed:(int)speed {
+    _speed = speed;
+    self.speedLabel.text = [NSString stringWithFormat:@"%d", speed];
+}
+
+
+//- (void)setCurrentType:(KSMetronomeType)currentType {
+//    _currentType = currentType;
+//    switch (currentType) {
+//        case KSMetronomeType1V4:
+//        {
+//            self.beatLabel.text = @"1 | 4";
+//        }
+//            break;
+//        case KSMetronomeType2V4:
+//        {
+//            self.beatLabel.text = @"2 | 4";
+//        }
+//            break;
+//        case KSMetronomeType3V4:
+//        {
+//            self.beatLabel.text = @"3 | 4";
+//        }
+//            break;
+//        case KSMetronomeType4V4:
+//        {
+//            self.beatLabel.text = @"4 | 4";
+//        }
+//            break;
+//        case KSMetronomeType6V8:
+//        {
+//            self.beatLabel.text = @"6 | 8";
+//        }
+//            break;
+//        default:
+//            break;
+//    }
+//}
+/*
+// Only override drawRect: if you perform custom drawing.
+// An empty implementation adversely affects performance during animation.
+- (void)drawRect:(CGRect)rect {
+    // Drawing code
+}
+*/
+
+@end

+ 81 - 0
KulexiuForStudent/KulexiuForStudent/Module/Widget/View/WidgetSpeedView.xib

@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina6_1" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
+        <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"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="WidgetSpeedView">
+            <rect key="frame" x="0.0" y="0.0" width="373" height="300"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="xgb-CP-q8k">
+                    <rect key="frame" x="36.5" y="0.0" width="300" height="300"/>
+                    <subviews>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="speed_background" translatesAutoresizingMaskIntoConstraints="NO" id="M3y-XL-rfN">
+                            <rect key="frame" x="0.0" y="0.0" width="300" height="300"/>
+                        </imageView>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="136" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="e9W-bt-jeB">
+                            <rect key="frame" x="115.5" y="126" width="69" height="48"/>
+                            <fontDescription key="fontDescription" type="system" weight="medium" pointSize="40"/>
+                            <nil key="textColor"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="quarter_node" translatesAutoresizingMaskIntoConstraints="NO" id="7gk-Eb-b8E">
+                            <rect key="frame" x="108" y="100" width="20" height="20"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="20" id="7Ln-ex-jSv"/>
+                                <constraint firstAttribute="width" constant="20" id="jtJ-h3-wy8"/>
+                            </constraints>
+                        </imageView>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="=" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tZK-hU-4GH">
+                            <rect key="frame" x="128" y="101.5" width="9" height="17"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                            <color key="textColor" red="0.20000000000000001" green="0.20000000000000001" blue="0.20000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                    </subviews>
+                    <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <constraints>
+                        <constraint firstItem="7gk-Eb-b8E" firstAttribute="leading" secondItem="xgb-CP-q8k" secondAttribute="leading" constant="108" id="9Z5-8o-0mh"/>
+                        <constraint firstItem="e9W-bt-jeB" firstAttribute="centerY" secondItem="xgb-CP-q8k" secondAttribute="centerY" id="Atr-A9-US6"/>
+                        <constraint firstItem="e9W-bt-jeB" firstAttribute="centerX" secondItem="xgb-CP-q8k" secondAttribute="centerX" id="B3Z-Wx-QmF"/>
+                        <constraint firstItem="tZK-hU-4GH" firstAttribute="leading" secondItem="7gk-Eb-b8E" secondAttribute="trailing" id="B9k-F1-kxz"/>
+                        <constraint firstAttribute="trailing" secondItem="M3y-XL-rfN" secondAttribute="trailing" id="Fff-ft-9mF"/>
+                        <constraint firstItem="tZK-hU-4GH" firstAttribute="centerY" secondItem="7gk-Eb-b8E" secondAttribute="centerY" id="FrH-5b-gLZ"/>
+                        <constraint firstAttribute="bottom" secondItem="M3y-XL-rfN" secondAttribute="bottom" id="ONf-RV-cOi"/>
+                        <constraint firstAttribute="height" constant="300" id="Ort-HP-5YW"/>
+                        <constraint firstItem="M3y-XL-rfN" firstAttribute="leading" secondItem="xgb-CP-q8k" secondAttribute="leading" id="bS2-Qj-cqY"/>
+                        <constraint firstItem="7gk-Eb-b8E" firstAttribute="top" secondItem="xgb-CP-q8k" secondAttribute="top" constant="100" id="k83-31-D35"/>
+                        <constraint firstAttribute="width" constant="300" id="liP-q8-rba"/>
+                        <constraint firstItem="M3y-XL-rfN" firstAttribute="top" secondItem="xgb-CP-q8k" secondAttribute="top" id="m8Z-QB-sEg"/>
+                    </constraints>
+                </view>
+            </subviews>
+            <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
+            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+            <constraints>
+                <constraint firstItem="xgb-CP-q8k" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="2Aa-Aa-9Gq"/>
+                <constraint firstItem="xgb-CP-q8k" firstAttribute="centerX" secondItem="iN0-l3-epB" secondAttribute="centerX" id="6cd-Mf-ZSX"/>
+            </constraints>
+            <nil key="simulatedTopBarMetrics"/>
+            <nil key="simulatedBottomBarMetrics"/>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="bgView" destination="xgb-CP-q8k" id="991-9V-bEO"/>
+                <outlet property="nodeImage" destination="7gk-Eb-b8E" id="WZ2-0a-Alb"/>
+                <outlet property="speedLabel" destination="e9W-bt-jeB" id="n90-IA-ARD"/>
+            </connections>
+            <point key="canvasLocation" x="161.59420289855075" y="11.383928571428571"/>
+        </view>
+    </objects>
+    <resources>
+        <image name="quarter_node" width="20" height="20"/>
+        <image name="speed_background" width="300" height="300"/>
+    </resources>
+</document>