├── .DS_Store ├── FFModifier.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── bblv.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcshareddata │ └── xcschemes │ └── FFModifier.xcscheme ├── FFModifier ├── 001 - Text │ ├── ContentView.swift │ ├── FFCustomizeLinks.swift │ ├── FFLabel.swift │ ├── FFTextAddSpacing.swift │ ├── FFTextAlignment.swift │ ├── FFTextDataFormat.swift │ ├── FFTextField.swift │ ├── FFTextFormat.swift │ ├── FFTextMarkdown.swift │ ├── FFTextPlaceholder.swift │ ├── FFTextPrivasySensitive.swift │ └── FFTextUsersSelect.swift ├── 002 - Image │ ├── FFColorWithGETRGB.swift │ ├── FFCombinShape.swift │ ├── FFGameScene.swift │ ├── FFImage.swift │ ├── FFImageBackgrounds.swift │ ├── FFImageContainerRelativeShape.swift │ ├── FFImageDynamicColor.swift │ ├── FFImageGradients.swift │ ├── FFImagePhotosPicker.swift │ ├── FFImageRemoteUrl.swift │ ├── FFImageSFSymbols.swift │ ├── FFImageShapeTrim.swift │ ├── FFImageShapes.swift │ ├── FFImageStorkeShapes.swift │ ├── FFImageTransparency.swift │ ├── FFImageVideo.swift │ ├── FFImagefitToSpace.swift │ ├── FFImagetile.swift │ ├── FFSFAminate.swift │ ├── FFSpriteView.swift │ ├── FFVideoPlayer.swift │ ├── SwiftCustomColorWithAsset.swift │ └── Temp.swift ├── 003 - Layout │ ├── FFViewAddPaddingForSafeArea.swift │ ├── FFViewContainerSize.swift │ ├── FFViewCustomLayout.swift │ ├── FFViewDynamicallyAppearance.swift │ ├── FFViewDynamicallyAppearanceRota.swift │ ├── FFViewDynamicallyChange.swift │ ├── FFViewForEach.swift │ ├── FFViewForegroundStyle.swift │ ├── FFViewGeometryReader.swift │ ├── FFViewGestures.swift │ ├── FFViewInsertSafeArea.swift │ ├── FFViewLayoutPriority.swift │ ├── FFViewLayoutProtocol.swift │ ├── FFViewPadding.swift │ ├── FFViewSafeArea.swift │ ├── FFViewSameWidthHeight.swift │ ├── FFViewThatFIts.swift │ ├── FFViewType.swift │ └── FFViewhideSystemUI.swift ├── 004 - Stacks,girds,scrollviews │ ├── FFGirdPosition.swift │ ├── FFLayoutsSizeClasses.swift │ ├── FFLazyGridPosition.swift │ ├── FFScrollVIewContent.swift │ ├── FFScrollViewDismissKeyboard.swift │ ├── FFScrollViewFlash.swift │ ├── FFScrollViewHideIndicators.swift │ ├── FFScrollViewOverFlow.swift │ ├── FFScrollViewReader.swift │ ├── FFScrollViewScrolling.swift │ ├── FFScrollViewSnap.swift │ ├── FFScrollViewStartBottom.swift │ ├── FFScrollViewTransition.swift │ ├── FFStack3DEffects.swift │ ├── FFStackAutomaticallySwitch.swift │ ├── FFStackPrimary.swift │ ├── FFStackSpacer.swift │ ├── FFStackSpacerFixedsize.swift │ ├── FFStackSpacingAndAlignment.swift │ ├── FFStackWithLazy.swift │ ├── FFStackZ.swift │ ├── FFStackZIndex.swift │ └── FFTableColumn.swift ├── 005 - UIControls │ ├── FFButtonRepeat.swift │ ├── FFButtonsBordered.swift │ ├── FFColorPicker.swift │ ├── FFControlGroup.swift │ ├── FFCustomSubmit.swift │ ├── FFDatePickerOrRead.swift │ ├── FFDisableOverlay.swift │ ├── FFLabelHidden.swift │ ├── FFMap.swift │ ├── FFMapAnnotations.swift │ ├── FFMultiDatePicker.swift │ ├── FFPickerOrRead.swift │ ├── FFProgressView.swift │ ├── FFProressViewIndeterminate.swift │ ├── FFSafari.swift │ ├── FFSecureField.swift │ ├── FFSegmentedOrRead.swift │ ├── FFSliderOrRead.swift │ ├── FFState.swift │ ├── FFStepperOrRead.swift │ ├── FFTappableButton.swift │ ├── FFTextEditor.swift │ ├── FFTextFieldAutocorrect.swift │ ├── FFTextFieldBorder.swift │ ├── FFTextFieldDefaultFocus.swift │ ├── FFTextFieldNumber.swift │ ├── FFTextFieldPlaceholder.swift │ ├── FFTextFieldRead.swift │ ├── FFTextFieldSubmit.swift │ ├── FFTextFieldVerticalEx.swift │ ├── FFTextFieldkeyboard.swift │ └── FFToggleSwitch.swift ├── 007 - RespondingEvent │ ├── FFAppdelegate.swift │ ├── FFAsynchronousTask.swift │ ├── FFCanvasDrop.swift │ ├── FFCanvasDropDraggable.swift │ ├── FFCanvasDropImage.swift │ ├── FFCanvasDropImages.swift │ ├── FFDetectAndRespondEvent.swift │ ├── FFDeviceRotation.swift │ ├── FFFindAndReplaceText.swift │ ├── FFHapticEffects.swift │ ├── FFLaunches.swift │ ├── FFLaunchesCode.swift │ ├── FFLifeCycle.swift │ ├── FFPasteData.swift │ ├── FFScenePhase.swift │ ├── FFSystemShareSheet.swift │ └── FFToolbarKeyboard.swift ├── 008 - TapAndGestures │ ├── FFContentShape.swift │ ├── FFDisableTaps.swift │ ├── FFGestureForView.swift │ ├── FFGestureHighPriority.swift │ ├── FFGestureMangify.swift │ ├── FFGestureOnTap.swift │ ├── FFGestureReadTapOrDouble.swift │ ├── FFGestureSequenced.swift │ ├── FFGestureShake.swift │ ├── FFSimultaneousGesture.swift │ └── FFViewHovering.swift ├── 009 - AdvancedState │ ├── FFAttributeWapper.swift │ ├── FFConstantBindings.swift │ ├── FFCustomBindings.swift │ ├── FFDarkMode.swift │ ├── FFEnvironmentShare.swift │ ├── FFObjectWillChange.swift │ ├── FFObservedObjectManageState.swift │ ├── FFStateObjectMonitorExternal.swift │ ├── FFStateOnchange.swift │ └── FFTimer.swift ├── 010 - Lists │ ├── FFList.swift │ ├── FFListAddSection.swift │ ├── FFListCustomSwipe.swift │ ├── FFListDeleteRows.swift │ ├── FFListDynamicItems.swift │ ├── FFListEditButton.swift │ ├── FFListExpanding.swift │ ├── FFListForEach.swift │ ├── FFListImplicitStacking.swift │ ├── FFListInsetGroup.swift │ ├── FFListMoveRows.swift │ ├── FFListPullRefresh.swift │ ├── FFListRowIndividual.swift │ ├── FFListRowSeparator.swift │ ├── FFListScroll.swift │ ├── FFListSearchBarFilterData.swift │ ├── FFListSearchTocken.swift │ ├── FFListSelectionRow.swift │ ├── FFListSeparator.swift │ ├── FFListStaticitems.swift │ └── SwiftListListRowBackground.swift ├── 011 - Forms │ ├── FFFormAlign.swift │ ├── FFFormDesign.swift │ ├── FFFormDisablingElements.swift │ ├── FFFormPicker.swift │ ├── FFFormSections.swift │ ├── FFFormShowAndHidden.swift │ └── FFForms.swift ├── 012 - Containers │ ├── FFBarsBackground.swift │ ├── FFBarsHidden.swift │ ├── FFContainer.swift │ ├── FFDisclosureGroupHide.swift │ ├── FFGroupBox.swift │ ├── FFGroupView.swift │ ├── FFStatusbarHideAndShow.swift │ ├── FFTabViewBadge.swift │ ├── FFTabViewEnbedViews.swift │ ├── FFTabViewScrollingPages.swift │ ├── FFToolbarButtons.swift │ └── FFToolbarCustomize.swift ├── 013 - Navigation │ ├── FFInspector.swift │ ├── FFInspectorIdeal.swift │ ├── FFNavigation.swift │ ├── FFNavigationCodable.swift │ ├── FFNavigationEdit.swift │ ├── FFNavigationEmbedView.swift │ ├── FFNavigationForList.swift │ ├── FFNavigationProgrammatic.swift │ ├── FFNavigationProgrammaticForHash.swift │ ├── FFNavigationProgrammaticForNext.swift │ ├── FFNavigationSplitView.swift │ ├── FFNavigationSplitViewCompact.swift │ ├── FFNavigationSplitViewContent.swift │ ├── FFNavigationSplitViewCustomize.swift │ ├── FFNavigationSplitViewCustomizeMax.swift │ ├── FFNavigationSplitViewDisplayMode.swift │ ├── FFNavigationSplitViewDisplayModeBalance.swift │ ├── FFNavigationSplitViewHideAndShow.swift │ ├── FFNavigationViewAddItems.swift │ └── FFnavigationPushView.swift ├── 014 - AlertsAndMenus │ ├── FFAlertAddAction.swift │ ├── FFAlertMultiple.swift │ ├── FFAlertSheet.swift │ ├── FFAlertShow.swift │ ├── FFAlertTextField.swift │ ├── FFAppStroeOverlay.swift │ ├── FFMenuContent.swift │ ├── FFMenuPick.swift │ ├── FFMenuShow.swift │ ├── FFPresentations.swift │ └── FFPurchases.swift ├── 015 - PresentingViews │ ├── FFContentUnavailable.swift │ ├── FFContentUnavailableCustom.swift │ ├── FFContentUnavailableCustomAll.swift │ ├── FFPresentSheets.swift │ ├── FFPresentSheetsMultiple.swift │ ├── FFSheetFullScreenCover.swift │ ├── FFSheetPopover.swift │ ├── FFSheetReview.swift │ ├── FFSheetShowBottom.swift │ ├── FFSheetSwipe.swift │ └── FFSheetViewDismiss.swift ├── 016 - TransformingViews │ ├── FFAdvancedEffects.swift │ ├── FFBorderEffect.swift │ ├── FFButtonStyle.swift │ ├── FFProgressViewCustomizing.swift │ ├── FFTextEditorBackground.swift │ ├── FFToggleStyle.swift │ ├── FFViewAccent.swift │ ├── FFViewBlend.swift │ ├── FFViewBlur.swift │ ├── FFViewBorder.swift │ ├── FFViewBorderInside.swift │ ├── FFViewChangeBackground.swift │ ├── FFViewClip.swift │ ├── FFViewMask.swift │ ├── FFViewOffset.swift │ ├── FFViewOpacity.swift │ ├── FFViewPaddingAroundColor.swift │ ├── FFViewRotate.swift │ ├── FFViewRotate3D.swift │ ├── FFViewRound.swift │ ├── FFViewScale.swift │ ├── FFViewShadow.swift │ └── FFViewTintingAndDesaturating.swift ├── 018 - Drawing │ ├── FFConvertToImage.swift │ ├── FFDramCustomPath.swift │ ├── FFDrawCheckerboard.swift │ ├── FFDrawPolygons.swift │ ├── FFMetal.metal │ ├── FFMetalShaders.swift │ ├── FFShapesBuiltin.swift │ ├── FFUIBezierPathAndCGPath.swift │ ├── FFViewToPDF.swift │ ├── FFVisualEffectBlurs.swift │ └── File.swift ├── 019 - Animation │ ├── FFAnimateBindingValues.swift │ ├── FFAnimateTextSize.swift │ ├── FFAnimationDelay.swift │ ├── FFAnimationExlicit.swift │ ├── FFAnimationFinishCallback.swift │ ├── FFAnimationMatchedGeometryEffect.swift │ ├── FFAnimationMultiple.swift │ ├── FFAnimationSpring.swift │ ├── FFAnimationViewAppears.swift │ ├── FFAnimationmulti-step.swift │ ├── FFAnimationsOverride.swift │ ├── FFBasicAnimations.swift │ ├── FFTransitionAsymmetric.swift │ ├── FFTransitionCustom.swift │ ├── FFTransitionView.swift │ └── FFTransitionsCombine.swift ├── 021 - ComposingViews │ ├── FFCreateModifiers.swift │ ├── FFCustomModifiers.swift │ ├── FFCustomText.swift │ ├── FFCustomView.swift │ ├── FFCustomViewWrap.swift │ ├── FFTextInsertImage.swift │ └── FFViewStoreProperties.swift ├── 022 - Cross-platform │ ├── FFCross-platformAbout.swift │ ├── FFMacOSTranslucent.swift │ ├── FFScrollingVertical.swift │ ├── FFWatchOSCarousel.swift │ ├── FFWatchOSDigitalCrown.swift │ └── FFWindowOpen.swift ├── 023 - CoreData │ ├── FFCoreData.swift │ ├── FFCoreDataAddObjects.swift │ ├── FFCoreDataConfigure.swift │ ├── FFCoreDataDeleteObjects.swift │ ├── FFCoreDataFetchRequest.swift │ ├── FFCoreDataFetchRequestsFilter.swift │ ├── FFCoreDataLimit.swift │ ├── FFCoreDataManagged.swift │ ├── FFCoreDataNSUserActivity.swift │ ├── Main.xcdatamodeld │ │ └── Main.xcdatamodel │ │ │ └── contents │ └── PersistenceController.swift ├── 024 - Accessibility │ ├── FFAccessibility.swift │ ├── FFAccessibilityDarkMode.swift │ ├── FFAccessibilityDecorative.swift │ ├── FFAccessibilityReduceModeRequest.swift │ ├── FFAccessibilityReduceMotion.swift │ ├── FFAccessibilityVoiceControl.swift │ ├── FFAccessibilityVoiceOver.swift │ ├── FFFontDynamicType.swift │ └── FFSpecifyDynamicType.swift ├── 025 - Tooling │ ├── FFToolingDiffenertSize.swift │ ├── FFToolingInstruments.swift │ ├── FFToolingSafe.swift │ └── FFToolingSwiftUIChange.swift ├── 026 - PropertyWappers │ ├── FFPropertyWappers.swift │ ├── FFPropertyWappersAll.swift │ ├── FFPropertyWrapperAppStorage.swift │ ├── FFPropertyWrapperBinding.swift │ ├── FFPropertyWrapperEnvironment.swift │ ├── FFPropertyWrapperEnvironmentObject.swift │ ├── FFPropertyWrapperFetchRequest.swift │ ├── FFPropertyWrapperFocusState.swift │ ├── FFPropertyWrapperFocusStateEnum.swift │ ├── FFPropertyWrapperGestureState.swift │ ├── FFPropertyWrapperObservedObject.swift │ ├── FFPropertyWrapperPublished.swift │ ├── FFPropertyWrapperScaledMetric.swift │ ├── FFPropertyWrapperSceneStorage.swift │ ├── FFPropertyWrapperState.swift │ ├── FFPropertyWrapperStateObject.swift │ └── FFPropertyWrapperUIApplicationDelegateAdaptor.swift ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── CustomAssetsColor.colorset │ │ └── Contents.json │ ├── Images │ │ ├── Contents.json │ │ ├── all-out-donuts-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── all-out-donuts-thumb@2x.jpg │ │ │ └── all-out-donuts-thumb@3x.jpg │ │ ├── all-out-donuts.imageset │ │ │ ├── Contents.json │ │ │ ├── all-out-donuts@2x.jpg │ │ │ └── all-out-donuts@3x.jpg │ │ ├── cheese-toastie-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── cheese-toastie-thumb@2x.jpg │ │ │ └── cheese-toastie-thumb@3x.jpg │ │ ├── cheese-toastie.imageset │ │ │ ├── Contents.json │ │ │ ├── cheese-toastie@2x.jpg │ │ │ └── cheese-toastie@3x.jpg │ │ ├── chrysanthemum-tea-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── chrysanthemum-tea-thumb@2x.jpg │ │ │ └── chrysanthemum-tea-thumb@3x.jpg │ │ ├── chrysanthemum-tea.imageset │ │ │ ├── Contents.json │ │ │ ├── chrysanthemum-tea@2x.jpg │ │ │ └── chrysanthemum-tea@3x.jpg │ │ ├── corn-on-the-cob-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── corn-on-the-cob-thumb@2x.jpg │ │ │ └── corn-on-the-cob-thumb@3x.jpg │ │ ├── corn-on-the-cob.imageset │ │ │ ├── Contents.json │ │ │ ├── corn-on-the-cob@2x.jpg │ │ │ └── corn-on-the-cob@3x.jpg │ │ ├── fillet-steak-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── fillet-steak-thumb@2x.jpg │ │ │ └── fillet-steak-thumb@3x.jpg │ │ ├── fillet-steak.imageset │ │ │ ├── Contents.json │ │ │ ├── fillet-steak@2x.jpg │ │ │ └── fillet-steak@3x.jpg │ │ ├── fresh-baked-croissant-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── fresh-baked-croissant-thumb@2x.jpg │ │ │ └── fresh-baked-croissant-thumb@3x.jpg │ │ ├── fresh-baked-croissant.imageset │ │ │ ├── Contents.json │ │ │ ├── fresh-baked-croissant@2x.jpg │ │ │ └── fresh-baked-croissant@3x.jpg │ │ ├── full-english-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── full-english-thumb@2x.jpg │ │ │ └── full-english-thumb@3x.jpg │ │ ├── full-english.imageset │ │ │ ├── Contents.json │ │ │ ├── full-english@2x.jpg │ │ │ └── full-english@3x.jpg │ │ ├── macarons-galore-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── macarons-galore-thumb@2x.jpg │ │ │ └── macarons-galore-thumb@3x.jpg │ │ ├── macarons-galore.imageset │ │ │ ├── Contents.json │ │ │ ├── macarons-galore@2x.jpg │ │ │ └── macarons-galore@3x.jpg │ │ ├── maple-french-toast-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── maple-french-toast-thumb@2x.jpg │ │ │ └── maple-french-toast-thumb@3x.jpg │ │ ├── maple-french-toast.imageset │ │ │ ├── Contents.json │ │ │ ├── maple-french-toast@2x.jpg │ │ │ └── maple-french-toast@3x.jpg │ │ ├── mexican-mocha-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── mexican-mocha-thumb@2x.jpg │ │ │ └── mexican-mocha-thumb@3x.jpg │ │ ├── mexican-mocha.imageset │ │ │ ├── Contents.json │ │ │ ├── mexican-mocha@2x.jpg │ │ │ └── mexican-mocha@3x.jpg │ │ ├── mushroom-tagliatelle-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── mushroom-tagliatelle-thumb@2x.jpg │ │ │ └── mushroom-tagliatelle-thumb@3x.jpg │ │ ├── mushroom-tagliatelle.imageset │ │ │ ├── Contents.json │ │ │ ├── mushroom-tagliatelle@2x.jpg │ │ │ └── mushroom-tagliatelle@3x.jpg │ │ ├── paella-alicante-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── paella-alicante-thumb@2x.jpg │ │ │ └── paella-alicante-thumb@3x.jpg │ │ ├── paella-alicante.imageset │ │ │ ├── Contents.json │ │ │ ├── paella-alicante@2x.jpg │ │ │ └── paella-alicante@3x.jpg │ │ ├── penne-carbonara-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── penne-carbonara-thumb@2x.jpg │ │ │ └── penne-carbonara-thumb@3x.jpg │ │ ├── penne-carbonara.imageset │ │ │ ├── Contents.json │ │ │ ├── penne-carbonara@2x.jpg │ │ │ └── penne-carbonara@3x.jpg │ │ ├── pepperoni-pizza-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── pepperoni-pizza-thumb@2x.jpg │ │ │ └── pepperoni-pizza-thumb@3x.jpg │ │ ├── pepperoni-pizza.imageset │ │ │ ├── Contents.json │ │ │ ├── pepperoni-pizza@2x.jpg │ │ │ └── pepperoni-pizza@3x.jpg │ │ ├── pesto-farfalle-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── pesto-farfalle-thumb@2x.jpg │ │ │ └── pesto-farfalle-thumb@3x.jpg │ │ ├── pesto-farfalle.imageset │ │ │ ├── Contents.json │ │ │ ├── pesto-farfalle@2x.jpg │ │ │ └── pesto-farfalle@3x.jpg │ │ ├── porridge-deluxe-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── porridge-deluxe-thumb@2x.jpg │ │ │ └── porridge-deluxe-thumb@3x.jpg │ │ ├── porridge-deluxe.imageset │ │ │ ├── Contents.json │ │ │ ├── porridge-deluxe@2x.jpg │ │ │ └── porridge-deluxe@3x.jpg │ │ ├── power-muesli-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── power-muesli-thumb@2x.jpg │ │ │ └── power-muesli-thumb@3x.jpg │ │ ├── power-muesli.imageset │ │ │ ├── Contents.json │ │ │ ├── power-muesli@2x.jpg │ │ │ └── power-muesli@3x.jpg │ │ ├── powerhouse-coffee-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── powerhouse-coffee-thumb@2x.jpg │ │ │ └── powerhouse-coffee-thumb@3x.jpg │ │ ├── powerhouse-coffee.imageset │ │ │ ├── Contents.json │ │ │ ├── powerhouse-coffee@2x.jpg │ │ │ └── powerhouse-coffee@3x.jpg │ │ ├── stack-o-pancakes-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── stack-o-pancakes-thumb@2x.jpg │ │ │ └── stack-o-pancakes-thumb@3x.jpg │ │ ├── stack-o-pancakes.imageset │ │ │ ├── Contents.json │ │ │ ├── stack-o-pancakes@2x.jpg │ │ │ └── stack-o-pancakes@3x.jpg │ │ ├── straight-up-oj-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── straight-up-oj-thumb@2x.jpg │ │ │ └── straight-up-oj-thumb@3x.jpg │ │ ├── straight-up-oj.imageset │ │ │ ├── Contents.json │ │ │ ├── straight-up-oj@2x.jpg │ │ │ └── straight-up-oj@3x.jpg │ │ ├── strawberry-cooler-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── strawberry-cooler-thumb@2x.jpg │ │ │ └── strawberry-cooler-thumb@3x.jpg │ │ ├── strawberry-cooler.imageset │ │ │ ├── Contents.json │ │ │ ├── strawberry-cooler@2x.jpg │ │ │ └── strawberry-cooler@3x.jpg │ │ ├── strawberry-surprise-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── strawberry-surprise-thumb@2x.jpg │ │ │ └── strawberry-surprise-thumb@3x.jpg │ │ ├── strawberry-surprise.imageset │ │ │ ├── Contents.json │ │ │ ├── strawberry-surprise@2x.jpg │ │ │ └── strawberry-surprise@3x.jpg │ │ ├── super-sundae-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── super-sundae-thumb@2x.jpg │ │ │ └── super-sundae-thumb@3x.jpg │ │ ├── super-sundae.imageset │ │ │ ├── Contents.json │ │ │ ├── super-sundae@2x.jpg │ │ │ └── super-sundae@3x.jpg │ │ ├── superfood-salad-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── superfood-salad-thumb@2x.jpg │ │ │ └── superfood-salad-thumb@3x.jpg │ │ ├── superfood-salad.imageset │ │ │ ├── Contents.json │ │ │ ├── superfood-salad@2x.jpg │ │ │ └── superfood-salad@3x.jpg │ │ ├── thai-red-curry-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── thai-red-curry-thumb@2x.jpg │ │ │ └── thai-red-curry-thumb@3x.jpg │ │ ├── thai-red-curry.imageset │ │ │ ├── Contents.json │ │ │ ├── thai-red-curry@2x.jpg │ │ │ └── thai-red-curry@3x.jpg │ │ ├── tower-burger-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── tower-burger-thumb@2x.jpg │ │ │ └── tower-burger-thumb@3x.jpg │ │ ├── tower-burger.imageset │ │ │ ├── Contents.json │ │ │ ├── tower-burger@2x.jpg │ │ │ └── tower-burger@3x.jpg │ │ ├── veggie-pizza-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── veggie-pizza-thumb@2x.jpg │ │ │ └── veggie-pizza-thumb@3x.jpg │ │ ├── veggie-pizza.imageset │ │ │ ├── Contents.json │ │ │ ├── veggie-pizza@2x.jpg │ │ │ └── veggie-pizza@3x.jpg │ │ ├── virgin-mojito-thumb.imageset │ │ │ ├── Contents.json │ │ │ ├── virgin-mojito-thumb@2x.jpg │ │ │ └── virgin-mojito-thumb@3x.jpg │ │ └── virgin-mojito.imageset │ │ │ ├── Contents.json │ │ │ ├── virgin-mojito@2x.jpg │ │ │ └── virgin-mojito@3x.jpg │ ├── chincoteague.imageset │ │ ├── Contents.json │ │ └── chincoteague@2x.jpg │ └── ff.colorset │ │ └── Contents.json ├── FFLaunchScreen.storyboard ├── FFModifierApp.swift ├── Info.plist ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json └── Video.mp4 └── README.md /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/.DS_Store -------------------------------------------------------------------------------- /FFModifier.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /FFModifier.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /FFModifier.xcodeproj/project.xcworkspace/xcuserdata/bblv.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier.xcodeproj/project.xcworkspace/xcuserdata/bblv.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /FFModifier/001 - Text/FFTextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFTextField.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/10. 6 | // 7 | // SwiftUI的TextField视图通常允许用户以他们想要的任何大小写的形式编辑内容,但如果你想控制它,你可以使用修饰符来强制使用大写或者小写textCase() 8 | 9 | import SwiftUI 10 | 11 | struct FFTextField: View { 12 | @State private var name = "Paul" 13 | var body: some View { 14 | 15 | List() { 16 | Section { 17 | // 将用户输入的名字每个字母改成大写字母 18 | TextField("Shout your name at me", text: $name) 19 | .textFieldStyle(.roundedBorder) 20 | .textCase(.uppercase) 21 | .padding(.horizontal) 22 | } 23 | } 24 | } 25 | } 26 | 27 | #Preview { 28 | FFTextField() 29 | } 30 | -------------------------------------------------------------------------------- /FFModifier/001 - Text/FFTextUsersSelect.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFTextUsersSelect.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/11. 6 | // 默认情况下,swift的Text视图表示静态、不可选择的文本,但是你可以使用.textSslection()带有值的修饰符来更改它为.enabled 7 | 8 | import SwiftUI 9 | 10 | struct FFTextUsersSelect: View { 11 | var body: some View { 12 | List { 13 | // 选择文本后,用户会自动获得对常规文本操作的访问权限,例如复制和共享。然而,现在至少整个文本区域都被复制了--你没有文本选择放大镜,所以你不能截选你想要的一小部分。 14 | Section { 15 | Text("You can't touch this") 16 | Text("Break it down!") 17 | .textSelection(.enabled) 18 | } 19 | 20 | Section { 21 | //textSelection()对任何类型的书图组进行设置都会自动使改组内的所有文本都可选择。例如,我们可以通过将修饰符添加到外层的Section组件上来使两个Text文本都可以选择copy 22 | 23 | // *注意:如果对list的section进行修饰,这个时候需要按住文本内容,点击空白处不会触发选择 24 | Text("You can't touch this") 25 | Text("Break it down!") 26 | } 27 | .textSelection(.enabled) 28 | } 29 | } 30 | } 31 | 32 | #Preview { 33 | FFTextUsersSelect() 34 | } 35 | -------------------------------------------------------------------------------- /FFModifier/002 - Image/FFGameScene.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFGameScene.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/11. 6 | // 7 | 8 | import Foundation 9 | import SpriteKit 10 | 11 | //创建一个游戏场景,无论点击哪里,这都会创建下落的盒子,并添加物理效果 12 | class FFGameScene: SKScene { 13 | override func didMove(to view: SKView) { 14 | physicsBody = SKPhysicsBody(edgeLoopFrom: frame) 15 | } 16 | 17 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 18 | guard let touch = touches.first else { return } 19 | let location = touch.location(in: self) 20 | let box = SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50)) 21 | box.position = location 22 | box.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 50, height: 50)) 23 | addChild(box) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /FFModifier/002 - Image/FFImageContainerRelativeShape.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFImageContainerRelativeShape.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/11. 6 | // 7 | // SwiftUI有许多不言自明的内置形状,但有一个很突出ContainerRelativeShape。这不是一个固定的形状,而是被设计为它所放置的任何形状的可插入版本,这在创建屏幕小组件时尤为重要 8 | // 重要提示:目前,ContainerRelativeShape禁用于小组件内部,你可以在其他地方使用,但是仅仅表现为一个矩形 9 | 10 | import SwiftUI 11 | 12 | struct FFImageContainerRelativeShape: View { 13 | var body: some View { 14 | //我们可以编写在小部件中绘制蓝色形状的代码,并使用ContainerRelativeShape来确保它与小部件本身形状相同 15 | ZStack { 16 | ContainerRelativeShape() 17 | .inset(by: 4) 18 | .fill(.blue) 19 | 20 | Text("Hello, World!") 21 | .font(.title) 22 | .foregroundStyle(.white) 23 | } 24 | .frame(width: 300, height: 200) 25 | .background(.red) 26 | .clipShape(Capsule()) 27 | 28 | } 29 | } 30 | 31 | #Preview { 32 | FFImageContainerRelativeShape() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/002 - Image/FFImageDynamicColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFImageDynamicColor.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/12. 6 | // 7 | // 如何动态调整 SF Symbol的颜色 8 | // 某些SF Symbols支持动态着色,控制范围在0-1之间 9 | 10 | import SwiftUI 11 | 12 | struct FFImageDynamicColor: View { 13 | @State private var value = 0.0 14 | 15 | var body: some View { 16 | 17 | List { 18 | Section { 19 | //部分填充的Wi-Fi 20 | Image(systemName: "wifi", variableValue: 0.5) 21 | } 22 | 23 | Section { 24 | Image(systemName: "aqi.low", variableValue: value) 25 | Image(systemName: "wifi", variableValue: value) 26 | Image(systemName: "chart.bar.fill", variableValue: value) 27 | Image(systemName: "waveform", variableValue: value) 28 | 29 | Slider(value: $value) 30 | } 31 | .font(.system(size: 72)) 32 | .foregroundStyle(.blue) 33 | .padding() 34 | } 35 | } 36 | } 37 | 38 | #Preview { 39 | FFImageDynamicColor() 40 | } 41 | -------------------------------------------------------------------------------- /FFModifier/002 - Image/FFImageShapes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFImageShapes.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/11. 6 | // 7 | // SwiftUI由很多种内置形状,例如矩形、圆形和圆角矩形 8 | 9 | import SwiftUI 10 | 11 | struct FFImageShapes: View { 12 | var body: some View { 13 | List { 14 | //200 * 200的红色矩形 15 | Rectangle() 16 | .fill(.red) 17 | .frame(width: 200, height: 200) 18 | 19 | //100 * 100的蓝色圆形 20 | Circle() 21 | .fill(.blue) 22 | .frame(width: 100, height: 100) 23 | 24 | //圆角矩形 25 | RoundedRectangle(cornerRadius: 25.0) 26 | .fill(.green) 27 | .frame(width: 150, height: 100) 28 | 29 | // Capsule()是SwiftUI提供的一种特殊的圆角矩形,其中最短的边永远是完全圆角的,类似Slider背景视图 30 | Capsule() 31 | .fill(.green) 32 | .frame(width: 150, height: 100) 33 | 34 | } 35 | } 36 | } 37 | 38 | #Preview { 39 | FFImageShapes() 40 | } 41 | -------------------------------------------------------------------------------- /FFModifier/002 - Image/FFImagefitToSpace.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFImagefitToSpace.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/11. 6 | // 7 | // SwiftUI的Image视图能够以不同的方式缩放,就像UIImageView一样,默认情况下,图像视图会自动根据器内容调整大小,这可能会是他们超出屏幕范围,如果添加了resizable()修饰符,则图像将自动调整大小,以便填充到可用空间,无论是在你指定的框架中还是屏幕上的任何空间中 8 | 9 | import SwiftUI 10 | 11 | struct FFImagefitToSpace: View { 12 | var body: some View { 13 | Image(.allOutDonutsThumb) 14 | .resizable() 15 | .frame(width: 200) 16 | 17 | //然而,这会导致图像的原始纵横比扭曲,因为它将在所有维度上拉伸以填充空间,如果你想保持纵横比,可以使用aspecRatio的.fill火.fit修饰符 18 | Image(.allOutDonutsThumb) 19 | .resizable() 20 | .aspectRatio(contentMode: .fit) 21 | .frame(width: 200) 22 | } 23 | } 24 | 25 | #Preview { 26 | FFImagefitToSpace() 27 | } 28 | -------------------------------------------------------------------------------- /FFModifier/002 - Image/FFImagetile.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFImagetile.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/11. 6 | // 7 | // 如果SwiftUI被要求使用图像视图占用的空间超过图像设计的空间,它的默认行为是拉伸图像,使其适合你所要求的空间。然而,它不需要这样,它可以平铺图像(水平或垂直重复),以便填满空间。关键将resizable()修饰符与其resizingMode参数一起使用,可以是.stretch(默认)、tile 8 | 9 | import SwiftUI 10 | 11 | struct FFImagetile: View { 12 | var body: some View { 13 | VStack { 14 | Image(.allOutDonuts) 15 | .resizable(resizingMode: .tile) 16 | 17 | // 如果你只想平铺图像的一部分(或将一个或多个边缘固定到图像视图的边缘),那么可以为第一个参数提供边缘插入 18 | 19 | Image(.cheeseToastie) 20 | .resizable(capInsets: EdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20), resizingMode: .tile) 21 | 22 | 23 | } 24 | } 25 | } 26 | 27 | #Preview { 28 | FFImagetile() 29 | } 30 | -------------------------------------------------------------------------------- /FFModifier/002 - Image/FFSpriteView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFSpriteView.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/11. 6 | // 7 | // SwiftUI中可以的SpriteView可以渲染任何子类,如果有需求,SKScene可以调整场景大小 8 | 9 | import Foundation 10 | import SwiftUI 11 | import SpriteKit 12 | 13 | struct FFSpriteView: View { 14 | 15 | var scene: SKScene { 16 | let scene = FFGameScene() 17 | scene.size = CGSize(width: 300, height: 400) 18 | scene.scaleMode = .fill 19 | return scene 20 | } 21 | 22 | var body: some View { 23 | SpriteView(scene: scene) 24 | .frame(width: 300, height: 400) 25 | .ignoresSafeArea() 26 | } 27 | } 28 | 29 | #Preview { 30 | FFSpriteView() 31 | } 32 | -------------------------------------------------------------------------------- /FFModifier/002 - Image/SwiftCustomColorWithAsset.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftCustomColorWithAsset.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/13. 6 | // 7 | // 如何在资产目录加载自定义颜色 8 | // 在Assets中创建 颜色是可视化它们最好的方式,也是添加深色与浅色模式调整的简单方法(在Assets中添加color set可以同时分别设定深色与浅色模式) 9 | 10 | import SwiftUI 11 | 12 | struct SwiftCustomColorWithAsset: View { 13 | var body: some View { 14 | 15 | List { 16 | Section { 17 | Color(.customAssets) 18 | } 19 | 20 | Section { 21 | Color(.ff) 22 | } 23 | } 24 | } 25 | } 26 | 27 | #Preview { 28 | SwiftCustomColorWithAsset() 29 | } 30 | -------------------------------------------------------------------------------- /FFModifier/002 - Image/Temp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Temp.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/13. 6 | // 7 | 8 | import Foundation 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /FFModifier/003 - Layout/FFViewGestures.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewGestures.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/17. 6 | // 7 | // 如何阻止系统手势干扰你自己的手势 8 | // SwiftUI的defersSystemGestures修饰符允许我们的手势优先于系统自己的内置手势。这在很多地方都很重要,例如频繁滑动的游戏,或者当你自己将手势放在屏幕边缘时 9 | 10 | import SwiftUI 11 | 12 | struct FFViewGestures: View { 13 | @State private var input = 0.0 14 | 15 | var body: some View { 16 | /**在iOS上,它做了三件不同的事情: 17 | 1、如果用户从顶部向下拉,它们会看到一个需要再次拉动的小选项卡,而不是出现控制中心。 18 | 2、主屏幕指示器将淡出至较低的不透明度,如果用户直接拖动该淡出的主屏幕指示器,则将其淡入。然后,可以再次向上活动以进入任务切换器或者主屏幕 19 | 3、如果用户从底部向上滑动到主页指示器的人一次,则会发生自定义的拖动手势 20 | */ 21 | 22 | Text("Current value: \(input)") 23 | .frame(maxWidth: .infinity, maxHeight: .infinity) 24 | .contentShape(Rectangle()) 25 | .gesture( 26 | DragGesture().onChanged({ value in 27 | input = value.location.y - value.startLocation.y 28 | }) 29 | ) 30 | .defersSystemGestures(on: .vertical) 31 | } 32 | } 33 | 34 | #Preview { 35 | FFViewGestures() 36 | } 37 | -------------------------------------------------------------------------------- /FFModifier/003 - Layout/FFViewLayoutPriority.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewLayoutPriority.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/17. 6 | // 7 | // 如何使用layoutPriority()控制布局优先级 8 | // SwiftUI的layoutPriority()修饰符允许我们请求在空间有限时应在屏幕上为某些视图提供更多的空间。默认情况下,所有视图的布局优先级均为0,但如果你发现某个特定的视图被压缩,你可以使用此修饰符为其赋予更高的优先级 9 | 10 | import SwiftUI 11 | 12 | struct FFViewLayoutPriority: View { 13 | var body: some View { 14 | List { 15 | Section { 16 | //由于两个字符串都很长,在iPhone上会自动换行,并且SwiftUI会尝试公平的调整它们的大小,以便它们根据自己的长度获得更大的空间 17 | HStack{ 18 | Text("蜀道难,难于上青天!") 19 | Text("蚕丛及鱼凫,开国何茫然!") 20 | } 21 | //这里使用layoutPriority修饰符来改变两个字符串的优先级,SwiftUI将计算低优先级文本视图所需的最小空间,然后将剩余空间提供给高优先级的文本,以便它可以占有更大的空间 22 | HStack{ 23 | Text("蜀道难,难于上青天!") 24 | Text("蚕丛及鱼凫,开国何茫然!") 25 | .layoutPriority(1) 26 | } 27 | } 28 | } 29 | } 30 | } 31 | 32 | #Preview { 33 | FFViewLayoutPriority() 34 | } 35 | -------------------------------------------------------------------------------- /FFModifier/003 - Layout/FFViewSafeArea.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewSafeArea.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/17. 6 | // 7 | // 如何将内容放置在安全区域之外 8 | // 默认情况下,SwiftUI视图将大部分留在安全区域内,它们将到达屏幕底部,但不会接近设备顶部的任何凹口,如果想更改,设置真正的全屏,添加修饰符ignoresSafeArea() 9 | 10 | import SwiftUI 11 | 12 | struct FFViewSafeArea: View { 13 | var body: some View { 14 | 15 | Text("Hello, World!") 16 | .frame(minWidth: 100, maxWidth: .infinity, minHeight: 100, maxHeight: .infinity) 17 | .foregroundStyle(.white) 18 | .background(.orange) 19 | .ignoresSafeArea() 20 | } 21 | } 22 | 23 | #Preview { 24 | FFViewSafeArea() 25 | } 26 | -------------------------------------------------------------------------------- /FFModifier/003 - Layout/FFViewhideSystemUI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewhideSystemUI.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/17. 6 | // 7 | // 如何隐藏主页指示器和其他系统UI 8 | // SwiftUI的persistentSystemOverlays修饰符可以让我们显示或隐藏所谓的“非瞬态系统视图”,这些视图会自动放置在我们的UI上,比如Apple的主页指示器、iPad上的多任务指示器的名称 9 | 10 | import SwiftUI 11 | 12 | struct FFViewhideSystemUI: View { 13 | var body: some View { 14 | Text("This needs to take up lots of space") 15 | .frame(maxWidth: .infinity,maxHeight: .infinity) 16 | .background(.yellow) 17 | .persistentSystemOverlays(.hidden) 18 | } 19 | } 20 | 21 | #Preview { 22 | FFViewhideSystemUI() 23 | } 24 | -------------------------------------------------------------------------------- /FFModifier/004 - Stacks,girds,scrollviews/FFLayoutsSizeClasses.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFLayoutsSizeClasses.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/18. 6 | // 7 | // 如何使用尺寸类别创建不同的Layouts 8 | // SwiftUI通过将尺寸类暴露在环境中供我们阅读原生支持尺寸累。要使用它们,首先创建一个将存储其值的@Environment对象,然后在需要时检查该属性的值,查找.compact或.regular大小类。 9 | //compact: 表示紧凑的尺寸类别。通常用于较小的屏幕或限制空间的界面布局。 10 | //regular: 表示常规的尺寸类别。通常用于较大的屏幕或具有更多空间的界面布局 11 | 12 | //通过检查 FFLayoutsSizeClasses 的 horizontalSizeClass 和 verticalSizeClass 属性来获取当前设备的尺寸类别。 13 | //使用 SwiftUI 的 @Environment 属性包装器来获取尺寸类别信息。 14 | 15 | import SwiftUI 16 | 17 | struct FFLayoutsSizeClasses: View { 18 | @Environment(\.horizontalSizeClass) var horizontalSizeClass 19 | 20 | var body: some View { 21 | //在 iPad 上,用户界面的尺寸类别通常是 regular,因为 iPad 屏幕较大,提供了足够的空间来显示更多内容。而在 iPhone 的竖屏模式下,尺寸类别通常是 compact,因为屏幕相对较小,需要更紧凑的布局。 22 | if horizontalSizeClass == .compact { 23 | return Text("Compact Size Class") 24 | } else { 25 | return Text("Regular Size Class") 26 | } 27 | } 28 | } 29 | 30 | #Preview { 31 | FFLayoutsSizeClasses() 32 | } 33 | -------------------------------------------------------------------------------- /FFModifier/004 - Stacks,girds,scrollviews/FFScrollViewHideIndicators.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFScrollViewHideIndicators.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/19. 6 | // 7 | // 如何隐藏ScrollView、List的滚动指示器 8 | // SwiftUI的ScrollIndicators()修饰符控制是否显示滚动指示器--这些闪烁的小条既能让用户了解内容的大小,又允许长按滚动 9 | import SwiftUI 10 | 11 | struct FFScrollViewHideIndicators: View { 12 | var body: some View { 13 | List(1..<100) { i in 14 | Text("Row \(i)") 15 | } 16 | .scrollIndicators(.hidden) 17 | 18 | /**ScrollIndicatorVisibility有四个枚举值: 19 | .automatic:这是没有应用修饰符的行为 20 | .visible:可以在iOS上显示自动隐藏滚动指示器,或在macOS上根据用户偏好设置来决定是否隐藏 21 | .hidden:可以隐藏iOS上的指示器,并在大多数情况下macOS上隐藏,如果用户链接鼠标,滚动指示器重新显示 22 | .never:可以在iOS和macOS上隐藏指示器,无论用户使用的指针设备时什么 23 | */ 24 | } 25 | } 26 | 27 | #Preview { 28 | FFScrollViewHideIndicators() 29 | } 30 | -------------------------------------------------------------------------------- /FFModifier/004 - Stacks,girds,scrollviews/FFScrollViewStartBottom.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFScrollViewStartBottom.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/19. 6 | // 7 | // 如何让ScrollView在底部开始 8 | // 默认情况下,SwiftUI的ScrollView从顶部开始滚动,但如果你想创建想Apple的消息app那样的UI,你可以使用带有.bottom初始锚点的scrollPosition()修饰符要求滚动视图从底部开始 9 | 10 | import SwiftUI 11 | 12 | struct FFScrollViewStartBottom: View { 13 | var body: some View { 14 | //例如,这在滚动视图中显示50个文本视图,但要求滚动视图从底部而不是顶部开始 15 | ScrollView { 16 | ForEach(0..<50) { i in 17 | Text("Item \(i)") 18 | .frame(maxWidth: .infinity) 19 | .padding() 20 | .background(.blue) 21 | .clipShape(.rect(cornerRadius: 25)) 22 | } 23 | } 24 | // .scrollPosition(initialAnchor: .bottom) 25 | 26 | //如果你的UI在用户不滚动的情况下发生某种变化(例如,如果出现假盘,或者你调整ScrollView的大小),则滚动位置将保持锚定在底部。但是,如果用户手动调整滚动位置,他将正常自由的滚动 27 | //提示:initialAnchor参数时任何UIPoint,因此你可以使用.trailing从右边边缘启动水平滚动的视图 28 | } 29 | } 30 | 31 | #Preview { 32 | FFScrollViewStartBottom() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/004 - Stacks,girds,scrollviews/FFStackPrimary.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFStackPrimary.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/18. 6 | // 7 | // 如何使用VStack和HStack创建stack 8 | // 我们的 SwiftUI 内容视图必须包含一个或多个视图,这是我们希望它们显示的布局。 当我们想要一次在屏幕上显示多个视图时,您通常会想要告诉 SwiftUI 如何排列它们,这就是堆栈的用武之地。 9 | // Stack - 相当于 UIKit 中的 UIStackView - 具有三种形式:水平 (HStack)、垂直 (VStack) 和基于深度 (ZStack),当您想要放置子视图以使它们重叠时,使用后者。 10 | 11 | import SwiftUI 12 | 13 | struct FFStackPrimary: View { 14 | var body: some View { 15 | List { 16 | Section { 17 | Text("Hello, SwiftUI") 18 | } 19 | 20 | Section { 21 | VStack { 22 | Text("Hello") 23 | Text("SwiftUI") 24 | } 25 | } 26 | 27 | Section { 28 | HStack { 29 | Text("Hello") 30 | Text("SwiftUI") 31 | } 32 | } 33 | } 34 | } 35 | } 36 | 37 | #Preview { 38 | FFStackPrimary() 39 | } 40 | -------------------------------------------------------------------------------- /FFModifier/004 - Stacks,girds,scrollviews/FFStackZIndex.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFStackZIndex.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/18. 6 | // 7 | // 如何通过ZIndex更改视图分层的顺序 8 | // 默认情况下,SwiftUI的ZStack使用画家算法来分层其视图来决定视图的深度:无论你先放入ZStack的什么内容都会被先绘制,然后后续的视图将在其上分层。虽然这通常是你想要的,但有时你需要更多的控制-例如,你可能虚妄在app运行时将一个视图推到另一个视图后面,或者在点击某个特定视图时将其置于前面。为此,你需要使用zIndex修饰符,它允许你准确指定视图在单个ZStack中如何分层。视图默认Z索引为0,但你可以设置正值或负值,分别将它们放置在其他视图的顶部或下方 9 | 10 | import SwiftUI 11 | 12 | struct FFStackZIndex: View { 13 | var body: some View { 14 | List { 15 | //此ZStack包含两个重叠的矩形,但绿色矩形仍然可见,因为它设置zIndex为1 16 | ZStack { 17 | Rectangle() 18 | .fill(.green) 19 | .frame(width: 50, height: 50) 20 | .zIndex(1) 21 | Rectangle() 22 | .fill(.red) 23 | .frame(width: 100, height: 100) 24 | } 25 | //zIndex修饰符仅影响当前ZStack内的绘制顺序,如果你有两个ZStack,需要分别设定 26 | } 27 | } 28 | } 29 | 30 | #Preview { 31 | FFStackZIndex() 32 | } 33 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFButtonRepeat.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFButtonRepeat.swift 3 | // FFModifier 4 | // 5 | // Created by 小B同学 on 2023/7/25. 6 | // 7 | // 如何创建按下时重复其动作的按钮 8 | // SwiftUI有一个专用的buttonRepeatBehavior()修饰符,当用户按住按钮是,他会反复出发按钮的动作。该动作的触发动作越来越快。 9 | 10 | 11 | import SwiftUI 12 | 13 | struct FFButtonRepeat: View { 14 | @State private var tapCount = 0 15 | 16 | var body: some View { 17 | Button("Tap Count: \(tapCount)") { 18 | tapCount += 1 19 | } 20 | .buttonRepeatBehavior(.enabled) 21 | 22 | Divider() 23 | //通过shift+return来反复出发我们的按钮 24 | Button("Tap Count: \(tapCount)") { 25 | tapCount += 1 26 | } 27 | .buttonRepeatBehavior(.enabled) 28 | .keyboardShortcut(.return, modifiers: .shift) 29 | } 30 | } 31 | 32 | #Preview { 33 | FFButtonRepeat() 34 | } 35 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFColorPicker.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFColorPicker.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/25. 6 | // 7 | // 如何通过ColorPicker选择颜色 8 | 9 | 10 | import SwiftUI 11 | 12 | struct FFColorPicker: View { 13 | @State private var bgColor = Color.red 14 | @State private var bgColor1 = Color.green 15 | var body: some View { 16 | 17 | VStack { 18 | ColorPicker("Set the background color", selection: $bgColor) 19 | } 20 | .frame(maxWidth: .infinity, maxHeight: .infinity) 21 | .background(bgColor) 22 | .padding() 23 | 24 | //默认情况下,ColorPicker支持颜色选择中的不透明度,可以禁用 25 | VStack { 26 | ColorPicker("Set the background color", selection: $bgColor1, supportsOpacity: false) 27 | } 28 | .frame(maxWidth: .infinity, maxHeight: .infinity) 29 | .background(bgColor1) 30 | .padding() 31 | } 32 | } 33 | 34 | #Preview { 35 | FFColorPicker() 36 | } 37 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFControlGroup.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFControlGroup.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/24. 6 | // 7 | // 如何使用ControlGroup将视图分组在一起 8 | // SwiftUI的ControlGroupView 9 | 10 | import SwiftUI 11 | 12 | struct FFControlGroup: View { 13 | var body: some View { 14 | ControlGroup { 15 | Button("First") { } 16 | Button("Second") { } 17 | Button("Thread") { } 18 | } 19 | } 20 | } 21 | 22 | #Preview { 23 | FFControlGroup() 24 | } 25 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFCustomSubmit.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFCustomSubmit.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/24. 6 | // 7 | // 如何自定义TextField、SecureField和TextEditor的submit按钮 8 | // 默认情况下,TextField和SecureField在键盘上显示一个简单的“return”按钮,可以使用submitlabel()修饰符让我们从一系列替代方案中进行选择 9 | 10 | import SwiftUI 11 | 12 | struct FFCustomSubmit: View { 13 | @State private var username = "" 14 | 15 | var body: some View { 16 | // 修改为join 17 | List { 18 | TextField("Username", text: $username) 19 | .submitLabel(.join) 20 | } 21 | 22 | /**通过submitLabel修饰符:可以选择不同的枚举: 23 | continue, 24 | done, 25 | go, 26 | join, 27 | next, 28 | return, 29 | route, 30 | search, 31 | send 32 | */ 33 | // 适用于TextField、SecureField、TextView输入控件 34 | } 35 | } 36 | 37 | #Preview { 38 | FFCustomSubmit() 39 | } 40 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFLabelHidden.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFLabelHidden.swift 3 | // FFModifier 4 | // 5 | // Created by 小B同学 on 2023/7/25. 6 | // 7 | // 如何使用LabelsHidden()隐藏Picker、Stepper、Toggle等标签 8 | // SwiftUI要求我们在其控件中添加标签,通常想要隐藏这些标签,以便你可以获得更精确的UI布局。然而,隐藏标签有一种糟糕的方式和一种好方法 9 | import SwiftUI 10 | 11 | struct FFLabelHidden: View { 12 | @State private var selectedNumber = 0 13 | 14 | var body: some View { 15 | Picker("Select a number", selection: $selectedNumber) { 16 | ForEach(0..<10) { 17 | Text("\($0)") 18 | } 19 | } 20 | .labelsHidden() 21 | } 22 | } 23 | 24 | #Preview { 25 | FFLabelHidden() 26 | } 27 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFMap.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFMap.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/25. 6 | // 7 | // SwiftUI的Map可以与其他控件一起使用,并控制是否向用户显示、注释信息等 8 | 9 | import SwiftUI 10 | import MapKit 11 | 12 | struct FFMap: View { 13 | @State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.507222, longitude: -0.1275), span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)) 14 | 15 | var body: some View { 16 | //通过MKCoordinateRegion创建经纬度 17 | Map(coordinateRegion: $region) 18 | .frame(width: 400, height: 300) 19 | } 20 | } 21 | 22 | #Preview { 23 | FFMap() 24 | } 25 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFPickerOrRead.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFPickerOrRead.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/25. 6 | // 7 | // 如何创建Picker并读取值 8 | // SwiftUI的Picker将UIPickerView、UISegmentedControl和UITableView合二为一,同时还适应其他OS上的样式。与大多数其他空间一样,你必须将picker附加到某中撞来来跟踪picker的选择。例如,创建一个colors数组和一个整数来存储选择的颜色,然后将其与选择器和文本殊途一起使用。 9 | 10 | import SwiftUI 11 | 12 | struct FFPickerOrRead: View { 13 | var colors = ["Red", "Green", "Blue", "Tartan"] 14 | @State private var selectedColor = "Red" 15 | 16 | var body: some View { 17 | VStack { 18 | Picker("Plaease choose a color", selection: $selectedColor) { 19 | ForEach(colors, id: \.self) { 20 | Text($0) 21 | } 22 | } 23 | 24 | Text("Your selected: \(selectedColor)") 25 | } 26 | } 27 | } 28 | 29 | #Preview { 30 | FFPickerOrRead() 31 | } 32 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFProgressView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFProgressView.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/25. 6 | // 7 | // 如何通过ProgressView显示任务进度 8 | 9 | import SwiftUI 10 | 11 | struct FFProgressView: View { 12 | @State private var downloadAmount = 0.0 13 | let timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect() 14 | var body: some View { 15 | //创建一个正在下载的进度条 16 | VStack { 17 | ProgressView("Downloading...", value: downloadAmount, total: 100) 18 | } 19 | .padding() 20 | 21 | ProgressView("Downloading...", value: downloadAmount, total: 100) 22 | .onReceive(timer, perform: { _ in 23 | if downloadAmount < 100 { 24 | downloadAmount += 2 25 | } 26 | }) 27 | .padding() 28 | 29 | //动态填满进度条 30 | 31 | } 32 | } 33 | 34 | #Preview { 35 | FFProgressView() 36 | } 37 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFProressViewIndeterminate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFProressViewIndeterminate.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/25. 6 | // 7 | // 如何使ProgressView显示不确定的进度 8 | // ProgressView可以在不附加任何类型的绑定的情况下创建,这种情况下显示一个菊花,不带进度 9 | 10 | import SwiftUI 11 | 12 | struct FFProressViewIndeterminate: View { 13 | var body: some View { 14 | ProgressView("Downloading...") 15 | } 16 | } 17 | 18 | #Preview { 19 | FFProressViewIndeterminate() 20 | } 21 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFSecureField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFSecureField.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/25. 6 | // 7 | // 如何使用SecureField创建加密TextField 8 | // SwiftUI的SecureField的原理与TextField几乎相同,只是为了保护隐私而屏蔽了字符。 9 | 10 | import SwiftUI 11 | 12 | struct FFSecureField: View { 13 | @State private var password: String = "" 14 | 15 | var body: some View { 16 | 17 | VStack(alignment: .leading) { 18 | SecureField("Enter a password", text: $password) 19 | Text("Your entered: \(password)") 20 | } 21 | .padding() 22 | 23 | Spacer() 24 | } 25 | } 26 | 27 | #Preview { 28 | FFSecureField() 29 | } 30 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFSliderOrRead.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFSliderOrRead.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/25. 6 | // 7 | // 如何创建Slider并读取值 8 | // SwiftUI的Slider的原理与UISlider相似,你需要将其绑定到某处一边可以存储值。 9 | /** 创建一个Slider需要的参数: 10 | value:绑定一个Double类型的数据 11 | in:slider的滑动范围 12 | Step:移动时值的变化量。 13 | */ 14 | 15 | import SwiftUI 16 | 17 | struct FFSliderOrRead: View { 18 | @State private var celsius: Double = 0 19 | 20 | var body: some View { 21 | VStack(alignment: .leading) { 22 | Slider(value: $celsius, in: -100...100) 23 | Text("\(celsius, specifier: "%.1f") Celsius is \(celsius * 9 / 5 + 32, specifier: "%.1f") fahrenheit") 24 | } 25 | .padding() 26 | 27 | Spacer() 28 | } 29 | } 30 | 31 | #Preview { 32 | FFSliderOrRead() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFStepperOrRead.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFStepperOrRead.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/25. 6 | // 7 | // 如何创建Stepper并读取值 8 | // SwiftUI的Stepper与UIStepper相同 9 | 10 | import SwiftUI 11 | 12 | struct FFStepperOrRead: View { 13 | @State private var age = 18 14 | 15 | var body: some View { 16 | 17 | //创建一个setpper绑定到age,取值范围0-130 18 | VStack { 19 | Stepper("Enter your age", value: $age, in: 0...130) 20 | Text("Your age is \(age)") 21 | 22 | Divider() 23 | 24 | //onIncrement可以自定义闭包 25 | Stepper("Enter your age") { 26 | age += 1 27 | } onDecrement: { 28 | age -= 1 29 | } 30 | 31 | Text("Your age is \(age)") 32 | 33 | } 34 | .padding() 35 | 36 | Spacer() 37 | 38 | } 39 | } 40 | 41 | #Preview { 42 | FFStepperOrRead() 43 | } 44 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFTextEditor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFTextEditor.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/25. 6 | // 7 | // 如何通过TextEditor创建多行可编辑文本 8 | // SwiftUI的TextEditor用于处理多行滚动文本的视图。你可以根据需要设置字体、更改颜色,甚至可以调整行距和行数 9 | 10 | import SwiftUI 11 | 12 | struct FFTextEditor: View { 13 | @State private var profileText = "Enter your bio" 14 | 15 | var body: some View { 16 | // 创建TextEditor 17 | NavigationStack { 18 | TextEditor(text: $profileText) 19 | .foregroundStyle(.secondary) 20 | .padding(.horizontal) 21 | .navigationTitle("About you") 22 | } 23 | } 24 | } 25 | 26 | #Preview { 27 | FFTextEditor() 28 | } 29 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFTextFieldAutocorrect.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFTextFieldAutocorrect.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/25. 6 | // 7 | // 如何使TextField文本自动更正 8 | // SwiftUI的TextField默认开启自动更正,这在大多数时候都是ok的,但是,如果你想禁用它,使用autocorrectionDisabled()修饰符,默认是true 9 | 10 | import SwiftUI 11 | 12 | struct FFTextFieldAutocorrect: View { 13 | @State private var name = "" 14 | 15 | var body: some View { 16 | TextField("输入你的名字", text: $name) 17 | .autocorrectionDisabled() 18 | } 19 | } 20 | 21 | #Preview { 22 | FFTextFieldAutocorrect() 23 | } 24 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFTextFieldBorder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFTextFieldBorder.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/25. 6 | // 7 | // 如何向文本字段添加边框 8 | // 默认情况下,SwiftUI的TextField视图没有样式,在屏幕上表现为空白区域。通常情况下,会添加边框使其更具有辨识度 9 | 10 | import SwiftUI 11 | 12 | struct FFTextFieldBorder: View { 13 | @State private var name: String = "Tim" 14 | 15 | var body: some View { 16 | List { 17 | //给TextField添加圆角边框 18 | VStack(alignment: .leading) { 19 | TextField("输入你的名字", text: $name) 20 | .textFieldStyle(.roundedBorder) 21 | Text("Hello, \(name)") 22 | } 23 | .frame(height: 150) 24 | } 25 | } 26 | } 27 | 28 | #Preview { 29 | FFTextFieldBorder() 30 | } 31 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFTextFieldPlaceholder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFTextFieldPlaceholder.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/25. 6 | // 7 | // 如何给TextField添加PlaceHolder 8 | // SwiftUI的TextField可以使用placeholder 9 | 10 | import SwiftUI 11 | 12 | struct FFTextFieldPlaceholder: View { 13 | @State private var emailAddress = "" 14 | 15 | //metabblv@163.com为placeholder 16 | var body: some View { 17 | List { 18 | TextField("metabblv@163.com", text: $emailAddress) 19 | .textFieldStyle(.roundedBorder) 20 | .padding() 21 | } 22 | } 23 | } 24 | 25 | #Preview { 26 | FFTextFieldPlaceholder() 27 | } 28 | -------------------------------------------------------------------------------- /FFModifier/005 - UIControls/FFTextFieldRead.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFTextFieldRead.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/24. 6 | // 7 | // 如何读取TextField的text 8 | // SwiftUI的TextField与UIKit中的UITextField类似,尽管默认情况下看起来有些不同,并且非常依赖状态绑定 9 | // 要创建一个TextField,传入一个文本字段内使用占位符,以及它应绑定的状态值。 10 | 11 | import SwiftUI 12 | 13 | struct FFTextFieldRead: View { 14 | @State private var name:String = "Tim" 15 | var body: some View { 16 | List { 17 | //例如,创建一个TextField到本地字符串绑定,然后下方创建一个Text。 18 | VStack(alignment: .leading, content: { 19 | TextField("输入你的名字", text: $name) 20 | Text("Hello, \(name)!") 21 | }) 22 | //运行后,结果时TextField中输入什么,直接在下方的Text中显示了。 23 | //使用文本字段时有两个重要限制条件。首先,默认情况下它们没有边框,因此你可能看不到任何内容,你需要在其内部大致位置点击才能激活键盘。 24 | } 25 | } 26 | } 27 | 28 | #Preview { 29 | FFTextFieldRead() 30 | } 31 | -------------------------------------------------------------------------------- /FFModifier/007 - RespondingEvent/FFAppdelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFAppdelegate.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/31. 6 | // 7 | // 如何给SwiftUI App添加一个AppDelegate 8 | // SwiftUI应用启动时使用一个符合App协议的自定义结构体,但有时你可能想要回到我们曾经拥有的就的UIApplicationDelegate功能--也许是处理推送通知的注册,响应内存警告,检测时间变化等等。 9 | 10 | import SwiftUI 11 | 12 | //要做到这一点,首先创建一个自定义类,继承自NSObject并遵守UIApplicationDelegate协议。 13 | 14 | class Appdelegate: NSObject, UIApplicationDelegate { 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { 16 | print("applicationDidFinishLaunching") 17 | return true 18 | } 19 | } 20 | 21 | struct FFAppdelegate: View { 22 | var body: some View { 23 | Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) 24 | } 25 | } 26 | 27 | #Preview { 28 | FFAppdelegate() 29 | } 30 | -------------------------------------------------------------------------------- /FFModifier/007 - RespondingEvent/FFCanvasDropImage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFCanvasDropImage.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/2. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct FFCanvasDropImage: View { 11 | @State private var message = "" 12 | @State private var image = Image(systemName: "photo") 13 | var body: some View { 14 | //处理图像有点困难,因为我们将获得一个代表图像内容的data实例。我们需要将其转化为UIImage,并将结果放入图像中进行渲染。幸运的是,如果我们支持data,那么两只都会起作用,所以想这样的代码允许用户将图像从照片中直接拖入到我们的应用程序中 15 | image 16 | .resizable() 17 | .scaledToFit() 18 | .frame(width: 300,height: 300) 19 | .dropDestination(for: Data.self) { items, location in 20 | guard let item = items.first else { return false } 21 | guard let uiImage = UIImage(data: item) else { return false } 22 | image = Image(uiImage: uiImage) 23 | return true 24 | } 25 | } 26 | } 27 | 28 | #Preview { 29 | FFCanvasDropImage() 30 | } 31 | -------------------------------------------------------------------------------- /FFModifier/007 - RespondingEvent/FFLaunchesCode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFLaunchesCode.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/31. 6 | // 7 | // 如何在应用程序启动的时候运行代码 8 | // 当你使用SwiftUI应用程序生命周期时,你的应用程序将通过应用程序协议的结构体启动。它是使用WindowGroup、DocumentGroup类似的工具创建初始视图,但因为它在你任何的实际视图之前创建的,所以这是在应用程序启动时运行代码的完美位置。 9 | // 例如:如果你想设置一些初始UserDefaults值,那么应用程序的初始值谁能够项是调用register(defaults:)的好地方。此方法设置默认值,我的意思是UserDefaults值的初始值仅在你设置它们之前存在,一旦你提供了自己的值,这些值不再使用,并且这些初始值也会在一下情况下消失:app终止。 10 | import SwiftUI 11 | 12 | //initializer()在body属性之前被调用,所以它在ContentView之前被调用,因此,你在ContentView中读取UserDefaults的任何地方都已经有了你的默认值。为了演示这一点,这里有一个示例ContentView结构体,它使用@AppStorage读取name的值。 13 | struct FFLaunchesCode: View { 14 | //一种属性包装器类型,它反映UserDefaults中的值,并在该用户默认值的值更改时使视图无效。 15 | @AppStorage("name") var name = "Anonymous" 16 | var body: some View { 17 | //当通过@AppStorage属性包装器生命的变量,只有当没register默认值的时候才用。如果有默认值,就使用默认的。 18 | Text("Your name is \(name).") 19 | } 20 | } 21 | 22 | #Preview { 23 | FFLaunchesCode() 24 | } 25 | -------------------------------------------------------------------------------- /FFModifier/007 - RespondingEvent/FFPasteData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFPasteData.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/7/31. 6 | // 7 | // 如何让用户将数据粘贴到应用程序中 8 | // SwiftUI有一个专用的PasteBUtton视图,科技让我们接收任何符合Transferable协议的数据,比如String和Data 9 | import SwiftUI 10 | 11 | struct FFPasteData: View { 12 | @State private var username = "@twostraws" 13 | var body: some View { 14 | VStack { 15 | TextField("Username", text: $username) 16 | .textFieldStyle(.roundedBorder) 17 | 18 | PasteButton(payloadType: String.self) { strings in 19 | guard let first = strings.first else { return } 20 | username = first 21 | } 22 | .buttonBorderShape(.capsule) 23 | } 24 | .padding() 25 | } 26 | } 27 | 28 | #Preview { 29 | FFPasteData() 30 | } 31 | -------------------------------------------------------------------------------- /FFModifier/008 - TapAndGestures/FFContentShape.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFContentShape.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/3. 6 | // 7 | // 如何使用contentShape()控制视图的可点击区域。 8 | // 如果你讲点击手势添加到原始的SwiftUI视图(文本或图像),则整个视图将变得可点击。如果你将点击手势添加到SwiftUI的容器视图(VStack或HStack),那么SwiftUI只会将手势添加到容器中包含内容的部分-Stack的大部分将无法点击。 9 | // 如果你想改变点击的区域,可以使用contengShape()修饰符和你想要的形状。 10 | import SwiftUI 11 | 12 | struct FFContentShape: View { 13 | var body: some View { 14 | //例如,此代码创建一个包含图像、间隔和一些文本的VStack,然后使用contentShape()修饰符使整个stack可点击,而不仅仅是图像和文本。 15 | VStack { 16 | Image(systemName: "person.circle") 17 | .resizable() 18 | .frame(width: 50, height: 50) 19 | Spacer() 20 | .frame(height: 50) 21 | Text("Meta BBlv") 22 | } 23 | .contentShape(Rectangle()) 24 | .onTapGesture { 25 | print("Show details for user") 26 | } 27 | 28 | } 29 | } 30 | 31 | #Preview { 32 | FFContentShape() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/008 - TapAndGestures/FFDisableTaps.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFDisableTaps.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/3. 6 | // 7 | // 如何使用allowsHitTexting()禁用视图的点击 8 | // SwiftUI可以使用allowedHitTesting()修饰符阻止视图接收任何类型的点击。如果视图不允许进行命中测试,则任何点击都会自动继续穿过测图,到达其后面的任何内容。 9 | import SwiftUI 10 | 11 | struct FFDisableTaps: View { 12 | var body: some View { 13 | ZStack { 14 | Button("Tap me") { 15 | print("Button was tapped") 16 | } 17 | .frame(width: 100, height: 100) 18 | .background(.gray) 19 | 20 | Rectangle() 21 | .fill(.green.opacity(0.2)) 22 | .frame(width: 300, height: 300) 23 | .clipShape(Circle()) 24 | .allowsHitTesting(false) 25 | } 26 | //尽管矩形位于按钮的上面,但它设置了allowsTightening(false)-矩形上的任何点击都不会被矩形捕获,而是传递到下面的按钮。 27 | //当你想要用另外一个视图突出显示一个视图时,这种效果非常有用-上面的绿色圆圈可能时点击此处开始的教程的一部分,如果圆圈本身抓住了点击,则该效果将不起作用 28 | } 29 | } 30 | 31 | #Preview { 32 | FFDisableTaps() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/008 - TapAndGestures/FFGestureOnTap.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFGestureOnTap.swift 3 | // FFModifier 4 | // 5 | // Created by 小B同学 on 2023/8/3. 6 | // 7 | // 如何检测视图中的tap insert位置 8 | // SwiftUI中有一个onTapGesture()变量,可以检测点击的确切位置,无论是相对于视图的边界还是在整个屏幕的全局位置。 9 | 10 | 11 | import SwiftUI 12 | 13 | struct FFGestureOnTap: View { 14 | var body: some View { 15 | //例如,显示一个红色的圆圈,打印他收到的任何点击的相对位置。 16 | Circle() 17 | .fill(.green) 18 | .frame(width: 100, height: 100) 19 | .onTapGesture { location in 20 | print("Tapped at \(location)") 21 | } 22 | //相对位置是指相对一圆圈的边界--由于圆圈的大小为100*100,如果你点击的中心,无论圆圈防止在屏幕上的任何位置,都会打印50 23 | //如果你想要全局位置--即相对于屏幕左上角的位置,你应该这样添加参数,coordinateSpace 24 | Circle() 25 | .fill(.blue) 26 | .frame(width: 100,height: 100) 27 | .onTapGesture(coordinateSpace: .global) { location in 28 | print("Tapped at \(location)") 29 | } 30 | //此onTapGesture在iOS16以及更高版本可用,如果你想在早起版本上做类似的事情。可以通过包装UIKit实现。 31 | } 32 | } 33 | 34 | #Preview { 35 | FFGestureOnTap() 36 | } 37 | -------------------------------------------------------------------------------- /FFModifier/008 - TapAndGestures/FFGestureReadTapOrDouble.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFGestureReadTapOrDouble.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/3. 6 | // 7 | // 如何读取单击和双击手势 8 | // 任何SwiftUI视图都可以附加Tap操作,并且可以指定在触发操作之前应接受多少次点击 9 | import SwiftUI 10 | 11 | struct FFGestureReadTapOrDouble: View { 12 | var body: some View { 13 | List { 14 | //单击 15 | Text("Tap me!") 16 | .onTapGesture { 17 | print("Tapped!") 18 | } 19 | //双击 20 | Image(.filletSteak) 21 | .onTapGesture(count: 2, perform: { 22 | print("Double Tapped!") 23 | }) 24 | } 25 | } 26 | } 27 | 28 | #Preview { 29 | FFGestureReadTapOrDouble() 30 | } 31 | -------------------------------------------------------------------------------- /FFModifier/008 - TapAndGestures/FFGestureSequenced.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFGestureSequenced.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/3. 6 | // 7 | // 如何使用sequenced(before:)创建手势链 8 | // SwiftUI可以从其他手势中创建新手势,这使得我们仅在两个手势连续出现时才触发操作,例如,用户拖动视图然后长按它。 9 | // 由于排序视图需要能够互相引用,因此你无法真正的将它们创建为视图的属性。相反,直接在body属性内创建它们,然后使用FirstGesture.sequenced(before:secondaryGesture)将两者链接在一起形成一个手势。 10 | 11 | import SwiftUI 12 | 13 | struct FFGestureSequenced: View { 14 | @State private var message = "Long press then drag" 15 | 16 | var body: some View { 17 | //拖动文本之前长按 18 | let longPress = LongPressGesture() 19 | .onChanged { _ in 20 | message = "Now drag me" 21 | } 22 | 23 | let drag = DragGesture() 24 | .onEnded { _ in 25 | message = "Success" 26 | } 27 | 28 | let combined = longPress.sequenced(before: drag) 29 | 30 | Text(message) 31 | .gesture(combined) 32 | //在手势发生时时同步Text。 33 | } 34 | } 35 | 36 | #Preview { 37 | FFGestureSequenced() 38 | } 39 | -------------------------------------------------------------------------------- /FFModifier/008 - TapAndGestures/FFSimultaneousGesture.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFSimultaneousGesture.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/3. 6 | // 7 | // 如何使用simultaneousGesture()同时识别两个手势 8 | // 默认情况下,SwiftUI一次只会触发一个手势操作,通常时层次结构中最前面的视图。子视图优先于父视图,如果想覆盖此行为同时触发两个手势,则应在创建第二个以及后续手势时使用synchronousGesture() 9 | 10 | import SwiftUI 11 | 12 | struct FFSimultaneousGesture: View { 13 | var body: some View { 14 | VStack { 15 | Circle() 16 | .fill(.blue) 17 | .frame(width: 200,height: 200) 18 | .onTapGesture { 19 | print("Circle Tapped!") 20 | } 21 | } 22 | .simultaneousGesture( 23 | TapGesture() 24 | .onEnded({ _ in 25 | print("VStack Tapped!") 26 | }) 27 | ) 28 | //你应该将synchronousGesture()与不会执行的手势一起使用,否则他将无法工作。因此,在示例中,使用带有源泉的simultaneousGesture()和带有VStack的简单onTapGesture,仍然会打印CircleTapped,他不会同时打印。 29 | } 30 | } 31 | 32 | #Preview { 33 | FFSimultaneousGesture() 34 | } 35 | -------------------------------------------------------------------------------- /FFModifier/009 - AdvancedState/FFConstantBindings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFConstantBindings.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/5. 6 | // 7 | // 如何创建常量绑定 8 | // 当制作一些UI时,或者只需要传递一个值给SwiftUI与来一些有意义的东西来展示时,使用常量绑定很有帮助,硬编码的值不会改变,但仍然可以向常规绑定一样使用。 9 | // 例如,如果想创建一个切换开关,通常需要创建一个@State属性来保存bool值,然后在创建时将其发送到切换开关中,然而,如果只是在原型化界面,可以使用常量绑定 10 | 11 | import SwiftUI 12 | 13 | struct FFConstantBindings: View { 14 | var body: some View { 15 | Toggle(isOn: .constant(true), label: { 16 | Text("Show advanced options") 17 | }) 18 | //这个开关是只读的,并且总是打开的,因为这就是使用了常量绑定,在后面接入实际数据时使用@State属性来替换他。 19 | //这些常量绑定有各种类型,bool、string、int等,SwiftUI会确保为每种视图类型使用正确的绑定。 20 | } 21 | } 22 | 23 | #Preview { 24 | FFConstantBindings() 25 | } 26 | -------------------------------------------------------------------------------- /FFModifier/010 - Lists/FFList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFList.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/7. 6 | // 什么是List? 7 | // SwiftUI的列表视图类似于UITableView,它可以根据你的需要显示静态的表格视图单元格。使用更加简单,不需要通过Storyboard或者在代码中register,也不需要告诉它有多少行,也不需要去手动排列和配置cell 8 | // 相反,SwiftUI的列表是为可组合性而设计的--设计成能够从小的东西构建更大的东西。所以,SwiftUI没有一个大的视图控制器,而是通过构建小的视图,它们知道如何将自己配置为列表行。 9 | //就代码大小而言,如果不考虑其他因素,差异是惊人的--你可以删除几乎所有的表视图代码,但仍然能得到你习惯的那种很棒的外观和感觉。 10 | 11 | import SwiftUI 12 | 13 | struct FFList: View { 14 | var body: some View { 15 | List { 16 | Text("Hello, World!") 17 | } 18 | } 19 | } 20 | 21 | #Preview { 22 | FFList() 23 | } 24 | -------------------------------------------------------------------------------- /FFModifier/010 - Lists/FFListEditButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFListEditButton.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/7. 6 | // 7 | // 如何使用EditButton对list进行编辑 8 | // 如果已经配置了一个SwiftUI列表视图来支持删除或编辑它的项目,允许可以在某处添加一个EditButton来开启list视图的编辑模式。 9 | 10 | import SwiftUI 11 | 12 | struct FFListEditButton: View { 13 | @State private var users = ["BBLv", "Taylor", "Paul"] 14 | var body: some View { 15 | NavigationStack { 16 | List { 17 | ForEach(users, id: \.self) { user in 18 | Text(user) 19 | } 20 | .onDelete(perform: { indexSet in 21 | users.remove(atOffsets: indexSet) 22 | }) 23 | } 24 | .toolbar(content: { 25 | EditButton() 26 | }) 27 | } 28 | } 29 | } 30 | 31 | #Preview { 32 | FFListEditButton() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/010 - Lists/FFListForEach.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFListForEach.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/8. 6 | // 7 | // 如何创建一个列表或从ForEach绑定 8 | // SwiftUI可以直接从绑定中创建List或ForEach,然后提供内容闭包,并为我们显示的数据几乎中的每个元素提供单独的绑定。当你为每个项目显示的内容需要绑定到他的一些数据时,。 9 | // 要使用这种方法,直接将绑定传递到列表中, 10 | 11 | import SwiftUI 12 | 13 | struct UserA: Identifiable { 14 | let id = UUID() 15 | let name: String 16 | var isContacted = false 17 | } 18 | 19 | struct FFListForEach: View { 20 | @State private var users = [ 21 | UserA(name: "Taylor"), 22 | UserA(name: "Justin"), 23 | UserA(name: "Adele") 24 | ] 25 | var body: some View { 26 | List($users) { $user in 27 | HStack { 28 | Text(user.name) 29 | Spacer() 30 | Toggle("User has been contacted", isOn: $user.isContacted) 31 | .labelsHidden() 32 | } 33 | } 34 | } 35 | //以这种方式使用绑定是修改列表的最有效方式,因为他不会在只有一个项更改时导致整个视图重新加载 36 | } 37 | 38 | #Preview { 39 | FFListForEach() 40 | } 41 | -------------------------------------------------------------------------------- /FFModifier/010 - Lists/FFListImplicitStacking.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFListImplicitStacking.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/8. 6 | // 7 | // 如何使用隐式堆叠 8 | // 如何创建一个动态列表并在每行中放置多个内容,会发生什么情况?SwiftUI的解决方案简单、灵活,并且在默认的情况下为我们提供了很好的行为:它创建了一个隐式的HStack来容纳你的项目,因此他们会自动横向布局。 9 | // 在iOS17beta2上未实现隐式堆叠, 10 | 11 | import SwiftUI 12 | 13 | struct FFUser: Identifiable { 14 | let id = UUID() 15 | let username = "Anonymous" 16 | } 17 | 18 | struct FFListImplicitStacking: View { 19 | let users = [FFUser(),FFUser(),FFUser()] 20 | 21 | var body: some View { 22 | 23 | List(users) { user in 24 | HStack { 25 | Image(.chincoteague) 26 | .resizable() 27 | .frame(width: 40, height: 40) 28 | Text(user.username) 29 | } 30 | } 31 | } 32 | } 33 | 34 | #Preview { 35 | FFListImplicitStacking() 36 | } 37 | -------------------------------------------------------------------------------- /FFModifier/010 - Lists/FFListInsetGroup.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFListInsetGroup.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/7. 6 | // 7 | // 如何创建分组和插入分组列表 8 | // SwiftUI的列表视图有一个listStyle()修饰符来控制list的样式,grouped来获得old-style分组,.insetgrouped获得newer-style的分组 9 | 10 | import SwiftUI 11 | 12 | struct ExampleRow: View { 13 | var body: some View { 14 | Text("Example Row") 15 | } 16 | } 17 | 18 | struct FFListInsetGroup: View { 19 | var body: some View { 20 | //.grouped 21 | List { 22 | Section { 23 | ExampleRow() 24 | ExampleRow() 25 | ExampleRow() 26 | } header: { 27 | Text("Examples") 28 | } 29 | } 30 | .listStyle(.grouped) 31 | 32 | //insetGrouped 33 | List(0..<100) { i in 34 | Text("Row \(i)") 35 | } 36 | .listStyle(.insetGrouped) 37 | } 38 | } 39 | 40 | #Preview { 41 | FFListInsetGroup() 42 | } 43 | -------------------------------------------------------------------------------- /FFModifier/010 - Lists/FFListRowIndividual.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFListRowIndividual.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/8. 6 | // 7 | // 如何更改耽搁list-row的颜色 8 | // SwiftUI有一个专用的listItmeTine修饰符来控制列表如何为其行上色。具体的行为取决于你的app运行在哪个平台上,代码一致 9 | 10 | import SwiftUI 11 | 12 | struct FFListRowIndividual: View { 13 | var body: some View { 14 | /** 15 | 就像我说的,这取决于平台: 16 | 17 | 在iOS上,图标会变成红色和绿色,而文字则保持原色。 18 | 在macOS上,它还会将图标更改为红色和绿色,覆盖用户首选的强调色。 19 | 在watchOS上,这将改变行背景颜色(称为“背景盘”)为红色或绿色。 20 | 在tvOS上,它什么也做不了。 21 | 在macOS上,你可以尊重用户的强调色,同时也可以添加你自己喜欢的列表行色调,像这样: 22 | */ 23 | List(1..<51) { i in 24 | Label("Row \(i)", systemImage: "\(i).circle") 25 | .listItemTint(.preferred(i.isMultiple(of: 2) ? .red : .green)) 26 | } 27 | } 28 | } 29 | 30 | #Preview { 31 | FFListRowIndividual() 32 | } 33 | -------------------------------------------------------------------------------- /FFModifier/010 - Lists/FFListSelectionRow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFListSelectionRow.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/8. 6 | // 7 | // SwiftUI的list支持多选,但仅限于编辑模式之下。为了支持多选,首先添加一个与列表中使用的类型相同的可选属性集合。例如,如果一个整数list,那么将有一个可选的Int。使用他的选择参数将它传递给list,确保list处于编辑模式。 8 | 9 | import SwiftUI 10 | 11 | struct FFListSelectionRow: View { 12 | @State private var selection = Set() 13 | let names = ["BBLv", "Cyril", "Lana", "Mallory", "Sterling"] 14 | 15 | var body: some View { 16 | NavigationStack { 17 | List(names, id: \.self, selection: $selection) { name in 18 | Text(name) 19 | } 20 | .navigationTitle("List Selection") 21 | .toolbar { 22 | EditButton() 23 | } 24 | } 25 | } 26 | } 27 | 28 | #Preview { 29 | FFListSelectionRow() 30 | } 31 | -------------------------------------------------------------------------------- /FFModifier/010 - Lists/FFListSeparator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFListSeparator.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/8. 6 | // 7 | // 如何调整list行分隔符的可见性和颜色 8 | // SwiftUI提供了两个修饰符来控制其列表中行分隔符的外观,特别是listRowSeparator()用于控制行分隔符是否可见,listRpwSeparator()用于控制分隔符的颜色。 9 | 10 | import SwiftUI 11 | 12 | struct FFListSeparator: View { 13 | var body: some View { 14 | //隐藏行分隔符 15 | List { 16 | ForEach(1..<100) { index in 17 | Text("Row \(index)") 18 | .listRowSeparator(.hidden) 19 | } 20 | } 21 | //设置分隔符颜色 22 | List { 23 | ForEach(1..<100) { index in 24 | Text("Row \(index)") 25 | .listRowSeparatorTint(.red) 26 | } 27 | } 28 | } 29 | } 30 | 31 | #Preview { 32 | FFListSeparator() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/010 - Lists/FFListStaticitems.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFListStaticitems.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/7. 6 | // 7 | // 如何创建一个静态项目列表 8 | // 要创建项目的静态列表,首先要定义列表中每一行应该是什么样子。这是一个与其他视图一样的视图,并且可以为你打算在行中显示的数据提供任何参数。一旦有了行,就可以创建一个List视图,该视图可以根据需要创建任意多的行 9 | 10 | import SwiftUI 11 | 12 | struct Pizzeria: View { 13 | let name: String 14 | 15 | var body: some View { 16 | Text("Restaurant: \(name)") 17 | } 18 | } 19 | 20 | struct FFListStaticitems: View { 21 | var body: some View { 22 | //例如,定义一个Pizzeria视图,它将显示一个名称字符串,然后将其用作带有三个固定数据快的Lists的一行。 23 | List { 24 | Pizzeria(name: "Joe's Original") 25 | Pizzeria(name: "The Real Joe's Original") 26 | Pizzeria(name: "Original Joe's") 27 | } 28 | } 29 | } 30 | 31 | #Preview { 32 | FFListStaticitems() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/010 - Lists/SwiftListListRowBackground.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftListListRowBackground.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/7. 6 | // 7 | // 如何使用listRowBackground()设置list-row的背景颜色 8 | // SwiftUI有一个专门的修饰符来设置list-row的背景视图,是listRowBackground。它接受任何类型的视图--包括颜色、图像和形状 9 | 10 | import SwiftUI 11 | 12 | struct SwiftListListRowBackground: View { 13 | var body: some View { 14 | List { 15 | ForEach(0..<10) { 16 | Text("Row \($0)") 17 | } 18 | .listRowBackground(Color.green) 19 | } 20 | } 21 | } 22 | 23 | #Preview { 24 | SwiftListListRowBackground() 25 | } 26 | -------------------------------------------------------------------------------- /FFModifier/011 - Forms/FFFormDesign.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFFormDesign.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/9. 6 | // 基于表单设计 7 | // SwiftUI的From像容器一样工作,就像HStack和VStack一样,这意味着你可以根据需要在其中添加其他视图。但是,它们会自动调整某些控件的行为和样式,以便更好的适应表单环境 8 | 9 | import SwiftUI 10 | 11 | struct FFFormDesign: View { 12 | @State private var enableLogging = false 13 | @State private var selectedColor = "Red" 14 | @State private var colors = ["Red", "Green", "Blue"] 15 | 16 | var body: some View { 17 | //例如,创建一个带有开关、分段控件和按钮的表单。 18 | Form { 19 | Picker("Select a color", selection: $selectedColor) { 20 | ForEach(colors, id: \.self) { 21 | Text($0) 22 | } 23 | } 24 | .pickerStyle(.segmented) 25 | 26 | Toggle("Enable Logging", isOn: $enableLogging) 27 | 28 | Button("Save changes") { 29 | print("Help me!") 30 | } 31 | } 32 | } 33 | } 34 | 35 | #Preview { 36 | FFFormDesign() 37 | } 38 | -------------------------------------------------------------------------------- /FFModifier/011 - Forms/FFFormDisablingElements.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFFormDisablingElements.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/10. 6 | // 7 | // 启用和禁用表单中的元素 8 | // 通过使用disable()修饰符,可以禁用form的任何section,甚至整个form。接受一个bool值,用来定义元素是否应该被禁用。form的element的样式会自动更新,以反映其状态--例如,按钮和开关会变灰。 9 | 10 | import SwiftUI 11 | 12 | struct FFFormDisablingElements: View { 13 | @State private var agreedToTerms = false 14 | 15 | var body: some View { 16 | Form { 17 | Section { 18 | Toggle("Agreen to terms and conditions", isOn: $agreedToTerms) 19 | } 20 | Section { 21 | Button("Continue") { 22 | print("Thank you!") 23 | } 24 | .disabled(agreedToTerms == false) 25 | } 26 | //像许多其他SwiftUI修饰符一样,disabled状态是可以解除的,可以附加到section,可以附加到Form,根据需求来决定禁用某一行还是禁用整块区域。 27 | } 28 | } 29 | } 30 | 31 | #Preview { 32 | FFFormDisablingElements() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/011 - Forms/FFFormShowAndHidden.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFFormShowAndHidden.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/10. 6 | // 7 | // 显示和隐藏Form-rows 8 | // SwiftUI允许我们根据需要在表单中添加和删除项目,当你想要根据之前的选项调整可见选项列表时,这一特性可用。 9 | 10 | import SwiftUI 11 | 12 | struct FFFormShowAndHidden: View { 13 | @State private var showingAdvancedOptions = false 14 | @State private var enableLogging = false 15 | 16 | var body: some View { 17 | Form { 18 | Section { 19 | Toggle("Show advanced options", isOn: $showingAdvancedOptions.animation()) 20 | 21 | if showingAdvancedOptions { 22 | Toggle("Enable logging",isOn: $enableLogging) 23 | } 24 | } 25 | } 26 | } 27 | } 28 | 29 | #Preview { 30 | FFFormShowAndHidden() 31 | } 32 | -------------------------------------------------------------------------------- /FFModifier/011 - Forms/FFForms.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFForms.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/9. 6 | // 7 | // Form原理 8 | // Swift坚定的专注于声明式用户界面,因此它为我们提供了一种构建表单的奇妙机制--用于收集信息的用户输入控件集合,比如订单或设置页面。 9 | // 更棒的是,SwiftUI的一些控件会自动适应被放置在表单中,它们的外观和行为会发生变化,因此它们可以更好的与其他输入控件一起工作。 10 | // SwiftUI实际上动态调整布局,可以根据代码运行的平台自动制作全新的UI--它完全理解了控件的目的和视觉效果。这意味着通过描述告诉他想要什么,然后SwiftUI实现在当前平台上 11 | // 表单就像VStack一样的常规容器,可以根据需求在两者之间自由的切换。 12 | 13 | import SwiftUI 14 | 15 | struct FFForms: View { 16 | var body: some View { 17 | Form { 18 | Text("Hello, World!") 19 | } 20 | } 21 | } 22 | 23 | #Preview { 24 | FFForms() 25 | } 26 | -------------------------------------------------------------------------------- /FFModifier/012 - Containers/FFContainer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFContainer.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/11. 6 | // 7 | // Container原理 8 | // SwiftUI被设计成开箱即用,这意味着可以根据需求将一个视图放置在另一个视图中。 9 | // 这在处理我们常用的主要容器视图时尤其有用,比如导航控制器和tabBar控制器。我们可以把任何视图放到另一个容器视图中,SwiftUI会自动调整它的布局, 10 | // 在这方面,SwiftUI自己的容器--NavigationStack、TabView、Group等--与我们用自己的视图组合制作的容器没有什么不同。 11 | 12 | import SwiftUI 13 | 14 | struct FFContainer: View { 15 | var body: some View { 16 | Text("Hello, World!") 17 | } 18 | } 19 | 20 | #Preview { 21 | FFContainer() 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/012 - Containers/FFStatusbarHideAndShow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFStatusbarHideAndShow.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/11. 6 | // 7 | // 如何隐藏和显示状态栏 8 | // 我们可以使用SwiftUI的StatusBar()修饰符隐藏和显示iOS状态栏。它接受一个掩藏参数,该参数必须为true或false,取决于你的需求 9 | 10 | import SwiftUI 11 | 12 | struct FFStatusbarHideAndShow: View { 13 | @State private var hideStatusBar = false 14 | 15 | var body: some View { 16 | //此修饰符仅在iOS上可用 17 | Text("No status bar, Please") 18 | // .statusBar(hidden: false) 19 | //如果你希望状态栏可见性依赖于某些程序状态,使用@state来代替hard-coded。例如,创建一个hideStatusBar的bool值,当按钮被点击时,该bool值会被切换,从而控制状态栏是否显示。 20 | Button("Toggle Status Bar") { 21 | withAnimation { 22 | hideStatusBar.toggle() 23 | } 24 | } 25 | .statusBar(hidden: hideStatusBar) 26 | 27 | //此case由于示例,Text与Button同时设定了statusBar,想要看到Button点击的动态效果,将18行代码注释掉,有干扰。 28 | } 29 | } 30 | 31 | #Preview { 32 | FFStatusbarHideAndShow() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/012 - Containers/FFTabViewBadge.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFTabViewBadge.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/11. 6 | // 7 | // 如何给TabView或List-cell添加一个badge 8 | // SwiftUI的Badge()修饰符允许我们向TabView item视图和list-cell添加数字和文本,目的将用户的注意力吸引到一些弥补状态信息上--例如,TabView上的数字标识未读消息技术 9 | 10 | import SwiftUI 11 | 12 | struct FFTabViewBadge: View { 13 | var body: some View { 14 | TabView { 15 | VStack { 16 | List { 17 | Text("Wi-Fi") 18 | .badge("Lan solo") 19 | Text("Bluetooth") 20 | .badge("On") 21 | } 22 | 23 | // Text("Your home screen here") 24 | } 25 | .tabItem { 26 | Label("Home", systemImage: "house") 27 | } 28 | .badge(5) 29 | } 30 | //badge同样适用于List-cell,并自动以第二种颜色显示为右对齐文本。 31 | } 32 | } 33 | 34 | #Preview { 35 | FFTabViewBadge() 36 | } 37 | -------------------------------------------------------------------------------- /FFModifier/013 - Navigation/FFInspector.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFInspector.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/15. 6 | // 7 | // 如何添加一个检查器在任何View上 8 | // SwiftUi的inspector()修饰符让我们可以在任何需要的地方添加检查器视图。这就像Xcode一样,检查器添加到UI的后面,并且可以根据需要与NavigationSplitView和NavigationStack一起使用。 9 | 10 | import SwiftUI 11 | 12 | struct FFInspector: View { 13 | @State private var isShowingInspector = false 14 | 15 | var body: some View { 16 | //当按钮被按下时,将显示一个检查器视图。 17 | Button("Hello, world!") { 18 | isShowingInspector.toggle() 19 | } 20 | .font(.largeTitle) 21 | .inspector(isPresented: $isShowingInspector) { 22 | Text("Inspector View") 23 | } 24 | //当空间很大时,比如使用全屏的iPad应用程序或macOS时,检查器就放在按钮旁边。然而,当空间有限时,例如在iPhone上,检查器作为一个页面向上滑动。 25 | } 26 | } 27 | 28 | #Preview { 29 | FFInspector() 30 | } 31 | -------------------------------------------------------------------------------- /FFModifier/013 - Navigation/FFInspectorIdeal.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFInspectorIdeal.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/15. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct FFInspectorIdeal: View { 11 | @State private var isShowingInspector1 = false 12 | 13 | var body: some View { 14 | //在支持他的平台上,你可以通过提供一个 (.inspectorColumnWidth(500)) 固定的大小来占用康健,或者通过提供一个(.inspectorColumnWidth(min: 50, ideal: 150, max: 200))范围来调整检查器的占用空间。 15 | 16 | Button("Hi, metaBBLv") { 17 | isShowingInspector1.toggle() 18 | } 19 | .font(.largeTitle) 20 | .inspector(isPresented: $isShowingInspector1) { 21 | Text("Insepctor View BBlv") 22 | .inspectorColumnWidth(min:50, ideal: 150, max: 200) 23 | } 24 | } 25 | } 26 | 27 | #Preview { 28 | FFInspectorIdeal() 29 | } 30 | -------------------------------------------------------------------------------- /FFModifier/013 - Navigation/FFNavigation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFNavigation.swift 3 | // FFModifier 4 | // 5 | // Created by 小B同学 on 2023/8/13. 6 | // 7 | // Navigation描述 8 | 9 | /**导航是许多应用程序的核心,SwiftUI的简单、易用的方面在Navigation上做的非常好,这意味着使用NavigationLink、使用NavigationPath完全控制导航,使用NavigationSplitcView支持第二视图和第三视图布局等。 10 | 这意味着很多时候可以忽略Navigation相关的场景,因为非常简单,专注于需要更多思考的部分,例如: 11 | - 制作具有合理默认值的可自定义的toolbar 12 | - 通过状态恢复保存和加载用户的导航 13 | - 决定如何显示侧边栏,或在需要时添加额外的Content视图 14 | - 结合NavigationSplitView和NavigationStack获得想要的结构 15 | */ 16 | 17 | import SwiftUI 18 | 19 | struct FFNavigation: View { 20 | var body: some View { 21 | NavigationStack { 22 | List { 23 | NavigationLink("最简单的Navigation") { 24 | Text("So easy") 25 | } 26 | } 27 | .navigationTitle("Navigation") 28 | } 29 | } 30 | } 31 | 32 | #Preview { 33 | FFNavigation() 34 | } 35 | -------------------------------------------------------------------------------- /FFModifier/013 - Navigation/FFNavigationEdit.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFNavigationEdit.swift 3 | // FFModifier 4 | // 5 | // Created by 小B同学 on 2023/8/13. 6 | // 7 | // 如何让用户编辑您的导航标题 8 | // SwiftUI的NavigationStack可以使用navigationTitle()显示一个简单的字符串,但同一修饰符也可接受字符串绑定,以便用户可以通过点击来编辑标题 9 | //重要信息:只有当导航栏以内联模式运行时,导航标题编辑才有效。据我所知,它仅适用于iOS和iPadOS 10 | 11 | import SwiftUI 12 | 13 | struct FFNavigationEdit: View { 14 | @State private var title = "Wecome" 15 | var body: some View { 16 | //例如,显示“欢迎”的默认标题,用户可以点击该标题进行更改。 17 | NavigationStack { 18 | Text("Hello, World!") 19 | .navigationTitle($title) 20 | .navigationBarTitleDisplayMode(.inline) 21 | 22 | //如果你的标题在哪里,因为它代表了你的用户正在编辑某些内容的名称,我建议添加.toolvarRole(.editor)以便你的标题向其他文档标题一样与前沿对其。 23 | .toolbarRole(.editor) 24 | } 25 | } 26 | } 27 | 28 | #Preview { 29 | FFNavigationEdit() 30 | } 31 | -------------------------------------------------------------------------------- /FFModifier/013 - Navigation/FFNavigationSplitView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFNavigationSplitView.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/15. 6 | // 7 | // 如何创建一个两列或三列布局用NavigatinSplitView 8 | // SwiftUI的NavigationSplitView允许我们在更大的设备上创建多列布局(iPad macOS和大屏幕的iPhone上),但是当空间有限时,将自动折叠成NavigationStack风格的布局。 9 | // 在最简单的形式中,你应该提供侧边栏作为它的第一个尾随闭包,你的细节视图作为他的第二个闭包。 10 | 11 | import SwiftUI 12 | 13 | struct FFNavigationSplitView: View { 14 | var body: some View { 15 | NavigationSplitView { 16 | List(1..<50) { i in 17 | NavigationLink("Row \(i)", value: i) 18 | } 19 | .navigationDestination(for: Int.self) { 20 | Text("Select row \($0)") 21 | } 22 | .navigationTitle("Split View") 23 | } detail: { 24 | Text("Please select a row") 25 | } 26 | //在该代码中,“Please select a row”文本仅在用户尚未在侧边栏中进行选择时显示,但是当用户进行选择时,它将自动被替换-navigationDestination()修饰符将自动在详细信息区域中显示其目的地视图。更棒的是,当空间有限时,你会看到整个东西被平展成一个常规的NavigationStack,这样你就可以两全其美了。 27 | 28 | } 29 | } 30 | 31 | #Preview { 32 | FFNavigationSplitView() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/013 - Navigation/FFNavigationSplitViewCompact.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFNavigationSplitViewCompact.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/15. 6 | // 7 | // 如何控制哪个NavigationSplitView列显示在紧凑的布局 8 | // 当你有一个NavigationSplitView运行在一个紧凑的size class中,当你的应用程序被调整到一个小的size--SwiftUI试图猜测你的分屏视图列中哪一个是最好的显示,这种猜测通常是正确的,但你可以通过分屏视图设置首选紧凑列来控制它。 9 | 10 | import SwiftUI 11 | 12 | struct FFNavigationSplitViewCompact: View { 13 | @State private var preferredColumn = NavigationSplitViewColumn.detail 14 | var body: some View { 15 | //例如:这段代码强制将detail视图列为首选,从而覆盖了SwiftUI的默认选择 16 | NavigationSplitView(preferredCompactColumn: $preferredColumn) { 17 | Text("Sidebar View") 18 | } detail: { 19 | Text("Detail View") 20 | } 21 | //如果你提供了一个不存在的值--比如,当你只有sidebar和detail,你让他选择content--那么SwiftUI就会选择侧边栏。 22 | } 23 | } 24 | 25 | #Preview { 26 | FFNavigationSplitViewCompact() 27 | } 28 | -------------------------------------------------------------------------------- /FFModifier/013 - Navigation/FFNavigationSplitViewContent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFNavigationSplitViewContent.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/15. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct FFNavigationSplitViewContent: View { 11 | var body: some View { 12 | //如果你想更近一步,NavigationSplitView允许我们在他的布局中添加第三个视图,它可以通过点击Button来显示。 13 | NavigationSplitView { 14 | Text("Sidebar") 15 | } content: { 16 | Text("Primary") 17 | } detail: { 18 | Text("Detail View") 19 | } 20 | //SwiftUI将自动显示一个按钮滑动在你的栏从屏幕的一边,也折叠它与你的猪视图,如果你在一个紧凑的大小类。 21 | } 22 | } 23 | 24 | #Preview { 25 | FFNavigationSplitViewContent() 26 | } 27 | -------------------------------------------------------------------------------- /FFModifier/013 - Navigation/FFNavigationSplitViewCustomize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFNavigationSplitViewCustomize.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/15. 6 | // 7 | // 如何在NavigationSplitView中自定义一个视图的宽度 8 | // SwiftUI的NavigationSplitView为它呈现的视图使用系统标准宽度,但是通过navigationSPlitViewColumnWidth()修饰符,你可以尝试自定义它。 9 | // 注意:系统可以选择忽略你指定的宽度。在编写文本时,此修饰符在iPhone上被忽略,而在iPad上仅适用于小于默认大小的值。 10 | // 在其最简单的形式,发送一个单一的值给navigationSplitViewColumnWidth()导致它使用一个固定的大小,没有更小火更大。 11 | 12 | import SwiftUI 13 | 14 | struct FFNavigationSplitViewCustomize: View { 15 | var body: some View { 16 | NavigationSplitView { 17 | Text("Sidebar") 18 | .navigationSplitViewColumnWidth(100) 19 | } content: { 20 | Text("Content") 21 | .navigationSplitViewColumnWidth(200) 22 | } detail: { 23 | Text("Detail") 24 | } 25 | 26 | } 27 | } 28 | 29 | #Preview { 30 | FFNavigationSplitViewCustomize() 31 | } 32 | -------------------------------------------------------------------------------- /FFModifier/013 - Navigation/FFNavigationSplitViewCustomizeMax.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFNavigationSplitViewCustomizeMax.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/15. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct FFNavigationSplitViewCustomizeMax: View { 11 | var body: some View { 12 | //然而,如果你愿意允许灵活性-如果你的平台支持它,现在可能只是macOS-你可以提供最小,最理想和最大的尺寸 13 | NavigationSplitView { 14 | Text("Sidebar") 15 | .navigationSplitViewColumnWidth(min:100, ideal: 200, max: 300) 16 | } content: { 17 | Text("Content") 18 | .navigationSplitViewColumnWidth(min:100, ideal: 200, max: 300) 19 | } detail: { 20 | Text("Detail") 21 | } 22 | 23 | } 24 | } 25 | 26 | #Preview { 27 | FFNavigationSplitViewCustomizeMax() 28 | } 29 | -------------------------------------------------------------------------------- /FFModifier/013 - Navigation/FFNavigationSplitViewDisplayMode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFNavigationSplitViewDisplayMode.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/15. 6 | // 7 | // 如何自定义NavigationSplitView的显示模式 8 | // SwiftUI的NavigationSplitView有三个选项来控制侧面栏的显示方式,每个选项都可以使用navigationSplitViewStyle()修饰符进行调整。 9 | // 10 | import SwiftUI 11 | 12 | struct FFNavigationSplitViewDisplayMode: View { 13 | var body: some View { 14 | //第一个是.prominentDetail,它告诉SwiftUI你想让细节视图一直保持完整的大小--侧边栏和内容视图会滑动到Detail视图上,而不是把他推到一边或把它挤得更小。 15 | NavigationSplitView { 16 | Text("Sidebar") 17 | } content: { 18 | Text("Content") 19 | } detail: { 20 | Text("Detail") 21 | } 22 | .navigationSplitViewStyle(.prominentDetail) 23 | 24 | //第二个选项是.balanced,这将在显示侧边栏或Content栏时减少Detail视图的大小--只需将.prominentDetail切换为.balance 25 | 26 | } 27 | } 28 | 29 | #Preview { 30 | FFNavigationSplitViewDisplayMode() 31 | } 32 | -------------------------------------------------------------------------------- /FFModifier/013 - Navigation/FFNavigationSplitViewDisplayModeBalance.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFNavigationSplitViewDisplayModeBalance.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/15. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct FFNavigationSplitViewDisplayModeBalance: View { 11 | var body: some View { 12 | //第二个选项是.balanced,这将在显示侧边栏或Content栏时减少Detail视图的大小--只需将.prominentDetail切换为.balance 13 | NavigationSplitView { 14 | Text("Sidebar") 15 | } content: { 16 | Text("Content") 17 | } detail: { 18 | Text("Detail") 19 | } 20 | .navigationSplitViewStyle(.balanced) 21 | 22 | 23 | //默认设置是.automatic,这将根据平台的不同而有所不同,在写Text是,在iPhone上变成了.prominentDetail,在iPad上变成.balance 24 | } 25 | } 26 | 27 | #Preview { 28 | FFNavigationSplitViewDisplayModeBalance() 29 | } 30 | -------------------------------------------------------------------------------- /FFModifier/014 - AlertsAndMenus/FFAlertAddAction.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFAlertAddAction.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/16. 6 | // 7 | // Alert-Button如何添加action 8 | 9 | import SwiftUI 10 | 11 | struct FFAlertAddAction: View { 12 | @State private var shwoingAlert = false 13 | 14 | var body: some View { 15 | //你经常需要将操作附加到Button上,一边在点击按钮时执行特定的操作,要做到这一点,给你的按钮附加一个闭包,当他被点击时将被调用。 16 | Button("Show Alert") { 17 | shwoingAlert = true 18 | } 19 | .alert(isPresented: $shwoingAlert) { 20 | Alert(title: Text("你确定要删除数据吗?"), message: Text("这是一个不可逆操作。"), primaryButton: .destructive(Text("删除"), action: { 21 | print("正在删除") 22 | }), secondaryButton: .cancel(Text("取消"))) 23 | } 24 | //如果要添加两个以上的Button,使用Sheet 25 | } 26 | } 27 | 28 | #Preview { 29 | FFAlertAddAction() 30 | } 31 | -------------------------------------------------------------------------------- /FFModifier/014 - AlertsAndMenus/FFAppStroeOverlay.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFAppStroeOverlay.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/16. 6 | // 7 | // 如何使用appStoreOverlay()推荐另一个应用。 8 | // SwiftUI给了我们一个专门的修改器,可以推荐AppStore上的其他应用,这是一个很好的交叉消失的方式。如果你使用的是App Clips,这一点尤其有用,一旦用户完成了主要操作,你就可以从App Clips中推荐完整的应用。 9 | // 这个修饰符需要一些状态来观察,这将决定App Store覆盖是否激活,以及SDKOverlay。确定要推荐哪个应用程序AppConfiguration。 10 | // 重要:appStoreOverlay在macOS上不可用 11 | // 例如,当按钮被按下时,它会推荐一个特定的App 12 | 13 | import SwiftUI 14 | import StoreKit 15 | 16 | struct FFAppStroeOverlay: View { 17 | @State private var showRecommended = false 18 | 19 | var body: some View { 20 | Button("Show Recommended App") { 21 | showRecommended.toggle() 22 | } 23 | .appStoreOverlay(isPresented: $showRecommended) { 24 | SKOverlay.AppConfiguration(appIdentifier: "1440611372", position: .bottom) 25 | } 26 | //需要导入StoreKit框架来使用SKOverlay。 27 | } 28 | } 29 | 30 | #Preview { 31 | FFAppStroeOverlay() 32 | } 33 | -------------------------------------------------------------------------------- /FFModifier/014 - AlertsAndMenus/FFMenuPick.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFMenuPick.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/16. 6 | // 7 | // 如何让用具从菜单中选择option 8 | // SwiftUI的Picker视图有一个名为.munu的专用样式,它显示了一个弹出式菜单的选项,选择器的标签显示为一个可点击的按钮。菜单本身将在当前选择的选项旁边自动显示一个复选标记,并可以根据选择器在屏幕上的位置向上或向下显示。 9 | 10 | import SwiftUI 11 | 12 | struct FFMenuPick: View { 13 | @State private var selection = "Red" 14 | let colors = ["Red", "Green", "Blue", "Black", "Tartan"] 15 | 16 | var body: some View { 17 | VStack { 18 | Picker("Select a paint color", selection: $selection) { 19 | ForEach(colors, id: \.self) { 20 | Text($0) 21 | } 22 | } 23 | .pickerStyle(.menu) 24 | 25 | Text("Selected color: \(selection)") 26 | } 27 | } 28 | } 29 | 30 | #Preview { 31 | FFMenuPick() 32 | } 33 | -------------------------------------------------------------------------------- /FFModifier/014 - AlertsAndMenus/FFPresentations.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFPresentations.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/16. 6 | // 关于Presentations 7 | // SwiftUI的声明式编程思想意味着我们不会像在UIKit中那样创建和呈现警报和动作表。相反,我们定义了他们应该显示的条件,告诉它他们应该是什么样子,然后让他自己决解剩下的问题。 8 | // 这都是使用修饰符完成的,修饰符将新的UI附加到我们的视图中,当满足条件时将显示该视图。你可以随意的添加,它们实际上是等待,直到他们饿条件成真,此时他们会显示自己的UI。例如,你可以在按下按钮时切换bool值,浙江出发警报。 9 | // 你可以将presentations附加到你的主视图或他的任何子视图,甚至是调整你的状态以触发presentations的按钮。这是一个微妙的区别,但重要的是要理解,这些present不是附加到按钮,因为它是一个按钮。也就是说,这不会以任何方式使警报显示,因为按钮被点击。相反,我们将它附加到我们的视图层次结构,一边SwiftUI知道它可能在任何时候显示。 10 | 11 | import SwiftUI 12 | 13 | struct FFPresentations: View { 14 | var body: some View { 15 | Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) 16 | } 17 | } 18 | 19 | #Preview { 20 | FFPresentations() 21 | } 22 | -------------------------------------------------------------------------------- /FFModifier/015 - PresentingViews/FFContentUnavailable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFContentUnavailable.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/18. 6 | // 7 | // 如何展示白画面的占位图 8 | // SwiftUI有一个专用的ContentUnavailableView视图,在没有数据的时候向用户展示非空画面。例如,在用户执行了搜索操作之后,并未搜索到内容,使用此View 9 | 10 | import SwiftUI 11 | 12 | struct FFContentUnavailable: View { 13 | var body: some View { 14 | //默认提供一个放大镜图标,有标题和副标题构成,用来展示用户并为搜索到具体内容 15 | ContentUnavailableView.search 16 | } 17 | } 18 | 19 | #Preview { 20 | FFContentUnavailable() 21 | } 22 | -------------------------------------------------------------------------------- /FFModifier/015 - PresentingViews/FFContentUnavailableCustom.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFContentUnavailableCustom.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/18. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct FFContentUnavailableCustom: View { 11 | var body: some View { 12 | //如果有需求,可以对齐进行自定义,以添加用户搜索的内容 13 | ContentUnavailableView.search(text: "Life, the Universe, and Everything") 14 | } 15 | } 16 | 17 | #Preview { 18 | FFContentUnavailableCustom() 19 | } 20 | -------------------------------------------------------------------------------- /FFModifier/015 - PresentingViews/FFContentUnavailableCustomAll.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFContentUnavailableCustomAll.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/18. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct FFContentUnavailableCustomAll: View { 11 | var body: some View { 12 | //完全自定义所有的内容 13 | ContentUnavailableView("No favorites", systemImage: "star", description: Text("You don't have any favorites yet.")) 14 | .symbolVariant(.slash) 15 | } 16 | } 17 | 18 | #Preview { 19 | FFContentUnavailableCustomAll() 20 | } 21 | -------------------------------------------------------------------------------- /FFModifier/015 - PresentingViews/FFPresentSheetsMultiple.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFPresentSheetsMultiple.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/17. 6 | // 7 | // Sheets多重present 8 | // 如果你想在SwiftUI中显示多个View页面,通过从第一个View-present第二个视图来实现,不可以将两个sheet()修饰符同时附加到一个父视图上。 9 | // 相反,将一个Sheet()修饰符放在前一个sheet中 10 | 11 | import SwiftUI 12 | 13 | struct FFPresentSheetsMultiple: View { 14 | @State private var showingFirst = false 15 | @State private var showingSecond = false 16 | 17 | var body: some View { 18 | VStack { 19 | Button("Show First Sheet") { 20 | showingFirst = true 21 | } 22 | } 23 | .sheet(isPresented: $showingFirst) { 24 | Button("Show Second Sheet") { 25 | showingSecond = true 26 | } 27 | .sheet(isPresented: $showingSecond) { 28 | Text("Second Sheet") 29 | } 30 | } 31 | 32 | //使用这种方法,两个Sheet都将正确显示。 33 | //如果你把两个Sheet()修饰符放在同一个父元素中,SwiftUI会失效,只显示第一个sheet 34 | } 35 | } 36 | 37 | #Preview { 38 | FFPresentSheetsMultiple() 39 | } 40 | -------------------------------------------------------------------------------- /FFModifier/015 - PresentingViews/FFSheetPopover.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFSheetPopover.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/17. 6 | // 7 | // 如何显示Popover视图 8 | // SwiftUI有一个专门的修饰器来显示弹出窗口,在iPad上显示为漂浮的气泡,在iOS上是滑动 9 | // 要显示弹出窗口,你需要一些状态来确定弹出窗口是否可见。与alert不同,弹出窗口可以包含任何类型的视图,所以,只要把你需要的东西放在弹出窗口中就可以。 10 | 11 | import SwiftUI 12 | 13 | struct FFSheetPopover: View { 14 | @State private var showingPopover = false 15 | 16 | var body: some View { 17 | Button("Show Menu") { 18 | showingPopover = true 19 | } 20 | .popover(isPresented: $showingPopover) { 21 | Text("Your content here") 22 | .font(.headline) 23 | .padding() 24 | } 25 | } 26 | } 27 | 28 | #Preview { 29 | FFSheetPopover() 30 | } 31 | -------------------------------------------------------------------------------- /FFModifier/015 - PresentingViews/FFSheetReview.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFSheetReview.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/18. 6 | // 7 | // 如何让用户Review你的app(失败的case) 8 | // 如果导入StoreKitdaoSwiftUI应用中,可以获得一个requestReview的环境变量来访问Appstore,可以提示用户应用内评价。 9 | // 要使用它,首相将StoreKit导入,将环境变量作为属性添加到视图中,然后在想要调用的地方调用他。 10 | 11 | import SwiftUI 12 | import StoreKit 13 | 14 | struct FFSheetReview: View { 15 | @Environment(\.requestReview) var requestReview 16 | var body: some View { 17 | Button("请给应用题一个评价吧") { 18 | requestReview() 19 | } 20 | 21 | } 22 | } 23 | 24 | #Preview { 25 | FFSheetReview() 26 | } 27 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFAdvancedEffects.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFAdvancedEffects.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/19. 6 | // 7 | // 如何使用更多的修饰符创建更加复杂的UI 8 | // 添加到视图中的每个修饰符都会调整之前的任何修饰符,并可以多次重复修饰符。 9 | 10 | import SwiftUI 11 | 12 | struct FFAdvancedEffects: View { 13 | var body: some View { 14 | Text("Hello, metaBBLv") 15 | .font(.largeTitle) 16 | .foregroundStyle(.white) 17 | .padding() 18 | .background(.red) 19 | .padding() 20 | .background(.orange) 21 | .padding() 22 | .background(.yellow) 23 | //这对于创建阴影,可以根据需求来重复使用修饰符。 24 | } 25 | } 26 | 27 | #Preview { 28 | FFAdvancedEffects() 29 | } 30 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFTextEditorBackground.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFTextEditorBackground.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct FFTextEditorBackground: View { 11 | @State private var bio = "Describe yourself" 12 | var body: some View { 13 | //隐藏TextEditor的默认背景,用渐变替代 14 | TextEditor(text: $bio) 15 | .scrollContentBackground(.hidden) 16 | .background(LinearGradient(colors: [.white, .gray], startPoint: .top, endPoint: .bottom)) 17 | } 18 | } 19 | 20 | #Preview { 21 | FFTextEditorBackground() 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFViewAccent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewAccent.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/21. 6 | // 7 | // 如何调整视图的强调色 8 | // iOS使用淡色调给应用程序一个协调的主题,在SwiftUI中也有相同的功能,名为accent。就像在UIkit中,当你设置一个视图的accent会影响它里面的所有视图,如果你设置顶层空间的访问色,那么所有的东西都有颜色。 9 | 10 | import SwiftUI 11 | 12 | struct FFViewAccent: View { 13 | var body: some View { 14 | VStack { 15 | Button("Press Here") { 16 | print("Button pressed!") 17 | } 18 | } 19 | .accentColor(.orange) 20 | } 21 | } 22 | 23 | #Preview { 24 | FFViewAccent() 25 | } 26 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFViewBlend.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewBlend.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/21. 6 | // 7 | // 如何将视图混合在一起 8 | // 当将一个视图放置在另一个视图上时,你可以使用blendMode()修饰符来控制重叠的方式。这包含了多种混合颜色的方法。 9 | 10 | import SwiftUI 11 | 12 | struct FFViewBlend: View { 13 | var body: some View { 14 | //创建一个ZStack,里面有两个重叠的圆,将混合模式设定为.multiply,颜色会变暗 15 | ZStack { 16 | Circle() 17 | .fill(.red) 18 | .frame(width: 200, height: 200) 19 | .offset(x: -50) 20 | .blendMode(.multiply) 21 | Circle() 22 | .fill(.blue) 23 | .frame(width: 200, height: 200) 24 | .offset(x: 50) 25 | .blendMode(.multiply) 26 | } 27 | .frame(width: 400) 28 | } 29 | } 30 | 31 | #Preview { 32 | FFViewBlend() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFViewBlur.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewBlur.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/21. 6 | // 7 | // 如何模糊视图 8 | // blur()修饰符允许我们根据自己的选择对视图附加实时的高斯模糊。 9 | 10 | import SwiftUI 11 | 12 | struct FFViewBlur: View { 13 | @State private var blurAmount = 0.0 14 | var body: some View { 15 | //对图像使用模糊 16 | Image(.freshBakedCroissantThumb) 17 | .resizable() 18 | .frame(width: 300, height: 300) 19 | .blur(radius: 20) 20 | Divider() 21 | //对文本使用模糊 22 | Text("Meta BBlv in Swift") 23 | .blur(radius: 2) 24 | Divider() 25 | //通过Slider动态调整模糊效果 26 | VStack { 27 | Image(.macaronsGaloreThumb) 28 | .resizable() 29 | .frame(width: 300, height: 300) 30 | .blur(radius: blurAmount) 31 | Slider(value: $blurAmount, in: 0...20) 32 | } 33 | .padding() 34 | } 35 | } 36 | 37 | #Preview { 38 | FFViewBlur() 39 | } 40 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFViewBorder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewBorder.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/19. 6 | // 7 | // 如何在View周围绘制边框 8 | // SwiftUI为我们提供了一个专门的border()修饰符来绘制视图周围的边框。它有一些变化取决于你是否想要指定宽度和圆角半径, 9 | 10 | import SwiftUI 11 | 12 | 13 | struct FFViewBorder: View { 14 | var body: some View { 15 | Text("metaBBlv with Swift") 16 | .border(.green) 17 | Divider() 18 | //可以添加一些padding来让边框更舒服 19 | Text("metaBBlv with Swift") 20 | .padding() 21 | .border(.green) 22 | Divider() 23 | //设置Border的宽度 24 | Text("metaBBlv with Swift") 25 | .padding() 26 | .border(.red, width: 4) 27 | Divider() 28 | //添加圆角边框,使用overlay()修饰符。 29 | Text("metaBBlv with Swift") 30 | .padding() 31 | .overlay { 32 | RoundedRectangle(cornerRadius: 16) 33 | .stroke(.blue, lineWidth: 4) 34 | } 35 | //对形状类型使用stroke()或strokeBorder(),对其他视图类型使用border() 36 | } 37 | } 38 | 39 | #Preview { 40 | FFViewBorder() 41 | } 42 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFViewBorderInside.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewBorderInside.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/19. 6 | // 7 | // 如何在视图中绘制border 8 | // SwiftUI为我们提供了stroke()和strokeBorder()修饰符,用于在形状周围绘制border,略有不同: 9 | // strokeBorder()修饰符将视图插入边框高度的一半,然后应用边框,这意味着整个边框都在视图内绘制。 10 | // stroke(0修饰符以视图的边缘为中心绘制border,这意味着一半的border在视图内部,一半在外部。 11 | // 重要提示:这两个修饰符只适用于形状(Circle、Rectangle、Capsule等视图),不能对Text、Image等其他非形状视图使用。如果你想在非形状视图周围绘制边框,使用border修饰符 12 | 13 | import SwiftUI 14 | 15 | struct FFViewBorderInside: View { 16 | var body: some View { 17 | Circle() 18 | .strokeBorder(Color.blue, lineWidth: 50) 19 | .frame(width: 200, height: 200) 20 | .padding() 21 | //因为使用了strokeBorder(),所以50宽度的边框全部在圆的内部 22 | Divider() 23 | Circle() 24 | .stroke(.green, lineWidth: 50) 25 | .frame(width: 200, height: 200) 26 | .padding() 27 | } 28 | } 29 | 30 | #Preview { 31 | FFViewBorderInside() 32 | } 33 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFViewChangeBackground.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewChangeBackground.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/21. 6 | // 7 | // 如何改变列表、文本编辑器等的背景颜色 8 | // 一些SwiftUI是有有一个默认的背景颜色,它会覆盖你自己想要的任何颜色,但是如果你使用scrollCOntentBackground()修饰符,你可以隐藏默认背景并用其他颜色替代。 9 | 10 | import SwiftUI 11 | 12 | struct FFViewChangeBackground: View { 13 | var body: some View { 14 | //删除List的默认颜色,替换为.indigo 15 | List(0..<100) { i in 16 | Text("Exampl \(i)") 17 | } 18 | .scrollContentBackground(.hidden) 19 | .background(.indigo) 20 | } 21 | } 22 | 23 | #Preview { 24 | FFViewChangeBackground() 25 | } 26 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFViewMask.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewMask.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/21. 6 | // 7 | // 如何用一个视图掩盖另一个视图 8 | // SwiftUI为我们提供了mask()修饰符,用于用一个遮罩另外一个,这意味着你可以用文本遮罩一个图像,或者。。。。 9 | 10 | import SwiftUI 11 | 12 | struct FFViewMask: View { 13 | var body: some View { 14 | //创建一个300*300的条纹图像,然后使用文本“SWIFT!”遮罩,这样这些字母就可以和图像合并。 15 | Image(.fullEnglish) 16 | .frame(width: 300, height: 300) 17 | .mask { 18 | Text("SWIFT!") 19 | .font(.system(size: 72)) 20 | } 21 | //mask()修饰符与clipShape()不同,因为它也应用遮罩视图中的任何透明度。你可以根据遮罩的透明度在底层视图中设置空洞。另一方面,clipShape()值调整应用他的视图的外部形状。 22 | } 23 | } 24 | 25 | #Preview { 26 | FFViewMask() 27 | } 28 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFViewOpacity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewOpacity.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/21. 6 | // 7 | // 如何调整视图的不透明度 8 | // 使用opacity()修饰符,任何SwiftUI视图都可以时部分透明或者全透明的,它接受一个介于0(完全不可见)-1(完全不透明)之间的值,与UIKit的alpha属性一致。 9 | 10 | 11 | import SwiftUI 12 | 13 | struct FFViewOpacity: View { 14 | @State private var opacity = 0.5 15 | 16 | var body: some View { 17 | //创建一个红色文本视图,附加30%透明度 18 | Text("Hello, World!") 19 | .padding() 20 | .background(.red) 21 | .opacity(0.3) 22 | //修改不透明度是非常快速的,基本不可见,视图出现即看见结果,通过Slider查看动态效果 23 | VStack { 24 | Text("Hello, World!") 25 | .padding() 26 | .background(.red) 27 | .opacity(opacity) 28 | Slider(value: $opacity, in: 0...1) 29 | } 30 | .padding() 31 | } 32 | } 33 | 34 | #Preview { 35 | FFViewOpacity() 36 | } 37 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFViewPaddingAroundColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewPaddingAroundColor.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/19. 6 | // 7 | // 如何在视图周围填充颜色 8 | // padding()修饰符允许我们在视图周围添加一些间距,background()修饰符允许我们设置背景颜色。 9 | 10 | import SwiftUI 11 | 12 | struct FFViewPaddingAroundColor: View { 13 | var body: some View { 14 | Text("metaBBLv with Swift") 15 | .background(.red) 16 | .foregroundStyle(.white) 17 | .padding() 18 | 19 | Divider() 20 | Text("metaBBLv with Swift") 21 | .padding() 22 | .background(.red) 23 | .foregroundStyle(.white) 24 | //这两段code可能看起来比较相似,但是他们产生不同的结果,因为使用修饰符的顺序很重要。在第二个例子中,视图被填充,然后着色,这意味着填充的范围也被着色。相比之下,第一个例子就是先着色再填充。 25 | } 26 | } 27 | 28 | #Preview { 29 | FFViewPaddingAroundColor() 30 | } 31 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFViewRotate3D.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewRotate3D.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/21. 6 | // 7 | // 如何在3D中旋转视图。 8 | // SwiftUI的rotation3DEffect()修饰符让我们在3D空间中旋转视图,几乎不需要太多的代码就可以创造非常好的效果。它接受两个参数:要旋转的角度(以弧度或度为单位),以及包含要绕其旋转的X、Y和Z轴的元祖。 9 | 10 | 11 | import SwiftUI 12 | 13 | struct FFViewRotate3D: View { 14 | var body: some View { 15 | //将Text围绕X轴旋转45度 16 | Text("METABBLV SWIFTUI") 17 | .font(.largeTitle) 18 | .foregroundStyle(.green) 19 | .rotation3DEffect(.degrees(45), axis: (x: 1, y: 0, z:0)) 20 | } 21 | } 22 | 23 | #Preview { 24 | FFViewRotate3D() 25 | } 26 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFViewRound.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewRound.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/21. 6 | // 7 | // 如何设定更精确的圆角 8 | // SwiftUI视图都可以使用cornerRadius()修饰符来设置圆角。它采用一个简单的、以点数为单位的值来控制圆角。 9 | 10 | import SwiftUI 11 | 12 | struct FFViewRound: View { 13 | var body: some View { 14 | //创建一个15点圆角的文本视图。 15 | Text("Hello, World!") 16 | .padding() 17 | .background(.green) 18 | .cornerRadius(15) 19 | //此函数在iOS17上建议使用“Use `clipShape` or `fill` instead” 20 | //你可以使用带Capsule的ClipShape()修饰符自动将最短的边缘更加的圆润。 21 | Text("Hello, world!") 22 | .padding() 23 | .background(.green) 24 | .clipShape(Capsule()) 25 | } 26 | } 27 | 28 | #Preview { 29 | FFViewRound() 30 | } 31 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFViewScale.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewScale.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/21. 6 | // 7 | // 如何放大或缩小视图 8 | // SwiftUI的scaleEffect()修饰符让我们可以自由的放大或缩小视图。 9 | 10 | import SwiftUI 11 | 12 | struct FFViewScale: View { 13 | var body: some View { 14 | //放大 15 | Text("Hello, World!") 16 | .scaleEffect(3) 17 | .frame(width: 300, height: 100) 18 | Spacer() 19 | //在X轴与Y轴之上做更改,可以压缩图像 20 | Text("Hello, World!") 21 | .scaleEffect(x: 1, y: 5) 22 | .frame(width: 300, height: 100) 23 | Spacer() 24 | //指定一个锚点进行缩放。 25 | Text("Hello, World!") 26 | .scaleEffect(2, anchor: .bottomTrailing) 27 | //获得一个两倍大小的文本视图,从右下角开始缩放。 28 | //提示:缩放视图不会导致它以新的大小重新绘制,只会在不同方向上拉伸。这意味着小的文本开起来模糊,小的图像可能看起来像素化或模糊 29 | Spacer() 30 | //对照组 31 | Text("Hello, World!") 32 | Spacer() 33 | } 34 | } 35 | 36 | #Preview { 37 | FFViewScale() 38 | } 39 | -------------------------------------------------------------------------------- /FFModifier/016 - TransformingViews/FFViewTintingAndDesaturating.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewTintingAndDesaturating.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/21. 6 | // 7 | // 如何通过着色、去饱和度来调整视图。 8 | // SwiftUI可以让我们通过调整他们的亮度、色调、色温、饱和度来精确的调整视图, 9 | 10 | import SwiftUI 11 | 12 | struct FFViewTintingAndDesaturating: View { 13 | @State private var contrastAmount = 0.5 14 | var body: some View { 15 | //将Image调成红色 16 | Image(.mexicanMocha) 17 | .colorMultiply(.red) 18 | //饱和度调整,0.0时全灰色-1.0为原始颜色 19 | Image(.mushroomTagliatelle) 20 | .saturation(0.3) 21 | //甚至可以通过使用contrast()修饰符动态调整视图的对比度,0.0不会产生对比度,为灰色图像,1.0为原始图像,高于1.0会增加对比度 22 | VStack { 23 | Image(.paellaAlicante) 24 | .contrast(contrastAmount) 25 | 26 | Slider(value: $contrastAmount , in: 0...3) 27 | } 28 | } 29 | } 30 | 31 | #Preview { 32 | FFViewTintingAndDesaturating() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/018 - Drawing/FFDramCustomPath.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFDramCustomPath.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/23. 6 | // 7 | // 如何绘制自定义路径 8 | // SwiftUI可以根据Shape协议绘制自定义路径,这样就可以创建自定义形状,可以是矩形、胶囊图形、圆形等。遵守这个协议并不难,因为需要做的就是支持一个接受CGRect并返回path的path(in:)方法。更棒的事,可以使用之前用CGPath或UIBezierPath构建的任何路径,然后将结果转换为SwiftUI路径。 9 | //如果想使用SwiftUI的原生路径类型,创建他的一个实例变量,然后根据需要添加尽可能多的点或形状。不需要考虑颜色、填充或边框宽度。这里只关注原始类型,这些设置是在使用自定义path时设定的。 10 | 11 | import SwiftUI 12 | 13 | struct ShrinkingSquares: Shape { 14 | func path(in rect: CGRect) -> Path { 15 | var path = Path() 16 | for i in stride(from: 1, to: 100, by: 5.0) { 17 | let rect = CGRect(x: 0, y: 0, width: rect.width, height: rect.height) 18 | let insetRect = rect.insetBy(dx: i, dy: i) 19 | path.addRect(insetRect) 20 | } 21 | return path 22 | } 23 | } 24 | 25 | struct FFDramCustomPath: View { 26 | var body: some View { 27 | ShrinkingSquares() 28 | .stroke() 29 | .frame(width: 200, height: 200) 30 | } 31 | } 32 | 33 | #Preview { 34 | FFDramCustomPath() 35 | } 36 | -------------------------------------------------------------------------------- /FFModifier/018 - Drawing/File.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/5. 6 | // 7 | 8 | import Foundation 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /FFModifier/019 - Animation/FFAnimateTextSize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFAnimateTextSize.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/25. 6 | // 7 | // 文本size的Animation 8 | // 从iOS16以后,SwiftUI可以将Text动画化。因此向下面这样的代码可以在两种不同的大小之间苹果的显示动画,自动的重新渲染文本。 9 | 10 | import SwiftUI 11 | 12 | struct FFAnimateTextSize: View { 13 | @State private var fontSize = 32.0 14 | 15 | var body: some View { 16 | Text("Hi, metaBBLv") 17 | .font(.custom("Georgia", size: fontSize)) 18 | .onTapGesture { 19 | withAnimation(.spring(response: 0.5, dampingFraction: 0.5, blendDuration: 1).repeatForever()) { 20 | fontSize = 72 21 | } 22 | } 23 | } 24 | } 25 | 26 | #Preview { 27 | FFAnimateTextSize() 28 | } 29 | -------------------------------------------------------------------------------- /FFModifier/019 - Animation/FFAnimationDelay.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFAnimationDelay.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/25. 6 | // 7 | // 动画延迟 8 | // 当你想创建任何动画时(隐式、显示、绑定),可以给动画附加修饰符来调整。例如,如果想让动画在一定的时间后开始,那么就需要使用delay()修饰符。 9 | 10 | import SwiftUI 11 | 12 | struct FFAnimationDelay: View { 13 | @State private var rotaitonDelay = 0.0 14 | 15 | var body: some View { 16 | //例如,创建一个红色矩形,当点击时,在1s后在2s时间内旋转360度。 17 | Rectangle() 18 | .fill(.red) 19 | .frame(width: 200, height: 200) 20 | .rotationEffect(.degrees(rotaitonDelay)) 21 | .animation(.easeInOut(duration: 3).delay(1), value: rotaitonDelay) 22 | .onTapGesture { 23 | rotaitonDelay += 360 24 | } 25 | } 26 | } 27 | 28 | #Preview { 29 | FFAnimationDelay() 30 | } 31 | -------------------------------------------------------------------------------- /FFModifier/019 - Animation/FFAnimationExlicit.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFAnimationExlicit.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/25. 6 | // 7 | // 如何创建显式动画 8 | // 如果将动画附加到视图上,最终会得到一个隐式动画。改变视图中的其他地方的一些状态可能会使用动画,及时你只是增加一个整数或者切换一个bool值。 9 | // 另外一种时显式动画,在这种情况下,你不给有问题的视图附加修饰符,而是让SwiftUI对你想要做的精确的更改进行动画化。为此,将更改封装在withAnimation()中。 10 | 11 | import SwiftUI 12 | 13 | struct FFAnimationExlicit: View { 14 | @State private var opacity = 1.0 15 | 16 | var body: some View { 17 | Button("Press here") { 18 | withAnimation { 19 | opacity -= 0.2 20 | } 21 | } 22 | .padding() 23 | .font(.title) 24 | .background(.green) 25 | .opacity(opacity) 26 | //withAnimation()也可以接受参数,指定动画类型,因此也可以创建一个3s的线性动画withAnimation(.linear(duration: 3)) 27 | //显式动画通常很有用,因为他们会使每个受影响的视图都产生动画,而不是仅仅是那些附加了隐式动画的视图。 28 | } 29 | } 30 | 31 | #Preview { 32 | FFAnimationExlicit() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/019 - Animation/FFAnimationMultiple.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFAnimationMultiple.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/25. 6 | // 7 | // 如何将多个动画应用到视图 8 | // 使用SwiftUI的animation()修饰符的顺序会影响那些修饰符会被动画化。也可以添加多个animation修饰符来设置不同的动画。 9 | // 有两种方法可以做到这一点: 10 | // - iOS17 新方法 11 | // - iOS16以及以前:旧方法 12 | 13 | 14 | import SwiftUI 15 | 16 | struct FFAnimationMultiple: View { 17 | @State private var isEnabled = false 18 | 19 | var body: some View { 20 | Button("Press me") { 21 | isEnabled.toggle() 22 | } 23 | .foregroundStyle(.white) 24 | .frame(width: 200, height: 200) 25 | .animation(.easeInOut(duration: 1)) { content in 26 | content 27 | .background(isEnabled ? .green : .red) 28 | } 29 | .animation(.easeInOut(duration: 2)) { content in 30 | content 31 | .clipShape(.rect(cornerRadius: isEnabled ? 100 : 0)) 32 | } 33 | } 34 | } 35 | 36 | #Preview { 37 | FFAnimationMultiple() 38 | } 39 | -------------------------------------------------------------------------------- /FFModifier/019 - Animation/FFTransitionAsymmetric.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFTransitionAsymmetric.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/25. 6 | // 7 | // 如何创建不对称过渡动画 8 | // SwiftUI可以在添加一个视图是指定transition,在删除时指定另一个transition。所有这些都是使用asymmetric()完成的。 9 | 10 | import SwiftUI 11 | 12 | struct FFTransitionAsymmetric: View { 13 | @State private var showDetails = false 14 | 15 | var body: some View { 16 | //创建一个使用不对称过渡的文本视图:添加时从左面出现,删除时向下移动 17 | VStack { 18 | Button("Press to show details") { 19 | withAnimation { 20 | showDetails.toggle() 21 | } 22 | } 23 | 24 | if showDetails { 25 | Text("Details go here") 26 | .transition(.asymmetric(insertion: .move(edge: .leading), removal: .move(edge: .bottom))) 27 | } 28 | } 29 | } 30 | } 31 | 32 | #Preview { 33 | FFTransitionAsymmetric() 34 | } 35 | -------------------------------------------------------------------------------- /FFModifier/021 - ComposingViews/FFCustomModifiers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFCustomModifiers.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/28. 6 | // 7 | // 如何创建自定义修饰符 8 | // 如果发现重复的将同一组修饰符附加到视图(比如,背景色、padding、字体等等),那么可以通过创建一个修饰符来封装这些重复的修饰符。 9 | // 如果你想创建自己的结构,那么要遵守ViewModifier协议。并且要实现一个body(content:)函数。 10 | 11 | import SwiftUI 12 | 13 | //创建一个新的PrimaryLabel修饰符,添加padding、background、foregroundcolor和font等 14 | struct PrimaryLabel: ViewModifier { 15 | func body(content: Content) -> some View { 16 | content 17 | .padding() 18 | .background(.red) 19 | .foregroundStyle(.white) 20 | .font(.largeTitle) 21 | } 22 | } 23 | 24 | struct FFCustomModifiers: View { 25 | var body: some View { 26 | Text("Hello, SwiftUI") 27 | .modifier(PrimaryLabel()) 28 | } 29 | } 30 | 31 | #Preview { 32 | FFCustomModifiers() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/021 - ComposingViews/FFCustomText.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFCustomText.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/28. 6 | // 7 | // 如何将文本视图组合在一起 8 | // SwiftUI文本视图重载了“+”运算符,可以将文本视图组合创建新的文本视图。 9 | // 当你需要在视图中使用不同的格式时,可以使每个文本视图都不一样,让后将它们连接在一起形成单个组合文本视图。最方便的是,当使用朗读功能是,VoiceOver会自动将它们识别为一段文本。 10 | 11 | import SwiftUI 12 | 13 | struct FFCustomText: View { 14 | var body: some View { 15 | Text("SwiftUI") 16 | .font(.largeTitle) 17 | + Text("is") 18 | .font(.headline) 19 | + Text("awesome") 20 | .font(.footnote) 21 | 22 | //创建不同颜色或字体的文本 23 | Text("SwiftUI") 24 | .foregroundStyle(.red) 25 | + Text("is") 26 | .foregroundStyle(.orange) 27 | .fontWeight(.black) 28 | + Text("awesome") 29 | .foregroundStyle(.blue) 30 | } 31 | } 32 | 33 | #Preview { 34 | FFCustomText() 35 | } 36 | -------------------------------------------------------------------------------- /FFModifier/021 - ComposingViews/FFTextInsertImage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFTextInsertImage.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/28. 6 | // 7 | // 如何在文本中插入图像 8 | // SwiftUI可以使用“+”来组合文本视图,也可以使用简单的文本初始值设定项将图像直接放到文本中, 9 | 10 | import SwiftUI 11 | 12 | struct FFTextInsertImage: View { 13 | var body: some View { 14 | //在Helloworld中添加一个星星icon 15 | Text("Hello ") + Text(Image(systemName: "star")) + Text(" World!") 16 | //文本中的图像将自动调整以匹配添加的修饰符(字体、颜色等),要用括号将链接的内容扩起来,以确保将修饰符应用于整个链接的文本。要不只能修饰最后一个Text 17 | (Text("Hello ") + Text(Image(systemName: "star")) + Text(" World!")) 18 | .font(.largeTitle) 19 | .foregroundStyle(.blue) 20 | //如果没有添加额外的括号,则只会修饰最后一个Text("World") 21 | Text("Hello ") + Text(Image(systemName: "star")) + Text(" World!") 22 | .font(.largeTitle) 23 | .foregroundStyle(.blue) 24 | } 25 | } 26 | 27 | #Preview { 28 | FFTextInsertImage() 29 | } 30 | -------------------------------------------------------------------------------- /FFModifier/021 - ComposingViews/FFViewStoreProperties.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFViewStoreProperties.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/28. 6 | // 7 | // 如何将视图存储为属性 8 | // 如果有多个视图前台在另一个视图中,你可能会发现为其中一些或全部视图创建属性很重要,可以使布局代码更容易,然后,可以在视图代码中內联引用这些属性,可以保证视图结构更清晰。 9 | 10 | import SwiftUI 11 | 12 | struct FFViewStoreProperties: View { 13 | let title = Text("metaBBLv").bold() 14 | let subtitle = Text("Author").foregroundStyle(.secondary) 15 | 16 | var body: some View { 17 | VStack { 18 | title 19 | subtitle 20 | //像这样,只需要在stack中写入属性名就可以使用了。 21 | //但是更方便的是可以将修饰符附加到这些属性上进行自定义操作。 22 | Divider() 23 | title 24 | .foregroundStyle(.red) 25 | subtitle 26 | //这不会改变标题的基础设定,只是在基础程度上附加的一种方式。 27 | } 28 | } 29 | } 30 | 31 | #Preview { 32 | FFViewStoreProperties() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/022 - Cross-platform/FFCross-platformAbout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFCross-platformAbout.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/28. 6 | // 7 | // 关于SwiftUI的跨平台 8 | // 当苹果宣布SwiftUI时,他们做了一个重要的区别:SwiftUI不是一个多平台框架,而是一个在多个平台上创建App的框架。 9 | // 这看起来像是用两种不同的方式表达同一件事,但实际上这意味着SwiftUI的许多部分在iOS上可以使用,但在macOS上不可用。 10 | // 应用程序的核心保持不变:模型、网络和大部分用户界面。但要获得好用的App(构建真正适合每个Apple平台的应用程序),需要添加一些特定于平台的增强功能。你的应用程序如何在watchOS上如何使用Digital Crown?tvOS上播放/暂停按钮怎么样?或者macOS上的右键菜单? 11 | // 如何将这些问题有效的解决是构建多平台体验的关键。 12 | 13 | import SwiftUI 14 | 15 | struct FFCross_platformAbout: View { 16 | var body: some View { 17 | Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) 18 | } 19 | } 20 | 21 | #Preview { 22 | FFCross_platformAbout() 23 | } 24 | -------------------------------------------------------------------------------- /FFModifier/022 - Cross-platform/FFMacOSTranslucent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFMacOSTranslucent.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/28. 6 | // 7 | // 如何在macOS上获取半透明list 8 | // macOS的一个微妙但重要的功能是当窗口处于活跃状态时,侧边栏会自动变的稍微透明,然后当窗口移动到背景时变的不透明 - 这是想用户展示那个窗口处于活跃状态的一个小提示,但也让他们的背景展示出来,给他们一些关于他们的环境的背景。 9 | //SwiftUI可以使用listStyle()修饰符来创建这些半透明侧边栏List,传入.sidebar。 10 | 11 | import SwiftUI 12 | 13 | struct FFMacOSTranslucent: View { 14 | var body: some View { 15 | NavigationStack { 16 | List(1..<51) { 17 | Text("meta \($0)") 18 | } 19 | .listStyle(.sidebar) 20 | } 21 | //在iOS和iPadOS上,.siderbar不提供半透明背景,但会影响单元格样式。 22 | } 23 | } 24 | 25 | #Preview { 26 | FFMacOSTranslucent() 27 | } 28 | -------------------------------------------------------------------------------- /FFModifier/022 - Cross-platform/FFWatchOSCarousel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFWatchOSCarousel.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/28. 6 | // 7 | // 如何在watchOS上制作轮播列表 8 | // wathhOS有一种特别常见的列表样式,可以使用以下的方式轻松复制,List列表中的行在移动到屏幕上时滑动并放大,在移出屏幕时滑动并缩小。 9 | // 要启用此轮博效果,使用.listStyle()修饰符和.carousel属性。 10 | 11 | import SwiftUI 12 | 13 | #if (watchOS) 14 | struct FFWatchOSCarousel: View { 15 | var body: some View { 16 | List(1..<51) { 17 | Text("meta \($0)") 18 | } 19 | .listStyle(.carousel) 20 | } 21 | } 22 | 23 | 24 | #Preview { 25 | FFWatchOSCarousel() 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /FFModifier/022 - Cross-platform/FFWindowOpen.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFWindowOpen.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/29. 6 | // 7 | // 如何打开新窗口 8 | // SwiftUI提供了一个openWindow环境密钥,可以在macOS上创建新的窗口。 9 | // 首先,编辑App场景以包含新的Window,这意味着提供了一个窗口标题,同时也提供了一个标识符。 10 | 11 | import SwiftUI 12 | 13 | /** 14 | Window("What's New", id: "wats-new") { 15 | Text("New in this version...") 16 | } 17 | */ 18 | 19 | struct FFWindowOpen: View { 20 | @Environment(\.openWindow) var openWindow 21 | 22 | var body: some View { 23 | Button("Show What's New") { 24 | openWindow(id: "whats-new") 25 | } 26 | //也可以通过“window”菜单打开窗口,macOS将使用你提供的窗口标题自动将其显示在哪里。 27 | } 28 | } 29 | 30 | #Preview { 31 | FFWindowOpen() 32 | } 33 | -------------------------------------------------------------------------------- /FFModifier/023 - CoreData/FFCoreData.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFCoreData.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/30. 6 | // 7 | // 在SwiftUI中使用CoreData 8 | // SwiftUI和CoreData作为Apple软件平台的其中两个重要组成部分,有很好的协同能力,SwiftUI有属性包装器、环境支持等等,这些都是为了确保能以最小的麻烦将Core Data集成到SwiftUI的App中。 9 | // 在SwiftUI之前,在架构角度来看,使用Core Data的方式如下: 10 | //- Apple建议在AppDelegate的级别创建容器,然后根据需要return 11 | //- 一部分人喜欢使用Manager Classes 12 | //- 还有一部分人喜欢完全抽象Core Data,以方便完全转移到Realm或其他可选项 13 | 14 | //SwiftUI与Core Data的集成是不同的,在启动时,需要创建Core Data容器,然后将其托管对象注入到环境中,然后直接在哪里执行Request 15 | //以下是四个特定的功能,可以帮你理解我的意思: 16 | //1. NSManagedObject遵守ObservableObject协议,这代表可以将任何对象绑定到用户界面。 17 | //2. 环境中有一个managedObjectContent的key,用于存储Core Data托管对象的上下文。 18 | //3. 然后Xcode的模版将这个context主入到初始的内容视图中。 19 | //4. 有一个@FetchRequest的属性包装器,它使用环境的托管对象上下文来获取request 20 | 21 | //因此,在应用启动时创建一个托管对象上下文,将其附加到视图的环境中,然后使用@FetchRequest加载数据供App使用。 22 | 23 | import SwiftUI 24 | 25 | struct FFCoreData: View { 26 | var body: some View { 27 | Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) 28 | } 29 | } 30 | 31 | #Preview { 32 | FFCoreData() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/023 - CoreData/FFCoreDataAddObjects.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFCoreDataAddObjects.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/30. 6 | // 7 | // 如何从SwiftUI视图添加Core Data对象 8 | // 在SwiftUI中保存core data对象的工作方式与在SwiftUI之外的工作往事完全相同,访问托管对象的context,在该上下文中创建你的类型的实例,然后在准备好时保存context。 9 | 10 | 11 | 12 | import SwiftUI 13 | 14 | struct FFCoreDataAddObjects: View { 15 | @Environment(\.managedObjectContext) var managedObjectContext 16 | @FetchRequest(sortDescriptors: []) var languages: FetchedResults 17 | var body: some View { 18 | //创建实例 19 | Button("Insert Example Languate") { 20 | let language = ProgrammingLanguage(context: managedObjectContext) 21 | language.name = "Python" 22 | language.creator = "Guido van Rossum" 23 | PersistenceController.shared.save() 24 | } 25 | //在添加一组对象之后,程序会多一组对象。 26 | List(languages) { language in 27 | Text(language.name ?? "UnKnown") 28 | } 29 | } 30 | } 31 | 32 | #Preview { 33 | FFCoreDataAddObjects() 34 | } 35 | -------------------------------------------------------------------------------- /FFModifier/023 - CoreData/FFCoreDataFetchRequest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFCoreDataFetchRequest.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/30. 6 | // 7 | // 如何使用@FetchRequest创建一个核心数据获取请求 8 | // FetchRequest可以加载符合指定的条件的Core Data结果,并且SwiftUI可以将这些结果直接绑定到用户界面。 9 | // 创建fetchRequest需要两条信息: 10 | //- 要查询的实体 11 | //- 以及确定返回结果顺序的排序描述符。 12 | 13 | 14 | import SwiftUI 15 | import CoreData 16 | 17 | struct FFCoreDataFetchRequest: View { 18 | 19 | @Environment(\.managedObjectContext) var managedObjectContext 20 | // SortDescriptors参数是一个数组,所以可以提供尽可能多的排序选项 21 | @FetchRequest(sortDescriptors: []) var languages: FetchedResults 22 | 23 | var body: some View { 24 | List(languages) { language in 25 | Text(language.name ?? "UnKnown") 26 | } 27 | } 28 | } 29 | 30 | #Preview { 31 | FFCoreDataFetchRequest() 32 | } 33 | -------------------------------------------------------------------------------- /FFModifier/023 - CoreData/FFCoreDataFetchRequestsFilter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFCoreDataFetchRequestsFilter.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/30. 6 | // 7 | // 如何使用predicate过滤CoreData的fetchRequests 8 | // CoreData的fetchRequest中可以使用Predicates,就像在UIKit中,所有这些都是通向你的@FetchRequest属性包装器提供一个predicate来实现的。 9 | // 10 | 11 | import SwiftUI 12 | 13 | struct FFCoreDataFetchRequestsFilter: View { 14 | @Environment(\.managedObjectContext) var managedObjectContext 15 | //创建predicate 16 | @FetchRequest( 17 | sortDescriptors: [], 18 | predicate: NSPredicate(format: "name == %@", "Python") 19 | ) var languages: FetchedResults 20 | //目前@FetchRequest使用的是标准的CoreData的Predicate,也可以创建复合Predicate 21 | 22 | var body: some View { 23 | List(languages) { language in 24 | Text(language.name ?? "UnKnown") 25 | } 26 | } 27 | } 28 | 29 | #Preview { 30 | FFCoreDataFetchRequestsFilter() 31 | } 32 | -------------------------------------------------------------------------------- /FFModifier/023 - CoreData/FFCoreDataLimit.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFCoreDataLimit.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/30. 6 | // 7 | // 如何限制获取FetchRequest中的item数量(分页) 8 | // SwiftUI的@FetchRequest属性包装器非常适合对Object发出简单request,提供排序和过滤功能。但是,如果想调整返回item的数量,那么需要额外设置 9 | 10 | 11 | import SwiftUI 12 | import CoreData 13 | 14 | struct FFCoreDataLimit: View { 15 | @Environment(\.managedObjectContext) var managedObjectContext 16 | //创建@FetchRequest 17 | @FetchRequest var languages: FetchedResults 18 | 19 | init() { 20 | let request: NSFetchRequest = ProgrammingLanguage.fetchRequest() 21 | request.sortDescriptors = [ 22 | NSSortDescriptor(keyPath: \ProgrammingLanguage.name, ascending: true) 23 | ] 24 | request.fetchLimit = 10 25 | _languages = FetchRequest(fetchRequest: request) 26 | } 27 | 28 | var body: some View { 29 | List(languages) { language in 30 | Text(language.name ?? "UnKnown") 31 | } 32 | } 33 | } 34 | 35 | #Preview { 36 | FFCoreDataLimit() 37 | } 38 | -------------------------------------------------------------------------------- /FFModifier/023 - CoreData/FFCoreDataManagged.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFCoreDataManagged.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/30. 6 | // 7 | // 如何从SwiftUI视图访问核心数据管理对象Context 8 | 9 | import SwiftUI 10 | 11 | struct FFCoreDataManagged: View { 12 | //将context作为环境变量传递给ContentView(我这里是FFCoreDataManagged),在此视图中添加一个@Environment属性来读取托管对象上下文。 13 | @Environment(\.managedObjectContext) var managedObjectContext 14 | var body: some View { 15 | Text("Hello, World!") 16 | } 17 | } 18 | 19 | #Preview { 20 | FFCoreDataManagged() 21 | } 22 | -------------------------------------------------------------------------------- /FFModifier/023 - CoreData/FFCoreDataNSUserActivity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFCoreDataNSUserActivity.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/30. 6 | // 7 | // 如何在SwiftUI中使用NSUserActivity 8 | // SwiftUI有一个专用的onContinueUserActivity()修饰符,可以捕获各种NSUserActivity类型,比如来自网络的点击、来自第三方或者Siri启动等等。在AppDelegate中使用application(_:continue:restorationHandler:)处理过这个问题,但SwiftUI方法更简单的处理这个问题。 9 | // 药实现这个需求,首先要创建一个函数并接受参数NSUserActivity,但是,不需要在App结构体中执行此操作。 10 | 11 | import SwiftUI 12 | 13 | struct FFCoreDataNSUserActivity: View { 14 | var body: some View { 15 | Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) 16 | } 17 | } 18 | 19 | #Preview { 20 | FFCoreDataNSUserActivity() 21 | } 22 | -------------------------------------------------------------------------------- /FFModifier/023 - CoreData/Main.xcdatamodeld/Main.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /FFModifier/024 - Accessibility/FFAccessibility.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFAccessibility.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/31. 6 | // 7 | // 关于SwiftUI的Accessibility 8 | // 默认情况下,SwiftUI引用程序具有非常高的可访问性,除非主动更改默认设置。 9 | // 这种行为的关键是SwiftUI布局是机遇Stack的方法。将视图放在Hstack和VStack中,一切都有默认的顺序,因此系统可以大致理解布局应该如何设定。相比之下,UIKit和AutoLayout可以将视图放在任何地方,因此系统必须有效的对视图应该如何排序做出最佳猜测。 10 | // SwiftUI还建议我们为所有的交互添加标签,明确用途。但是,我们可以屏蔽标签,以及它们被隐藏,系统仍然会使用它们作为屏幕阅读器的饮品提示。 11 | //因此,SwiftUI提供了很多的可访问性。然而,还有额外的工具来更好的体验来解决下面的问题: 12 | //- 屏幕阅读器应该如何阅读内容? 13 | //- 是否所有内容都需要阅读? 14 | //- 如果用户不喜欢复杂的动画怎么办? 15 | //- ... 16 | 17 | import SwiftUI 18 | 19 | struct FFAccessibility: View { 20 | var body: some View { 21 | Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) 22 | } 23 | } 24 | 25 | #Preview { 26 | FFAccessibility() 27 | } 28 | -------------------------------------------------------------------------------- /FFModifier/024 - Accessibility/FFAccessibilityDarkMode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFDarkMode.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/31. 6 | // 7 | // 如何检测深色模式 8 | //SwiftUI可以使用环境检测键(colorScheme)检测当前是否启用了深色模式或浅色模式。如果使用了@environment声明了此属性,就可以在视图中引用它,并且当配色方案更改时将自动加载 9 | 10 | import SwiftUI 11 | 12 | struct FFAccessibilityDarkMode: View { 13 | @Environment(\.colorScheme) var colorScheme 14 | var body: some View { 15 | Text(colorScheme == .dark ? "META BBLV in dark mode" : "META BBLV in light mode") 16 | } 17 | } 18 | 19 | #Preview { 20 | FFAccessibilityDarkMode() 21 | } 22 | -------------------------------------------------------------------------------- /FFModifier/024 - Accessibility/FFAccessibilityDecorative.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFAccessibilityDecorative.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/31. 6 | // 7 | // 如何使用装饰图像来减少屏幕阅读器的混乱 8 | // SwiftUI会自动使用图像名称作为屏幕阅读器标签,通常情况下会很有用。然而,有些图像并不适合阅读,因为它只是装饰性的。它们不会传达屏幕其他地方没有的信息,只是为了让用户界面看起来更好看。 9 | //Image("star")这种方式创建的图像,则会将她们作为标准UI的一部分读出。更好的方式是使用Image(decorative:)初始化程序来创建它们,它告诉SwiftUI图像不应该暴露给屏幕阅读去器。 10 | 11 | import SwiftUI 12 | 13 | struct FFAccessibilityDecorative: View { 14 | var body: some View { 15 | Image(decorative: "star") 16 | //通过这种方式构建的UI,使用VoiceOver检查时,屏幕阅读器是不会读出此标签的。 17 | } 18 | } 19 | 20 | #Preview { 21 | FFAccessibilityDecorative() 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/024 - Accessibility/FFAccessibilityVoiceControl.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFAccessibilityVoiceControl.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/31. 6 | // 7 | // 如何添加语音控制的自定义激活命令 8 | // SwiftUI的accessibilityInputLabels()修饰符可以提供一系列的字符串,当用户在其他设备上激活语音控制或完整键盘访问时,系统应监听这些字符串。accessibilityLabel()与accessibilityHint()不同。 9 | 10 | import SwiftUI 11 | 12 | struct FFAccessibilityVoiceControl: View { 13 | var body: some View { 14 | NavigationStack { 15 | Text("Your Content Here") 16 | .toolbar { 17 | Button { 18 | // remove this user 19 | } label: { 20 | Label("Remove User", systemImage: "trash") 21 | } 22 | .accessibilityHint("Removes this user form your account") 23 | .accessibilityInputLabels(["Remove User", "Remove", "Delete User", "Delete"]) 24 | } 25 | } 26 | } 27 | } 28 | 29 | #Preview { 30 | FFAccessibilityVoiceControl() 31 | } 32 | -------------------------------------------------------------------------------- /FFModifier/024 - Accessibility/FFAccessibilityVoiceOver.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFAccessibilityVoiceOver.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/31. 6 | // 7 | // 如何让VoiceOver单独朗读字符 8 | // 大多数的文本都可以作为单词阅读,但某些特殊文本(例如密码,股票代码和某些特定的数字)必须通过VoiceOver诸葛字母的阅读才能发挥作用。在SwiftUI中,可以使用speechSpellsOutCharacters()修饰符启用此功能。 9 | 10 | import SwiftUI 11 | 12 | struct FFAccessibilityVoiceOver: View { 13 | var body: some View { 14 | //当对整组元素启用辅助功能时,会有更好的结果 15 | VStack { 16 | Text("Your password is") 17 | Text("abCayer-muQai") 18 | .font(.title) 19 | .speechSpellsOutCharacters() 20 | } 21 | .accessibilityElement(children: .combine) 22 | //使用该代码,VoiceOver会自然的自动读出“你的密码是”,然后根据要求拼代码部分。 23 | } 24 | } 25 | 26 | #Preview { 27 | FFAccessibilityVoiceOver() 28 | } 29 | -------------------------------------------------------------------------------- /FFModifier/024 - Accessibility/FFFontDynamicType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFFontDynamicType.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/31. 6 | // 如何将DynamicType与自定义Font一起使用 7 | // 如果在iOS14或更高的版本,就可以实现自动移Font的自动缩放。但是,如果虚妄字体相对于特定动态类型进行缩放,则使用relativeTo修饰符 8 | 9 | import SwiftUI 10 | 11 | struct FFFontDynamicType: View { 12 | var body: some View { 13 | //使字体从24pt开始,但它会相对于Headline DynamicType字体进行缩放。 14 | Text("meta BBLv") 15 | .font(.custom("Georgia", size: 24, relativeTo: .headline)) 16 | //如果想禁用字体的动态类型,使用fixedSize修饰符字体大小,无论动态类型如何设置都不会影响字体大小 17 | Text("metabblv@163.com") 18 | .font(.custom("Georgia", fixedSize: 24)) 19 | } 20 | } 21 | 22 | #Preview { 23 | FFFontDynamicType() 24 | } 25 | -------------------------------------------------------------------------------- /FFModifier/024 - Accessibility/FFSpecifyDynamicType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFSpecifyDynamicType.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/8/31. 6 | // 7 | // 如何指定视图支持的动态类型的大小 8 | // SwiftUI对动态类型的自动支持意味着视图可以根据用户的偏好放大或缩小。但是,一些情况下会超出屏幕导致UI的不一致,可以使用dyanmicTypeSize()来限制 9 | 10 | import SwiftUI 11 | 12 | struct FFSpecifyDynamicType: View { 13 | var body: some View { 14 | VStack { 15 | //与固定值一起使用,意味着视图将忽略所有动态类型的大小 16 | Text("This will stay small") 17 | .dynamicTypeSize(.xxLarge) 18 | //可以指定范围 19 | Text("This won't go above large") 20 | .dynamicTypeSize(...DynamicTypeSize.large) 21 | 22 | Text("This will scale within a range") 23 | .dynamicTypeSize(DynamicTypeSize.large...DynamicTypeSize.xxxLarge) 24 | 25 | Text("This will scale to any Size") 26 | //许多用户喜欢以来较大的动态字体来使用App。但是,随着屏幕内信息量的增加,在某些特定的场景下要限制这种特性。 27 | } 28 | } 29 | } 30 | 31 | #Preview { 32 | FFSpecifyDynamicType() 33 | } 34 | -------------------------------------------------------------------------------- /FFModifier/025 - Tooling/FFToolingDiffenertSize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFToolingDiffenertSize.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/9/1. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct FFToolingDiffenertSize: View { 11 | var body: some View { 12 | Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) 13 | } 14 | } 15 | 16 | #Preview { 17 | FFToolingDiffenertSize() 18 | } 19 | -------------------------------------------------------------------------------- /FFModifier/025 - Tooling/FFToolingInstruments.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFToolingInstruments.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/9/4. 6 | // 7 | // 如何使用Instrument分析SwiftUI代码并识别缓慢布局 8 | // Xcode的Instruments工具附带了一组出色的SwiftUI分析功能,使我们能够确定视图重回的频率、计算视图主体缓慢的次数,甚至状态在实时变化的情况。 9 | 10 | import SwiftUI 11 | 12 | //首先,创建一个每0.01秒触发一次的计时器,并有一个显示随机值UUID的视图和一个button 13 | class FrequentUdater: ObservableObject { 14 | var timer: Timer? 15 | 16 | init() { 17 | timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true, block: { _ in 18 | self.objectWillChange.send() 19 | }) 20 | } 21 | } 22 | 23 | struct FFToolingInstruments: View { 24 | @StateObject private var updater = FrequentUdater() 25 | @State private var tapCount = 0 26 | 27 | var body: some View { 28 | VStack { 29 | Text("\(UUID().uuidString)") 30 | Button("Tap count: \(tapCount)") { 31 | tapCount += 1 32 | } 33 | } 34 | } 35 | } 36 | 37 | #Preview { 38 | FFToolingInstruments() 39 | } 40 | -------------------------------------------------------------------------------- /FFModifier/026 - PropertyWappers/FFPropertyWappers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFPropertyWappers.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/9/5. 6 | // 7 | // 了解Swift和SwiftUI中的属性包装器 8 | // SwiftUI严重依赖属性包装器来使我们的代码更易于阅读、编写和维护。即使以前不了解或者未使用过,但是在SwiftUI中有很多的@和$符号,你可能会很疑惑这是干嘛的? 9 | //属性包装器在Swift 5.1中引入的通用Swift功能,但相比于Swift,在SwiftUI中更加的常见,比如@Published、@ObservedObject和@EnvironmentObject等等,这都都是。 10 | //属性包装器的基本情况: 11 | //- 一些属性包装器可以实现原本不可能实现的效果,例如@State可以修改结构体的内部属性。 12 | //- 某些属性包装器特别要求在其他地方完成额外的工作,如果该工作未完成,则可能会使应用程序崩溃。例如@FetchRequest的使用前提将CoreData的托管对象context放入环境中。 13 | //- 一次只能使用一个属性包装器,那么@ObservedObject @Binding var value = SomeClass()是错误的声明。 14 | //- 尽管有些属性包装器看起来非常相似,但是作用是不同的,要在正确的场景使用它们,比如@Environment和@EnvironmentOjbect 15 | //- 在某些特定情况下,还可以创建自己的属性包装器。 16 | 17 | import SwiftUI 18 | 19 | struct FFPropertyWappers: View { 20 | var body: some View { 21 | Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) 22 | } 23 | } 24 | 25 | #Preview { 26 | FFPropertyWappers() 27 | } 28 | -------------------------------------------------------------------------------- /FFModifier/026 - PropertyWappers/FFPropertyWrapperFetchRequest.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFPropertyWrapperFetchRequest.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/9/6. 6 | // 7 | // 什么是@FetchRequest 8 | //SwiftUI为我们提供了一个专门用于处理CoreData获取请求的属性包装器,可以将数据直接嵌入到SwiftUI视图中,而无需编写额外的逻辑。 9 | //使用@FetchRequest至少提供一个值,即用于排列数据的排序描述符数组,还可以根据需求选择性提供参数来过滤数据。 10 | //在使用@FetchRequest之前,必须将CoreData托管对象上下文注入到环境中, 11 | 12 | import SwiftUI 13 | 14 | struct FFPropertyWrapperFetchRequest: View { 15 | 16 | @Environment(\.managedObjectContext) var managedObjectContext 17 | // SortDescriptors参数是一个数组,所以可以提供尽可能多的排序选项 18 | @FetchRequest( 19 | sortDescriptors: [] 20 | ) var languages: FetchedResults 21 | 22 | var body: some View { 23 | Text("Hello, World!") 24 | } 25 | } 26 | 27 | #Preview { 28 | FFPropertyWrapperFetchRequest() 29 | } 30 | -------------------------------------------------------------------------------- /FFModifier/026 - PropertyWappers/FFPropertyWrapperFocusState.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFPropertyWrapperFocusState.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/9/6. 6 | // 7 | // 什么是@FocusState 8 | //SwiftUI提供了一个特定的属性包装器来跟踪当前接受用户输入的视图,成为@FocusState。这可以绑定到一个Bool值以控制单个字段,或绑定到一个枚举以在多个字段之间进行控制。 9 | 10 | 11 | import SwiftUI 12 | 13 | //控制单个输入字段是否具有键盘焦点 14 | struct FFPropertyWrapperFocusState: View { 15 | @FocusState private var isUsernameFocused: Bool 16 | @State private var username = "meta BBLv" 17 | 18 | var body: some View { 19 | VStack { 20 | TextField("输入你的用户名", text: $username) 21 | .focused($isUsernameFocused) 22 | 23 | Button("切换焦点") { 24 | isUsernameFocused.toggle() 25 | } 26 | } 27 | } 28 | } 29 | 30 | #Preview { 31 | FFPropertyWrapperFocusState() 32 | } 33 | -------------------------------------------------------------------------------- /FFModifier/026 - PropertyWappers/FFPropertyWrapperScaledMetric.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFPropertyWrapperScaledMetric.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/9/6. 6 | // 7 | // 什么是@ScaledMetric 8 | //SwiftUI提供了@ScaleMetric属性包装器,用于定义根据用户的动态类型设置自动缩放的数字。 9 | 10 | import SwiftUI 11 | 12 | //在其基本用法中,为属性提供一个默认值,@ScaledMetric将处理其余部分。例如,根据用户的设置,以下代码将以不同的size绘制相同的图像 13 | struct FFPropertyWrapperScaledMetric: View { 14 | @ScaledMetric var imageSize = 100.0 15 | //如果需要使缩放与特定的其他文本匹配,可以为属性包装器使用relativeTo参数,该参数可以指定要匹配的字体大小。例如,与大标题大小一起缩放 16 | @ScaledMetric(relativeTo: .largeTitle) var titleSize = 100.0 17 | var body: some View { 18 | Image(systemName: "cloud.sun.bolt.fill") 19 | .resizable() 20 | .frame(width: imageSize, height: imageSize) 21 | } 22 | } 23 | 24 | #Preview { 25 | FFPropertyWrapperScaledMetric() 26 | } 27 | -------------------------------------------------------------------------------- /FFModifier/026 - PropertyWappers/FFPropertyWrapperSceneStorage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFPropertyWrapperSceneStorage.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/9/6. 6 | // 7 | // 什么是@SceneStorage 8 | //如果香味每个屏幕保存独特的数据,应该使用SwiftUI的@SceneStorage属性包装器。这与@AppStorage有些相似,需要为它提供一个名称来保存数据以及一个默认值,但与使用UserDefaults不同,它用于状态恢复,而且它甚至在iPadOS中经常看到的复杂多场景设置中非常好用。 9 | 10 | import SwiftUI 11 | 12 | //如果有一个文本编辑器,并希望存储用户正在输入的内容 13 | struct FFPropertyWrapperSceneStorage: View { 14 | @SceneStorage("text") var text = "" 15 | var body: some View { 16 | NavigationStack { 17 | TextEditor(text: $text) 18 | } 19 | } 20 | //因为使用了@SceneStorage,SwiftUI将自动确保每个场景实例都有其自己的文本,如果同时运行多个应用程序,都可以正确保存和恢复其数据。 21 | //现在,在使用@SceneStorage之前,有一些来自Apple的重要警告: 22 | //- 不要保存大量数据:只保存状态恢复的所需内容 23 | //- 用用不要将敏感数据存储在场景存储中,因为是不安全的。 24 | //- 如果用户赚到应用程序切换器并销毁应用程序,场景存储也将被销毁(iOS17上发现未销毁。) 25 | } 26 | 27 | #Preview { 28 | FFPropertyWrapperSceneStorage() 29 | } 30 | -------------------------------------------------------------------------------- /FFModifier/026 - PropertyWappers/FFPropertyWrapperState.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFPropertyWrapperState.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/9/6. 6 | // 7 | // 什么是@State属性包装器 8 | //SwiftUI使用@State属性包装器可以修改结构体中的值,在结构体中,由于结构体是值类型,默认情况下是不允许的。 9 | //使用@State修饰属性时,实际上将其存储在结构体中移除,并放入由SwiftUI管理的共享缓存中。这代表SwiftUI可以根据需要销毁并重新创建结构体(这在程序运行中可能会发生很多次!),而不会丢失它正在存储的状态。 10 | 11 | import SwiftUI 12 | 13 | struct FFPropertyWrapperState: View { 14 | //由于@State的特性是存储在SwiftUI的共享缓存中,Apple建议使用@State修饰的变量最好标记为private 15 | @State private var prompt = "meta BBLv" 16 | //当然,这不是必须选项,你也可以不使用private定义 17 | @State var hobby = "KEEP LOVING, KEEP LIVING" 18 | //当使用@State修饰引用类型的时候,数据发生更改时,不会收到通知,对于不符合ObservableObject协议的类有用。 19 | var body: some View { 20 | Text("Hello, World!") 21 | } 22 | } 23 | 24 | #Preview { 25 | FFPropertyWrapperState() 26 | } 27 | -------------------------------------------------------------------------------- /FFModifier/026 - PropertyWappers/FFPropertyWrapperStateObject.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FFPropertyWrapperStateObject.swift 3 | // FFModifier 4 | // 5 | // Created by BBLv on 2023/9/6. 6 | // 7 | // 什么是@StateObject 8 | //SwiftUI的@StateObject属性包装器旨在填补状态管理中的一个非特定的空白:当你需要在视图内创建一个引用类型并确保它在该视图与其他与之共享的视图中保持active状态时。 9 | 10 | import SwiftUI 11 | 12 | //创建一个User类,并遵守obserVableObject 13 | class StateObjectUser: ObservableObject { 14 | var username = "meta BBLv" 15 | } 16 | 17 | struct FFPropertyWrapperStateObject: View { 18 | //如果想在视图中使用它,可以在SwiftUI外部创建并注入,或者在SwiftUI中创建并使用@StateObject 19 | @StateObject var user = StateObjectUser() 20 | 21 | var body: some View { 22 | Text("Username: \(user.username)") 23 | //这将确保user实例视图更新时不会被销毁 24 | //以前,可以使用@ObservedObject来获得相同的结果,但这是不安全的操作。在极小的概率下@ObservedObject可能会意外释放它存储的对象,因为它并没有被设计成对象的最终数据源。说人话就是它不持有数据,不对数据负责。而@StateObject则不会出现此问题,所以引用类型要使用@StateObject修饰。 25 | //重要提示:在创建视图时负责对对象的创建,使用@StateObject创建的对象应该被创建一次,然后其他共享的视图使用@ObservedObject来共享对象。 26 | } 27 | } 28 | 29 | #Preview { 30 | FFPropertyWrapperStateObject() 31 | } 32 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/CustomAssetsColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "1.000", 9 | "green" : "1.000", 10 | "red" : "0.256" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "1.000", 27 | "green" : "0.294", 28 | "red" : "1.000" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/all-out-donuts-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "all-out-donuts-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "all-out-donuts-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/all-out-donuts-thumb.imageset/all-out-donuts-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/all-out-donuts-thumb.imageset/all-out-donuts-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/all-out-donuts-thumb.imageset/all-out-donuts-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/all-out-donuts-thumb.imageset/all-out-donuts-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/all-out-donuts.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "all-out-donuts@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "all-out-donuts@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/all-out-donuts.imageset/all-out-donuts@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/all-out-donuts.imageset/all-out-donuts@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/all-out-donuts.imageset/all-out-donuts@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/all-out-donuts.imageset/all-out-donuts@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/cheese-toastie-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "cheese-toastie-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "cheese-toastie-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/cheese-toastie-thumb.imageset/cheese-toastie-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/cheese-toastie-thumb.imageset/cheese-toastie-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/cheese-toastie-thumb.imageset/cheese-toastie-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/cheese-toastie-thumb.imageset/cheese-toastie-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/cheese-toastie.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "cheese-toastie@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "cheese-toastie@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/cheese-toastie.imageset/cheese-toastie@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/cheese-toastie.imageset/cheese-toastie@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/cheese-toastie.imageset/cheese-toastie@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/cheese-toastie.imageset/cheese-toastie@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/chrysanthemum-tea-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "chrysanthemum-tea-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "chrysanthemum-tea-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/chrysanthemum-tea-thumb.imageset/chrysanthemum-tea-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/chrysanthemum-tea-thumb.imageset/chrysanthemum-tea-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/chrysanthemum-tea-thumb.imageset/chrysanthemum-tea-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/chrysanthemum-tea-thumb.imageset/chrysanthemum-tea-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/chrysanthemum-tea.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "chrysanthemum-tea@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "chrysanthemum-tea@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/chrysanthemum-tea.imageset/chrysanthemum-tea@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/chrysanthemum-tea.imageset/chrysanthemum-tea@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/chrysanthemum-tea.imageset/chrysanthemum-tea@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/chrysanthemum-tea.imageset/chrysanthemum-tea@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/corn-on-the-cob-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "corn-on-the-cob-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "corn-on-the-cob-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/corn-on-the-cob-thumb.imageset/corn-on-the-cob-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/corn-on-the-cob-thumb.imageset/corn-on-the-cob-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/corn-on-the-cob-thumb.imageset/corn-on-the-cob-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/corn-on-the-cob-thumb.imageset/corn-on-the-cob-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/corn-on-the-cob.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "corn-on-the-cob@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "corn-on-the-cob@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/corn-on-the-cob.imageset/corn-on-the-cob@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/corn-on-the-cob.imageset/corn-on-the-cob@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/corn-on-the-cob.imageset/corn-on-the-cob@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/corn-on-the-cob.imageset/corn-on-the-cob@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/fillet-steak-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "fillet-steak-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "fillet-steak-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/fillet-steak-thumb.imageset/fillet-steak-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/fillet-steak-thumb.imageset/fillet-steak-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/fillet-steak-thumb.imageset/fillet-steak-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/fillet-steak-thumb.imageset/fillet-steak-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/fillet-steak.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "fillet-steak@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "fillet-steak@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/fillet-steak.imageset/fillet-steak@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/fillet-steak.imageset/fillet-steak@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/fillet-steak.imageset/fillet-steak@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/fillet-steak.imageset/fillet-steak@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/fresh-baked-croissant-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "fresh-baked-croissant-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "fresh-baked-croissant-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/fresh-baked-croissant-thumb.imageset/fresh-baked-croissant-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/fresh-baked-croissant-thumb.imageset/fresh-baked-croissant-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/fresh-baked-croissant-thumb.imageset/fresh-baked-croissant-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/fresh-baked-croissant-thumb.imageset/fresh-baked-croissant-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/fresh-baked-croissant.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "fresh-baked-croissant@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "fresh-baked-croissant@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/fresh-baked-croissant.imageset/fresh-baked-croissant@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/fresh-baked-croissant.imageset/fresh-baked-croissant@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/fresh-baked-croissant.imageset/fresh-baked-croissant@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/fresh-baked-croissant.imageset/fresh-baked-croissant@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/full-english-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "full-english-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "full-english-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/full-english-thumb.imageset/full-english-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/full-english-thumb.imageset/full-english-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/full-english-thumb.imageset/full-english-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/full-english-thumb.imageset/full-english-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/full-english.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "full-english@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "full-english@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/full-english.imageset/full-english@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/full-english.imageset/full-english@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/full-english.imageset/full-english@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/full-english.imageset/full-english@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/macarons-galore-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "macarons-galore-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "macarons-galore-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/macarons-galore-thumb.imageset/macarons-galore-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/macarons-galore-thumb.imageset/macarons-galore-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/macarons-galore-thumb.imageset/macarons-galore-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/macarons-galore-thumb.imageset/macarons-galore-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/macarons-galore.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "macarons-galore@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "macarons-galore@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/macarons-galore.imageset/macarons-galore@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/macarons-galore.imageset/macarons-galore@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/macarons-galore.imageset/macarons-galore@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/macarons-galore.imageset/macarons-galore@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/maple-french-toast-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "maple-french-toast-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "maple-french-toast-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/maple-french-toast-thumb.imageset/maple-french-toast-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/maple-french-toast-thumb.imageset/maple-french-toast-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/maple-french-toast-thumb.imageset/maple-french-toast-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/maple-french-toast-thumb.imageset/maple-french-toast-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/maple-french-toast.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "maple-french-toast@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "maple-french-toast@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/maple-french-toast.imageset/maple-french-toast@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/maple-french-toast.imageset/maple-french-toast@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/maple-french-toast.imageset/maple-french-toast@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/maple-french-toast.imageset/maple-french-toast@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/mexican-mocha-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "mexican-mocha-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "mexican-mocha-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/mexican-mocha-thumb.imageset/mexican-mocha-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/mexican-mocha-thumb.imageset/mexican-mocha-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/mexican-mocha-thumb.imageset/mexican-mocha-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/mexican-mocha-thumb.imageset/mexican-mocha-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/mexican-mocha.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "mexican-mocha@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "mexican-mocha@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/mexican-mocha.imageset/mexican-mocha@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/mexican-mocha.imageset/mexican-mocha@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/mexican-mocha.imageset/mexican-mocha@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/mexican-mocha.imageset/mexican-mocha@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/mushroom-tagliatelle-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "mushroom-tagliatelle-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "mushroom-tagliatelle-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/mushroom-tagliatelle-thumb.imageset/mushroom-tagliatelle-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/mushroom-tagliatelle-thumb.imageset/mushroom-tagliatelle-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/mushroom-tagliatelle-thumb.imageset/mushroom-tagliatelle-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/mushroom-tagliatelle-thumb.imageset/mushroom-tagliatelle-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/mushroom-tagliatelle.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "mushroom-tagliatelle@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "mushroom-tagliatelle@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/mushroom-tagliatelle.imageset/mushroom-tagliatelle@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/mushroom-tagliatelle.imageset/mushroom-tagliatelle@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/mushroom-tagliatelle.imageset/mushroom-tagliatelle@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/mushroom-tagliatelle.imageset/mushroom-tagliatelle@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/paella-alicante-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "paella-alicante-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "paella-alicante-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/paella-alicante-thumb.imageset/paella-alicante-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/paella-alicante-thumb.imageset/paella-alicante-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/paella-alicante-thumb.imageset/paella-alicante-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/paella-alicante-thumb.imageset/paella-alicante-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/paella-alicante.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "paella-alicante@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "paella-alicante@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/paella-alicante.imageset/paella-alicante@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/paella-alicante.imageset/paella-alicante@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/paella-alicante.imageset/paella-alicante@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/paella-alicante.imageset/paella-alicante@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/penne-carbonara-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "penne-carbonara-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "penne-carbonara-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/penne-carbonara-thumb.imageset/penne-carbonara-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/penne-carbonara-thumb.imageset/penne-carbonara-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/penne-carbonara-thumb.imageset/penne-carbonara-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/penne-carbonara-thumb.imageset/penne-carbonara-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/penne-carbonara.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "penne-carbonara@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "penne-carbonara@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/penne-carbonara.imageset/penne-carbonara@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/penne-carbonara.imageset/penne-carbonara@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/penne-carbonara.imageset/penne-carbonara@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/penne-carbonara.imageset/penne-carbonara@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/pepperoni-pizza-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "pepperoni-pizza-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "pepperoni-pizza-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/pepperoni-pizza-thumb.imageset/pepperoni-pizza-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/pepperoni-pizza-thumb.imageset/pepperoni-pizza-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/pepperoni-pizza-thumb.imageset/pepperoni-pizza-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/pepperoni-pizza-thumb.imageset/pepperoni-pizza-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/pepperoni-pizza.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "pepperoni-pizza@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "pepperoni-pizza@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/pepperoni-pizza.imageset/pepperoni-pizza@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/pepperoni-pizza.imageset/pepperoni-pizza@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/pepperoni-pizza.imageset/pepperoni-pizza@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/pepperoni-pizza.imageset/pepperoni-pizza@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/pesto-farfalle-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "pesto-farfalle-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "pesto-farfalle-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/pesto-farfalle-thumb.imageset/pesto-farfalle-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/pesto-farfalle-thumb.imageset/pesto-farfalle-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/pesto-farfalle-thumb.imageset/pesto-farfalle-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/pesto-farfalle-thumb.imageset/pesto-farfalle-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/pesto-farfalle.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "pesto-farfalle@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "pesto-farfalle@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/pesto-farfalle.imageset/pesto-farfalle@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/pesto-farfalle.imageset/pesto-farfalle@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/pesto-farfalle.imageset/pesto-farfalle@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/pesto-farfalle.imageset/pesto-farfalle@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/porridge-deluxe-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "porridge-deluxe-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "porridge-deluxe-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/porridge-deluxe-thumb.imageset/porridge-deluxe-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/porridge-deluxe-thumb.imageset/porridge-deluxe-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/porridge-deluxe-thumb.imageset/porridge-deluxe-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/porridge-deluxe-thumb.imageset/porridge-deluxe-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/porridge-deluxe.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "porridge-deluxe@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "porridge-deluxe@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/porridge-deluxe.imageset/porridge-deluxe@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/porridge-deluxe.imageset/porridge-deluxe@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/porridge-deluxe.imageset/porridge-deluxe@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/porridge-deluxe.imageset/porridge-deluxe@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/power-muesli-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "power-muesli-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "power-muesli-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/power-muesli-thumb.imageset/power-muesli-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/power-muesli-thumb.imageset/power-muesli-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/power-muesli-thumb.imageset/power-muesli-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/power-muesli-thumb.imageset/power-muesli-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/power-muesli.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "power-muesli@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "power-muesli@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/power-muesli.imageset/power-muesli@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/power-muesli.imageset/power-muesli@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/power-muesli.imageset/power-muesli@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/power-muesli.imageset/power-muesli@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/powerhouse-coffee-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "powerhouse-coffee-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "powerhouse-coffee-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/powerhouse-coffee-thumb.imageset/powerhouse-coffee-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/powerhouse-coffee-thumb.imageset/powerhouse-coffee-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/powerhouse-coffee-thumb.imageset/powerhouse-coffee-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/powerhouse-coffee-thumb.imageset/powerhouse-coffee-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/powerhouse-coffee.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "powerhouse-coffee@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "powerhouse-coffee@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/powerhouse-coffee.imageset/powerhouse-coffee@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/powerhouse-coffee.imageset/powerhouse-coffee@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/powerhouse-coffee.imageset/powerhouse-coffee@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/powerhouse-coffee.imageset/powerhouse-coffee@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/stack-o-pancakes-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "stack-o-pancakes-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "stack-o-pancakes-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/stack-o-pancakes-thumb.imageset/stack-o-pancakes-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/stack-o-pancakes-thumb.imageset/stack-o-pancakes-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/stack-o-pancakes-thumb.imageset/stack-o-pancakes-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/stack-o-pancakes-thumb.imageset/stack-o-pancakes-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/stack-o-pancakes.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "stack-o-pancakes@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "stack-o-pancakes@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/stack-o-pancakes.imageset/stack-o-pancakes@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/stack-o-pancakes.imageset/stack-o-pancakes@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/stack-o-pancakes.imageset/stack-o-pancakes@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/stack-o-pancakes.imageset/stack-o-pancakes@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/straight-up-oj-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "straight-up-oj-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "straight-up-oj-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/straight-up-oj-thumb.imageset/straight-up-oj-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/straight-up-oj-thumb.imageset/straight-up-oj-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/straight-up-oj-thumb.imageset/straight-up-oj-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/straight-up-oj-thumb.imageset/straight-up-oj-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/straight-up-oj.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "straight-up-oj@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "straight-up-oj@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/straight-up-oj.imageset/straight-up-oj@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/straight-up-oj.imageset/straight-up-oj@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/straight-up-oj.imageset/straight-up-oj@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/straight-up-oj.imageset/straight-up-oj@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/strawberry-cooler-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "strawberry-cooler-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "strawberry-cooler-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/strawberry-cooler-thumb.imageset/strawberry-cooler-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/strawberry-cooler-thumb.imageset/strawberry-cooler-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/strawberry-cooler-thumb.imageset/strawberry-cooler-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/strawberry-cooler-thumb.imageset/strawberry-cooler-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/strawberry-cooler.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "strawberry-cooler@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "strawberry-cooler@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/strawberry-cooler.imageset/strawberry-cooler@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/strawberry-cooler.imageset/strawberry-cooler@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/strawberry-cooler.imageset/strawberry-cooler@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/strawberry-cooler.imageset/strawberry-cooler@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/strawberry-surprise-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "strawberry-surprise-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "strawberry-surprise-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/strawberry-surprise-thumb.imageset/strawberry-surprise-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/strawberry-surprise-thumb.imageset/strawberry-surprise-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/strawberry-surprise-thumb.imageset/strawberry-surprise-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/strawberry-surprise-thumb.imageset/strawberry-surprise-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/strawberry-surprise.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "strawberry-surprise@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "strawberry-surprise@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/strawberry-surprise.imageset/strawberry-surprise@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/strawberry-surprise.imageset/strawberry-surprise@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/strawberry-surprise.imageset/strawberry-surprise@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/strawberry-surprise.imageset/strawberry-surprise@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/super-sundae-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "super-sundae-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "super-sundae-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/super-sundae-thumb.imageset/super-sundae-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/super-sundae-thumb.imageset/super-sundae-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/super-sundae-thumb.imageset/super-sundae-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/super-sundae-thumb.imageset/super-sundae-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/super-sundae.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "super-sundae@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "super-sundae@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/super-sundae.imageset/super-sundae@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/super-sundae.imageset/super-sundae@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/super-sundae.imageset/super-sundae@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/super-sundae.imageset/super-sundae@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/superfood-salad-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "superfood-salad-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "superfood-salad-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/superfood-salad-thumb.imageset/superfood-salad-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/superfood-salad-thumb.imageset/superfood-salad-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/superfood-salad-thumb.imageset/superfood-salad-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/superfood-salad-thumb.imageset/superfood-salad-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/superfood-salad.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "superfood-salad@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "superfood-salad@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/superfood-salad.imageset/superfood-salad@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/superfood-salad.imageset/superfood-salad@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/superfood-salad.imageset/superfood-salad@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/superfood-salad.imageset/superfood-salad@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/thai-red-curry-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "thai-red-curry-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "thai-red-curry-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/thai-red-curry-thumb.imageset/thai-red-curry-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/thai-red-curry-thumb.imageset/thai-red-curry-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/thai-red-curry-thumb.imageset/thai-red-curry-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/thai-red-curry-thumb.imageset/thai-red-curry-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/thai-red-curry.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "thai-red-curry@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "thai-red-curry@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/thai-red-curry.imageset/thai-red-curry@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/thai-red-curry.imageset/thai-red-curry@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/thai-red-curry.imageset/thai-red-curry@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/thai-red-curry.imageset/thai-red-curry@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/tower-burger-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "tower-burger-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "tower-burger-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/tower-burger-thumb.imageset/tower-burger-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/tower-burger-thumb.imageset/tower-burger-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/tower-burger-thumb.imageset/tower-burger-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/tower-burger-thumb.imageset/tower-burger-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/tower-burger.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "tower-burger@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "tower-burger@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/tower-burger.imageset/tower-burger@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/tower-burger.imageset/tower-burger@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/tower-burger.imageset/tower-burger@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/tower-burger.imageset/tower-burger@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/veggie-pizza-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "veggie-pizza-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "veggie-pizza-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/veggie-pizza-thumb.imageset/veggie-pizza-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/veggie-pizza-thumb.imageset/veggie-pizza-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/veggie-pizza-thumb.imageset/veggie-pizza-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/veggie-pizza-thumb.imageset/veggie-pizza-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/veggie-pizza.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "veggie-pizza@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "veggie-pizza@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/veggie-pizza.imageset/veggie-pizza@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/veggie-pizza.imageset/veggie-pizza@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/veggie-pizza.imageset/veggie-pizza@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/veggie-pizza.imageset/veggie-pizza@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/virgin-mojito-thumb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "virgin-mojito-thumb@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "virgin-mojito-thumb@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/virgin-mojito-thumb.imageset/virgin-mojito-thumb@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/virgin-mojito-thumb.imageset/virgin-mojito-thumb@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/virgin-mojito-thumb.imageset/virgin-mojito-thumb@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/virgin-mojito-thumb.imageset/virgin-mojito-thumb@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/virgin-mojito.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "virgin-mojito@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "filename" : "virgin-mojito@3x.jpg", 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "author" : "xcode", 20 | "version" : 1 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/virgin-mojito.imageset/virgin-mojito@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/virgin-mojito.imageset/virgin-mojito@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/Images/virgin-mojito.imageset/virgin-mojito@3x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/Images/virgin-mojito.imageset/virgin-mojito@3x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/chincoteague.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "chincoteague@2x.jpg", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/chincoteague.imageset/chincoteague@2x.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Assets.xcassets/chincoteague.imageset/chincoteague@2x.jpg -------------------------------------------------------------------------------- /FFModifier/Assets.xcassets/ff.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.522", 9 | "green" : "1.000", 10 | "red" : "1.000" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "srgb", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "1.000", 27 | "green" : "0.485", 28 | "red" : "0.452" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /FFModifier/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /FFModifier/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /FFModifier/Video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MetaBBLv/SwiftUIModifier/3b0a1181f8ea5a46e9289bb9e7f6afc3188fa5b5/FFModifier/Video.mp4 --------------------------------------------------------------------------------