Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Tweak your iOS app without recompiling!

License

NotificationsYou must be signed in to change notification settings

bryanjclark/SwiftTweaks

Repository files navigation

Adjust your iOS app on the fly without waiting to re-compile!

SwiftTweaks Icon

Your users won’t see your animation study, Sketch comps, or prototypes. What they will see is the finished product - so it’s really important to make sure that your app feels right on a real device!

Animations that look great on your laptop often feel too slow when in-hand. Layouts that looks perfect on a 27-inch display might be too cramped on a 4-inch device. Light gray text may look subtle in Sketch, but it’s downright illegible when you’re outside on a sunny day.

These animation timings, font sizes, and color choices are all examples of “magic numbers” - the constants that give your app its usability and identity. The goal of SwiftTweaks: allow you to fine-tune these magic numbers in the debug builds of your Swift project, without having to wait for Xcode to rebuild the app.

Tweaks

SwiftPM compatibleCarthage compatibleVersionGitHub releaseSwift 5.0platformsBuild Status

Overview

Use aTweak in place of a boolean, number, or color in your code. You can adjust thatTweak without having to recompile, which means you can play with animation timings, colors, and layouts without needing Xcode!

Currently, you can tweak the following types:

  • Bool
  • Int
  • CGFloat
  • Double
  • UIColor
  • TweakAction
  • String
  • StringOption

ATweak looks like this:

publicstaticletcolorTint=Tweak("General","Colors","Tint",UIColor.blueColor())

There are also helpfulTweakGroupTemplate types, so you can quickly declare commonly-used-together combos. They all have sensible defaults, but of course, you can set your own!

// Controls delay and duration for UIView.animate// Use it with UIView.animate(basicTweakTemplate:...)publicstaticletbasicAnimation=BasicAnimationTweakTemplate("Animation","Basic Animation")// Controls delay, duration, damping, and initial spring velocity for UIView.animate// Use it with UIView.animate(springTweakTemplate:...)publicstaticletspringAnimation=SpringAnimationTweakTemplate("Animation","Spring Animation")// Controls shadow color, radius, offset, and opacity for CALayer// Use it with CALayer.apply(shadowTweakTemplate:...)publicstaticletshadowTweak=ShadowTweakTemplate("Shadows","Button Shadow")// Controls top/right/bottom/left for UIEdgeInsets// Use it with UIEdgeInsets.init(edgeInsetsTweakTemplate)publicstaticletedgeInsets=EdgeInsetsTweakTemplate("Layout","Screen Edge Insets")

Of course, you can create your ownTweakGroupTemplate type if you'd like - they're handy whenever you have a cluster of tweaks that need to be used together to get a desired effect. They can be built out of any combination ofTweaks.

Tweaks

Actions

SwiftTweaks now supports closures, so you can perform actions that do not depend on data from SwiftTweaks. To do this, useTweakAction as a type in yourTweakStore to create a Tweak that executes your custom closures:

publicstaticletaction=Tweak<TweakAction>("Actions","Action","Perform some action")

Later in the code you can add closures to that tweak, which are executed when a button in Tweaks window is pressed.

