Giter Club home page Giter Club logo

cyborg's Introduction

Cyborg

Build Status CII Best Practices Carthage compatible

Cyborg is a partial port of Android's VectorDrawable to iOS. It is intended as a replacement for UIImages, Icon Fonts, and Apple's PDF vector image option. The VectorDrawable format provides a number of advantages:

  • Full theming support of individual elements of an illustration, beyond simple image tinting or changing the text color in an Icon Font
  • Ability to use one asset for both platforms, simplifying the design -> engineering pipeline
  • Assets are resolution independent
  • RTL support
  • Easily convertible from SVG using Android Studio or third-party tools

Cyborg also supports MacOS (AppKit), TvOS, and can be used from SwiftUI. However, be aware that these implementations are currently less mature than the iOS version.

Performance Comparisons

We benchmarked Cyborg against a number of alternatives, loading the 50+ icons contained in our Driver app's icon set.

  • Cyborg's parser is faster than the iOS SVG libraries we could find
  • It tends to be a tiny bit slower than UIImage. The differences should be in the fractions of milliseconds in practice
  • An icon font with ~50 icons can be loaded in the time that it takes to load around 2-3 drawables of similar complexity.

If parsing performance becomes an issue, you may wish to implement either a caching mechanism appropriate for your application, or take advantage of Cyborg's thread safety to perform parsing off the main thread.

With that said, many performance improvement opportunities currently exist, so performance should improve in the future. As of this writing, Swift is a young language, and performance improvements to it, particularly in String creation, closures, and ownership should also have a positive impact on Cyborg's performance.

The full list of features is enumerated in the Android Documentation.

Installing Cyborg

Cyborg supports Swift Package Manager and Carthage.

To install using Carthage:

  1. Get Carthage.
  2. Add the following to your CartFile: github "uber/cyborg" ~> [desired version]

To add Cyborg to an Xcode project using Swift Package Manager, follow the instructions provided by Apple.

Using Cyborg

After following the integration steps below, using Cyborg requires only slightly more code than using a UIImage:

let vectorView = VectorView(theme: myTheme)
vectorView.drawable = VectorDrawable.named("MyDrawable")

Integration

Cyborg is made to scale up to complex uses cases, and as such require a bit of configuration to get the clean code sample above.

Let's see how to write the minimal integration to get started:

Implementing Themes and Resources

One of the best features of VectorDrawables is the ability to swap in arbitrary values at runtime. Well authored VectorDrawable assets can change their colors in response to changes in app state, such as a night mode.

However, gaining access to these powerful features requires us to write our own Theme and Resource providers:

class Theme: Cyborg.ThemeProviding {

    func colorFromTheme(named _: String) -> UIColor {
        return .black
    }

}

class Resources: ResourceProviding {

    func colorFromResources(named _: String) -> UIColor {
        return .black
    }

}

Assuming that resources never change, we can now write the convenience initializer depicted in the first code sample:

fileprivate let resources = Resources()