letidenfitier=ExampleTweaks.action.addClosure{/// Some complicated action happens hereprint("We're all done!")}

If you want to, you can also always remove closure using unique idenfitier thataddClosure method provides.

ExampleTweaks.action.removeClosure(with: idenfitier)

Wait, what aboutFacebook Tweaks?

Good question! I’m glad you asked.The whole reason SwiftTweaks exists is because we love the stuffing out of FBTweaks. We’re long-time fans of FBTweaks in our Objective-C projects: Replace the magic numbers with anFBTweak macro, and you’re all set! You can leave an FBTweak macro in your production code, because it’s replaced at compile-time with the tweak’s default value.

But Swift doesn’t support this macro-wizardry, so FBTweaks is burdensome to use in Swift code. Our app is nearly all Swift, so we wanted to see if we could make something that was a little easier!

Steps to Tweaking

There are three steps to add SwiftTweaks to your project:

  1. Create aTweakLibraryType, which contains a set ofTweaks and aTweakStore to persist them.
  2. Reference thatTweakLibraryType in your code to use aTweak.
  3. In your AppDelegate, make theTweakWindow the window of your app (there are other options, but this is the most straightforward! More on that later.)

Now build-and-run, then shake your phone to bring up the Tweaks UI! Adjust tweaks, and when you’re satisfied with what you’ve got, share your tweaks with others from within the Tweaks UI.

Step One: Make your TweakLibrary

A tweak library is responsible for listing out a bunch ofpublic static tweaks, and building aTweakStore. A tweak library looks like this:

publicstructExampleTweaks:TweakLibraryType{publicstaticletcolorTint=Tweak("General","Colors","Tint",UIColor.blue)publicstaticletmarginHorizontal=Tweak<CGFloat>("General","Layout","H. Margins", defaultValue:15, min:0)publicstaticletmarginVertical=Tweak<CGFloat>("General","Layout","V. Margins", defaultValue:10, min:0)publicstaticletfont=Tweak<StringOption>("General","Layout","Font", options:["AvenirNext","Helvetica","SanFrancisco"])publicstaticletfeatureFlagMainScreenHelperText=Tweak<Bool>("Feature Flags","Main Screen","Show Body Text",true)publicstaticletbuttonAnimation=SpringAnimationTweakTemplate("Animation","Button Animation")publicstaticletdefaultStore:TweakStore={letallTweaks:[TweakClusterType]=[colorTint, marginHorizontal, marginVertical, featureFlagMainScreenHelperText, buttonAnimation]lettweaksEnabled=TweakDebug.isActivereturnTweakStore(tweaks: allTweaks,enabled: tweaksEnabled)}()}

Let’s break down what happened here:

  • We have five tweaks inExampleTweaks: a tint color, twoCGFloats for layout, aStringOption for font choice, and aBool that toggles an in-development feature.
  • The compiler can get confused betweenInt,CGFloat, andDouble - so you might find it necessary to tell theTweak<T> what type itsT is - as we do here with our margin tweaks.
  • We create adefaultStore by creating aTweakStore, which needs to know whether tweaks areenabled, and a list of alltweaks.
  • Theenabled flag onTweakStore exists so thatSwiftTweaks isn’t accessible by your users in production. You can set it however you like; we enjoy using theDEBUG flag from our project’s Build Settings.

Step Two: Using Your TweakLibrary

To use a tweak, you replace a number orUIColors in your code with aTweak reference, like this:

Here’s our original code:

button.tintColor=UIColor.green

assign returns the current value of the tweak:

button.tintColor=ExampleTweaks.assign(ExampleTweaks.colorTint)

bind calls its closure immediately, and again each time the tweak changes:

ExampleTweaks.bind(ExampleTweaks.colorTint){ button.tintColor= $0}

bindMultiple calls its closure immediately, and again each time any of its tweaks change:

// A "multipleBind" is called initially, and each time _any_ of the included tweaks change:lettweaksToWatch:[TweakType]=[ExampleTweaks.marginHorizontal,ExampleTweaks.marginVertical]ExampleTweaks.bindMultiple(tweaksToWatch){lethorizontal=ExampleTweaks.assign(ExampleTweaks.marginHorizontal)letvertical=ExampleTweaks.assign(ExampleTweaks.marginVertical)scrollView.contentInset=UIEdgeInsets(top: vertical, right: horizontal, bottom: vertical, left: horizontal)}

For more examples, check out the example project’sViewController.swift file.

Step Three: Set TweakWindow as your Root View Controller

By default, SwiftTweaks uses a shake gesture to bring up the UI, but you can also use a custom gesture!

Installation

Swift Package Manager

SwiftTweaks is available via the Swift Package Manager; add it to Xcode with this URL:

https://github.com/Khan/SwiftTweaks

It's also listed in the (excellent)Swift Package Index!

To addSwiftTweaks to your application, add it to yourCartfile:

github "Khan/SwiftTweaks"

In addition, add-DDEBUG toOther Swift Flags in your project's Build Settings for yourDebug configuration.

pod'SwiftTweaks'# Enable DEBUG flag in Swift for SwiftTweakspost_installdo |installer|installer.pods_project.targets.eachdo |target|iftarget.name =='SwiftTweaks'target.build_configurations.eachdo |config|ifconfig.name =='Debug'config.build_settings['OTHER_SWIFT_FLAGS']='-DDEBUG'endendendendend

FAQ

Do Ihave to set TweakWindow as the root of my app?

Nope! Wherever/however you prefer, just create aTweaksViewController like so:

let tweaksVC = TweaksViewController(tweakStore: ExampleTweaks.defaultStore, delegate: self)

Can I have multipleTweakLibraryTypes in my app?

Sure! You’d initialize theirdefaultStores with a uniquestoreName identifier, like so:

publicstructFirstTweaksLibrary:TweakLibraryType{// ...publicstaticletdefaultStore:TweakStore={letallTweaks:[TweakClusterType]= //...return TweakStore(tweaks: allTweaks,storeName:"FirstTweaksLibrary", // Here's the identifierenabled: tweaksEnabled)}()}

Why can’t any type be used for aTweak?

WhileTweak<T> is generic, we have to restrictT to beTweakableType so that we can guarantee that each kind ofT can be represented in our editing interface and persisted on disk. More types would be awesome, though! It’d be neat to support dictionaries, closures, and other things.

If you’d like to extendTweakableType, you’ll need to extend some internal components, likeTweakViewDataType,TweakDefaultData,TweakViewData, andTweakPersistency. Feel free to open a pull request if you’d like to add a new type!

How do I create a new TweakGroupTemplate?

Maybe you’re using a different animation framework, or want a template forCGRect or something like that - great! As long as the tweakable “components” of your template conform toTweakableType then you’re all set. Create a newTweakGroupTemplateType, and take a look at the existing templates for implementation suggestions. (You’ll probably want to useSignedNumberTweakDefaultParameters too - they’re very helpful!)

If you think yourTweakGroupTemplateType would help out others, please make a pull request!


[8]ページ先頭

©2009-2025 Movatter.jp