extension VectorDrawable {
    public convenience init(theme: Theme) {
        self.init(theme: theme, resources: resources()
    }
}

Reporting Drawable Parse Errors:

If, for some reason, you provide an invalid VectorDrawable to Cyborg, the standard creation function in Cyborg will give you a detailed error message that you can report as a nonfatal to the crash reporting service of your choice and use to debug locally. This can be handled at your app's "platform" level, allowing you to write code that assumes that the parsing always succeeds, just like with UIImage:

extension VectorDrawable {
    public static func named(_ name: String) -> VectorDrawable? {
        return Bundle.main.url(forResource: name, withExtension: "xml").flatMap { url in
        switch VectorDrawable.create(from: url) {
            case .ok(let drawable):
                return drawable
            case .error(let error):
               myAssertionFailureThatAlsoReportsToBackend("Could not create a vectordrawable named \(name); the error was \(error)")
               return nil
        }
    }
}

Best Practices

Lint VectorDrawable Assets

As you may already have noticed, the Theme and Resource objects you wrote in an earlier section are stringly typed. To prevent issues with assets that reference nonexistent theme or resource colors, you may want to lint the xml files to ensure that they are valid.

Store Your VectorDrawables in a Single Repo

You may find it convenient to allow designers to commit new assets directly to a repo that can be pulled into your Android and iOS repos by designers.

Snapshot Test Your VectorDrawables

The easiest way to ensure correctness of your UIs that use static vector drawables is to snapshot test the UIs that use them using a tool like iOSSnapshotTestCase. This will ensure that any code that isn't compiler-verified matches your expectations.

cyborg's People

Contributors

alanzeino avatar ashare80 avatar benpious avatar catri0na avatar sbarow avatar seljabali avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cyborg's Issues

Better Error Messages

Currently most error messages are blank, or are extremely generic, and there are ugly hacks like passing in whether to show an error or not for literal parsers.

Error messages should provide useful information, and they should be unit tested.

Implement blend mode

The spec allows a blend mode for the tint color. We have an enum representation of the tint color, but the modes haven't been implemented.

Investigate potential bug in prior context

The spec specifies that only certain commands should use parts of the "prior context" construct that we use in DrawingCommands.swift to convey information about prior curves in the path.

The fact that we are seemingly more liberal than the spec, and would allow, for example, a T command to use prior context from a C command. This may be responsible for bugs like the one below in rendering the flag of Sri Lanka.

Screen Shot 2020-05-12 at 12 13 15 PM

Support all drawing commands

We support most drawing commands in DrawingCommand.swift, but there are several we don't, including arc, arc absolute, reflected quadratic, and reflected quadratic absolute.

Implement Auto-Mirror

Some VectorDrawables should be automatically mirrored. We can parse this, but we don't do anything with the information yet.

Investigate Swift 5 String Performance

In Swift 5 String will use UTF-8 instead of UTF-16, which means that it won't need to do allocations to access the raw buffer for strtod, and converting from XMLChar buffers will be cheaper. We may be able to get rid of XMLString as a result.

Error parsing vector that Android is happy with

I've got a few vector assets that render fine in Android but fail with "Error parsing the android:pathData tag: Expected one of the path commands, but found "t"". Perhaps this is due to how the assets were created, or perhaps it's a Cyborg issue (I haven't had time to really dig into it).

I can provide an example if anybody wants to recreate/debug, unless you have a "it's probably this" solution?

Many thanks.

Add asynchronous loading mode

It should be possible to load drawables off the main thread. The parser should already be thread safe, so the interesting part of the task here is deciding how to handle the concurrency: whether it should be hidden from the user, whether there should be a placeholder or whether it should be converted to blocking when it's time to display a drawable onscreen, etc.

This shouldn't change the existing priorities for performance, we should still be aiming to be faster than competing libraries even when we're exclusively on the main thread.

Support gradients

The spec supports them, though it doesn't seem like they're very popular. At least one of these will require custom drawing code, as it's not natively supported on iOS.

Support Animated VectorDrawables

Android supports this. We may want to support it too.

We'll need to investigate whether this is actually a popular enough feature of the Android SDK to justify support, as Lottie is already an excellent cross platform option for those who need this feature.

The main blocker to this is that it will likely require a new API that allows loading off the main thread but can return the size of the drawable immediately, as animated drawables will likely be significantly larger than static ones, but we should be able to return something that has a size immediately. This may imply a more complex data structure than the VectorDrawable struct that can be passed around while it's still deserializing off the main thread, then can notify its displaying view (if it has one) once it's done.

Support multiple move ops

Vector drawables with paths of the form M 0 1 0 2 are currently rejected, though they are actually valid (though meaningless) SVG paths.

Support Interface Builder

It would be extremely useful to support placement of VectorViews in Interface Builder. Programmatic layout is cumbersome and increases development time.

CocoaPods Support

Please add a Podfile so the library could also be integrated via CocoaPods.

Add Snapshot tests

There's a couple of options for this:

  1. Generate snapshots using android studio, compare against them with low tolerance.
  2. Generate with Cyborg
  3. "Snapshot" path output instead of images themselves. Has the advantage of being immune to minor changes in the iOS rasterization algorithms, disadvantage is we might miss major changes, and they aren't self documenting. Our representation would be smaller than images though, which is good for repo binary size.

Improved SwiftUI Support

We currently have experimental support for SwiftUI. However, it has yet to be used in any real Apps, so there may be issues with the API that we need to address.

Our use of EnvironmentValues is also not currently ideal, as summarized here.

We may wish to reimplement VectorDrawableView using GeometryReader and Paths, which which could allow us to take advantage of the Environment colors provided by Apple if they improve the API to allow us to get a color for a String.

Add project status disclaimer

In an effort to provide more transparency to project state, Add the appropriate disclaimer on the top of the README.

Some examples as follows:
-This project is a technical snapshot and will not be kept in sync.
-This project is deprecated and not maintained.
-This project is experimental and the APIs are not considered stable.
-This project is stable and being incubated for long-term support
-This project may contain experimental code and may not be ready for general use. Support and/or new releases may be limited.

How to change android:fillColor

I want to set different fill color for same vector xml file for different screen. Is there any way to change android:fillColor programatically?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.