Compare commits

..

1 Commits

Author SHA1 Message Date
liukegang
19035c90e9 [bugfix] rm duplication process dimension 2019-06-11 21:15:29 +08:00
949 changed files with 90079 additions and 163203 deletions

10
.buckconfig Normal file
View File

@@ -0,0 +1,10 @@
[cxx]
gtest_dep = //lib/gtest:gtest
[android]
target = android-25
build_tools_version = 26.0.2
[ndk]
ndk_version = 15.2.4203891
compiler = clang
app_platform = android-21
cpu_abis = arm64, armv7, x86, x86_64

View File

@@ -1,91 +1,48 @@
AccessModifierOffset: -1
Language: Cpp
AccessModifierOffset: -2
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveBitFields: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: DontAlign
AlignOperands: false
AlignTrailingComments: false
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BreakBeforeBinaryOperators: None
BreakBeforeBinaryOperators: false
BreakBeforeBraces: Attach
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false
BreakInheritanceList: BeforeColon
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
FixNamespaceComments: true
ForEachMacros:
- FOR_EACH
- FOR_EACH_R
- FOR_EACH_RANGE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^<.*\.h(pp)?>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IndentCaseLabels: true
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PenaltyReturnTypeOnItsOwnLine: 2000
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterCStyleCast: true
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
@@ -93,17 +50,7 @@ SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard: Latest
TabWidth: 8
UseCRLF: false
Standard: Cpp11
UseTab: Never

1
.clang-format-ignore Normal file
View File

@@ -0,0 +1 @@
^lib/.*

View File

@@ -1,89 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
module.exports = {
root: true,
ignorePatterns: [
'/website',
'**/binaries/**',
'**/build/**',
'**/generated/**',
],
overrides: [
// Catch-all
{
files: ['**/*.?(m|c){j,t}s?(x)'],
extends: ['eslint:recommended', 'plugin:prettier/recommended'],
plugins: ['prettier'],
rules: {
'no-unused-vars': ['error', {argsIgnorePattern: '^_'}],
'no-var': 'error',
'prefer-arrow-callback': 'error',
'prefer-const': 'error',
'prefer-object-spread': 'error',
'prefer-spread': 'error',
'require-await': 'error',
},
env: {
es2020: true,
'shared-node-browser': true,
},
parserOptions: {
ecmaVersion: 'latest',
},
},
// ES Modules
{
files: ['**/*.?(m){j,t}s?(x)'],
parserOptions: {
sourceType: 'module',
},
},
// CommonJS Modules
{
files: ['**/*.c{j,t}s?(x)'],
env: {
commonjs: true,
},
parserOptions: {
sourceType: 'commonjs',
},
},
// TypeScript
{
files: ['**/*.?(m|c)ts?(x)'],
extends: ['plugin:@typescript-eslint/recommended'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: true,
},
plugins: ['@typescript-eslint'],
rules: {
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{argsIgnorePattern: '^_'},
],
'@typescript-eslint/no-var-requires': 'off',
},
},
// Node
{
files: ['**/.*rc.(c){j,t}s', '**/*.config.?(c){j,t}s'],
env: {
node: true,
},
},
// Jest
{
files: ['**/tests/**'],
extends: ['plugin:jest/recommended'],
},
],
};

View File

@@ -1,25 +0,0 @@
name: Black Formatter
inputs:
directory:
description: Directory to Lint
required: true
version:
description: pypi version of "black" to use
required: false
default: 22.3.0
runs:
using: "composite"
steps:
- name: Ensure supported Python selected
uses: actions/setup-python@v4
with:
python-version: '>=3.6.2'
- name: pip install
shell: bash
run: pip install black==${{ inputs.version }}
- name: black
shell: bash
run: black --check ${{ inputs.directory }}

View File

@@ -1,10 +0,0 @@
name: Cache the installed copy of emsdk and its build artifacts
runs:
using: "composite"
steps:
- name: Cache emsdk
uses: actions/cache@v3
with:
path: javascript/.emsdk
key: emsdk-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('yarn.lock', 'javascript/package.json', 'javascript/just.config.cjs')}}

View File

@@ -1,23 +0,0 @@
name: Clang Format
inputs:
directory:
description: Directory to Lint
required: true
version:
description: LLVM version to use # Should be kept roughly in sync with arcanist
required: false
default: 12
runs:
using: "composite"
steps:
- name: Install
shell: bash
run: sudo apt-get install -y clang-format-${{ inputs.version }}
- name: clang-format
working-directory: ${{ inputs.directory }}
shell: bash
env:
BASHOPTS: extglob:nullglob
run: clang-format-${{ inputs.version }} --dry-run --Werror **/*.{h,hh,hpp,c,cpp,cc,m,mm}

View File

@@ -1,14 +0,0 @@
name: Install Ninja
runs:
using: "composite"
steps:
- name: Install ninja (Linux)
if: ${{ runner.os == 'Linux' }}
shell: bash
run: sudo apt-get install -y ninja-build
- name: Install ninja (Windows)
if: ${{ runner.os == 'Windows' }}
shell: powershell
run: choco install ninja

View File

@@ -1,12 +0,0 @@
name: Setup Android environment
runs:
using: "composite"
steps:
- name: Select Java Version
uses: actions/setup-java@v2
with:
distribution: zulu
java-version: 17
- name: Configure Gradle Caches
uses: gradle/gradle-build-action@v2

View File

@@ -1,13 +0,0 @@
name: Setup Apple envirionment
runs:
using: "composite"
steps:
# TODO: This and Ruby should be versioned
- name: Install Cocoapods
shell: bash
run: sudo gem install cocoapods
- uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: 14.3.1

View File

@@ -1,33 +0,0 @@
name: Setup C++ envirionment
inputs:
toolchain:
description: Compiler toolchain to use (Clang, GCC, or MSVC)
required: false
default: 'Clang'
runs:
using: "composite"
steps:
- name: Install Ninja
if: ${{ runner.os != 'Windows' }}
uses: ./.github/actions/install-ninja
- name: Set Clang as compiler
if: ${{ inputs.toolchain == 'Clang' }}
shell: bash
run: |
echo "CC=/usr/bin/clang" >> $GITHUB_ENV
echo "CXX=/usr/bin/clang++" >> $GITHUB_ENV
echo "CXXFLAGS=-stdlib=libc++" >> $GITHUB_ENV
echo "LDFLAGS=-stdlib=libc++" >> $GITHUB_ENV
- name: Set GCC as compiler
if: ${{ inputs.toolchain == 'GCC' }}
shell: bash
run: |
echo "CC=/usr/bin/gcc" >> $GITHUB_ENV
echo "CXX=/usr/bin/g++" >> $GITHUB_ENV
- name: Setup VS Developer Command Prompt
if: ${{ runner.os == 'Windows' }}
uses: ilammy/msvc-dev-cmd@v1

View File

@@ -1,18 +0,0 @@
name: Setup JavaScript envirionment
runs:
using: "composite"
steps:
- name: Setup Node environment
uses: actions/setup-node@v3
with:
node-version: 18.x
cache: yarn
cache-dependency-path: yarn.lock
env:
# https://github.com/actions/setup-node/issues/317
FORCE_COLOR: 0
- name: yarn install
shell: bash
run: yarn install --frozen-lockfile

View File

@@ -1,23 +0,0 @@
name: Setup Website envirionment
runs:
using: "composite"
steps:
# TODO: Update to latest when website is moved to the workspace version of
# yoga-layout
- name: Setup Node environment
uses: actions/setup-node@v3
with:
node-version: 12.x
cache: yarn
cache-dependency-path: website/yarn.lock
env:
# https://github.com/actions/setup-node/issues/317
FORCE_COLOR: 0
# TODO: the website should be in a yarn workspace with the library, but the
# current version of gatsby is incompatible with hoisting.
- name: yarn install
shell: bash
run: yarn install --frozen-lockfile --network-timeout 1000000
working-directory: website

View File

@@ -1,38 +0,0 @@
name: Publish Android Release
on:
push:
tags:
- '*'
workflow_dispatch:
jobs:
publish:
name: Publish to Maven Central
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-android
- name: Publish to Maven Local
run: ./gradlew publishToMavenLocal
env:
ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}
- name: Upload Build Artifacts
uses: actions/upload-artifact@v3
with:
name: 'snapshot-artifacts'
path: '~/.m2/repository/'
- name: Publish to the Maven Central
run: ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository
env:
ORG_GRADLE_PROJECT_SONATYPE_USERNAME: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_USERNAME }}
ORG_GRADLE_PROJECT_SONATYPE_PASSWORD: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_PASSWORD }}
ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_KEY }}
ORG_GRADLE_PROJECT_SIGNING_PWD: ${{ secrets.ORG_GRADLE_PROJECT_SIGNING_PWD }}

View File

@@ -1,36 +0,0 @@
name: Publish Android Snapshot
on:
push:
branches:
- main
workflow_dispatch:
jobs:
publish:
name: Publish Snapshot
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-android
- name: Publish to Maven Local
run: ./gradlew publishToMavenLocal
env:
ORG_GRADLE_PROJECT_USE_SNAPSHOT: true
- name: Upload Build Artifacts
uses: actions/upload-artifact@v3
with:
name: 'snapshot-artifacts'
path: '~/.m2/repository/'
- name: Publish to the Snapshot Repository
run: ./gradlew publishToSonatype
env:
ORG_GRADLE_PROJECT_SONATYPE_USERNAME: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_USERNAME }}
ORG_GRADLE_PROJECT_SONATYPE_PASSWORD: ${{ secrets.ORG_GRADLE_PROJECT_SONATYPE_PASSWORD }}
ORG_GRADLE_PROJECT_USE_SNAPSHOT: true

View File

@@ -1,23 +0,0 @@
name: Publish CocoaPods Release
on:
push:
tags:
- '*'
workflow_dispatch:
jobs:
publish:
name: Publish to CocoaPods trunk
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-apple
- name: Publish Yoga
run: pod trunk push Yoga.podspec
env:
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}

View File

@@ -1,25 +0,0 @@
name: Publish NPM Release
on:
push:
tags:
- '*'
workflow_dispatch:
jobs:
publish:
name: Publish to npmjs registry
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-js
- name: Store auth token in config file
run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc
- name: yarn publish
run: yarn publish
working-directory: javascript

View File

@@ -1,35 +0,0 @@
name: Publish Website
on:
push:
branches:
- main
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}
jobs:
publish:
name: Publish to GitHub Pages
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-website
- name: yarn build
run: yarn build
working-directory: website
- uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_branch: gh-pages
publish_dir: website/public
cname: yogalayout.dev
keep_files: true
user_name: 'Yoga-bot'
user_email: 'yogabot@fb.com'

View File

@@ -1,27 +0,0 @@
name: Validate Android
on:
pull_request:
push:
branches:
- main
- 'release-*'
workflow_dispatch:
jobs:
build:
name: Build [${{ matrix.os }}][${{ matrix.mode }}]
runs-on: ${{ matrix.os }}
strategy:
matrix:
mode: [Debug, Release]
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-android
- name: Build
run: ./gradlew assemble${{ matrix.mode }} --stacktrace

View File

@@ -1,39 +0,0 @@
name: Validate Apple
on:
pull_request:
push:
branches:
- main
- 'release-*'
workflow_dispatch:
jobs:
lint-pods:
name: Build [CocoaPods]
runs-on: macos-13
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-apple
- name: pod lib lint
run: pod lib lint --verbose --include-podspecs=**/*.podspec
test:
name: Build [SwiftPM]
runs-on: macos-13
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-apple
- name: Build Debug
run: swift build -c debug
- name: Build Release
run: swift build -c release

View File

@@ -1,109 +0,0 @@
name: Validate C++
on:
pull_request:
push:
branches:
- main
- 'release-*'
workflow_dispatch:
env:
GTEST_COLOR: 1
jobs:
test:
name: Build and Test [${{ matrix.toolchain }}][${{ matrix.mode }}]
runs-on: ${{ (matrix.toolchain == 'MSVC') && 'windows-latest' || 'ubuntu-latest' }}
strategy:
matrix:
mode: [Debug, Release]
toolchain: [Clang, GCC] # TODO: fix issues building GTest Binary with MSVC in GitHub Actions
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-cpp
with:
toolchain: ${{ matrix.toolchain }}
- name: Unit tests
run: ./unit_tests ${{ matrix.mode }}
build_fuzzers:
name: Build fuzzers [${{ matrix.toolchain }}][${{ matrix.mode }}]
runs-on: ubuntu-latest
strategy:
matrix:
mode: [Debug, Release]
toolchain: [Clang]
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-cpp
with:
toolchain: ${{ matrix.toolchain }}
- name: Unit tests
run: ./build_fuzz_tests ${{ matrix.mode }}
benchmark:
name: Benchmark [${{ matrix.toolchain }}]
runs-on: ${{ (matrix.toolchain == 'MSVC') && 'windows-latest' || 'ubuntu-latest' }}
strategy:
matrix:
toolchain: [Clang, GCC, MSVC]
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-cpp
with:
toolchain: ${{ matrix.toolchain }}
- name: Build and run benchmark
run: |
cmake -S . -B build -G Ninja -D CMAKE_BUILD_TYPE=Release
cmake --build build
./build/benchmark ./captures
working-directory: benchmark
- name: Build and run benchmarklegacy
run: ./build/benchmarklegacy
working-directory: benchmark
capture:
name: Capture [${{ matrix.toolchain }}]
runs-on: ${{ (matrix.toolchain == 'MSVC') && 'windows-latest' || 'ubuntu-latest' }}
strategy:
matrix:
toolchain: [Clang, GCC, MSVC]
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-cpp
with:
toolchain: ${{ matrix.toolchain }}
- name: Build capture
run: |
cmake -S . -B build -G Ninja -D CMAKE_BUILD_TYPE=Release
cmake --build build
working-directory: capture
clang-format:
name: Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: clang-format
uses: ./.github/actions/clang-format

View File

@@ -1,116 +0,0 @@
name: Validate JavaScript
on:
pull_request:
push:
branches:
- main
- 'release-*'
workflow_dispatch:
env:
FORCE_COLOR: 3
jobs:
benchmark:
name: Benchmark [${{ matrix.os }}]
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-js
- name: Restore emsdk
uses: ./.github/actions/cache-emsdk
- name: yarn benchmark
run: yarn benchmark
working-directory: javascript
build:
name: Build [${{ matrix.os }}]
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-js
- name: Restore emsdk
uses: ./.github/actions/cache-emsdk
- name: yarn build
run: yarn build --verbose
working-directory: javascript
test:
name: Test [${{ matrix.os }}]
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-js
- name: Restore emsdk
uses: ./.github/actions/cache-emsdk
- name: yarn test
run: yarn test
working-directory: javascript
lint:
name: ESLint (All Packages)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-js
- name: yarn lint
run: yarn lint
typecheck:
name: Typecheck
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-js
- name: yarn tsc
run: yarn tsc
working-directory: javascript
pack:
name: Pack
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-js
- name: Restore emsdk
uses: ./.github/actions/cache-emsdk
- name: yarn pack
run: yarn pack --filename yoga-layout.tar.gz
working-directory: javascript
- uses: actions/upload-artifact@v3
with:
name: npm-package
path: javascript/yoga-layout.tar.gz

View File

@@ -1,33 +0,0 @@
name: Validate Tests
on:
pull_request:
push:
branches:
- main
- 'release-*'
workflow_dispatch:
jobs:
validate:
name: Validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup JS
uses: ./.github/actions/setup-js
- name: yarn gentest-validate
run: yarn gentest-validate
- name: yarn gentest
run: yarn gentest -h
- name: Check for modified tests
run: |
if [[ -n $(git status -s) ]]; then
git status -s
echo "yarn gentest modified these tests. Please run yarn gentest to resolve."
exit 1
fi

View File

@@ -1,56 +0,0 @@
name: Validate Website
on:
pull_request:
branches:
- main
push:
branches:
- main
workflow_dispatch:
jobs:
build:
name: Build [Gatsby]
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-website
- name: yarn build
run: yarn build
working-directory: website
build_next:
name: Build [Docusaurus]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-js
- name: Restore emsdk
uses: ./.github/actions/cache-emsdk
- name: Build Website
run: yarn build
working-directory: website-next
typecheck:
name: Typecheck [Docusaurus]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup
uses: ./.github/actions/setup-js
- name: yarn tsc
run: yarn tsc
working-directory: website-next

12
.gitignore vendored
View File

@@ -5,16 +5,14 @@
/.buckconfig.local
/.buckd
/gentest/test.html
.buck-java11
node_modules
.buckversion
# Jekyll
/.sass-cache/
/_site/
# Visual studio code
!.vscode
.vscode
*.pdb
*.tlog
*.obj
@@ -65,11 +63,5 @@ Carthage/Build
# Gradle
.gradle
local.properties
# NDK/CMake
.cxx
.externalNativeBuild
# Docusarus build
.docusaurus

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "lib/gtest/googletest"]
path = lib/gtest/googletest
url = https://github.com/google/googletest.git

View File

@@ -1,3 +0,0 @@
**/binaries/**
**/build/**
**/generated/**

View File

@@ -1,16 +0,0 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @format
*/
module.exports = {
arrowParens: 'avoid',
bracketSameLine: true,
bracketSpacing: false,
singleQuote: true,
trailingComma: 'all',
};

1
.swift-version Normal file
View File

@@ -0,0 +1 @@
4.0

76
.travis.yml Normal file
View File

@@ -0,0 +1,76 @@
language: java
os: linux
addons:
apt:
sources:
- llvm-toolchain-trusty-6.0
- ubuntu-toolchain-r-test
packages:
- clang-6.0
env:
- TARGET: website
- TARGET: android
install:
- cd website
- yarn --ignore-scripts
- cd ..
cache:
directories:
- $HOME/buck
- $HOME/.gradle
before_install:
- |
if [[ -n "$encrypted_d27e803291ff_iv" ]]; then
openssl aes-256-cbc -K $encrypted_d27e803291ff_key -iv $encrypted_d27e803291ff_iv -in scripts/setup-keys.enc -d >> gradle.properties;
fi
# Android
- |
if [[ $TARGET = "android" ]]; then
pushd $HOME
git clone --depth 1 https://github.com/facebook/buck.git
cd buck
ant
popd
export PATH=$PATH:$HOME/buck/bin/
buck --version
export TERMINAL=dumb
source scripts/android-setup.sh && installAndroidSDK
export ANDROID_SDK=$ANDROID_HOME
export ANDROID_NDK_REPOSITORY=$HOME/android-ndk
export ANDROID_NDK_HOME=$ANDROID_NDK_REPOSITORY/android-ndk-r15c
fi
# Website
- |
if [[ $TARGET = "website" ]]; then
nvm install 8
nvm use 8
fi
script:
- |
if [[ $TARGET = "android" ]]; then
./gradlew testDebugUnit && scripts/publish-snapshot.sh
fi
- |
if [[ $TARGET = "website" ]]; then
pushd website
yarn build
popd
fi
deploy:
provider: pages
skip-cleanup: true
github-token: $GITHUB_TOKEN
fqdn: yogalayout.com
local-dir: website/public
email: yogabot@fb.com
name: Yoga-bot
keep-history: true
on:
branch: master
condition: $TARGET = website

View File

@@ -1,7 +0,0 @@
{
"recommendations": [
"ms-vscode.cpptools",
"EditorConfig.EditorConfig",
"dbaeumer.vscode-eslint",
]
}

25
.vscode/launch.json vendored
View File

@@ -1,25 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Debug C++ Unit tests (lldb)",
"type": "cppdbg",
"MIMode": "lldb",
"request": "launch",
"program": "${workspaceFolder}/tests/build/yogatests",
"cwd": "${workspaceFolder}",
"preLaunchTask": "Build Unit Tests"
},
{
"name": "Debug C++ Unit tests (vsdbg)",
"type": "cppvsdbg",
"request": "launch",
"program": "${workspaceFolder}/tests/build/yogatests",
"cwd": "${workspaceFolder}",
"preLaunchTask": "Build Unit Tests"
}
]
}

20
.vscode/settings.json vendored
View File

@@ -1,20 +0,0 @@
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.format.enable": true,
"eslint.packageManager": "yarn",
"eslint.enable": true,
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"eslint.workingDirectories": [
{
"mode": "auto"
}
],
}

23
.vscode/tasks.json vendored
View File

@@ -1,23 +0,0 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Build Unit Tests",
"type": "shell",
"command": "(which ninja && cmake -B build -S . -D CMAKE_BUILD_TYPE=Debug -G Ninja || cmake -B build -S . -D CMAKE_BUILD_TYPE=Debug) && cmake --build build",
"windows": {
"command": "(where ninja && cmake -B build -S . -D CMAKE_BUILD_TYPE=Debug -G Ninja || cmake -B build -S . -D CMAKE_BUILD_TYPE=Debug) && cmake --build build",
},
"group": "build",
"options": {
"cwd": "tests"
},
"presentation": {
"reveal": "always",
"panel": "new"
}
}
]
}

57
BUCK Normal file
View File

@@ -0,0 +1,57 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
load("//tools/build_defs/oss:yoga_defs.bzl", "BASE_COMPILER_FLAGS", "GTEST_TARGET", "LIBRARY_COMPILER_FLAGS", "subdir_glob", "yoga_cxx_library", "yoga_cxx_test", "yoga_dep")
GMOCK_OVERRIDE_FLAGS = [
# gmock does not mark mocked methods as override, ignore the warnings in tests
"-Wno-inconsistent-missing-override",
]
TEST_COMPILER_FLAGS = BASE_COMPILER_FLAGS + GMOCK_OVERRIDE_FLAGS + [
"-DDEBUG",
"-DYG_ENABLE_EVENTS",
]
yoga_cxx_library(
name = "yoga",
srcs = glob(["yoga/**/*.cpp"]),
header_namespace = "",
exported_headers = subdir_glob([("", "yoga/**/*.h")]),
compiler_flags = LIBRARY_COMPILER_FLAGS,
soname = "libyogacore.$(ext)",
tests = [":YogaTests"],
visibility = ["PUBLIC"],
deps = [
yoga_dep("lib/fb:ndklog"),
],
)
yoga_cxx_library(
name = "yogaForDebug",
srcs = glob(["yoga/**/*.cpp"]),
header_namespace = "",
exported_headers = subdir_glob([("", "yoga/**/*.h")]),
compiler_flags = TEST_COMPILER_FLAGS,
soname = "libyogacore.$(ext)",
tests = [":YogaTests"],
visibility = ["PUBLIC"],
deps = [
yoga_dep("lib/fb:ndklog"),
],
)
yoga_cxx_test(
name = "YogaTests",
srcs = glob(["tests/*.cpp"]),
headers = subdir_glob([("", "yoga/**/*.h")]),
compiler_flags = TEST_COMPILER_FLAGS,
contacts = ["emilsj@fb.com"],
visibility = ["PUBLIC"],
deps = [
":yogaForDebug",
yoga_dep("testutil:testutil"),
GTEST_TARGET,
],
)

View File

@@ -1,58 +1,16 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
#
cmake_minimum_required(VERSION 3.4.1)
cmake_minimum_required(VERSION 3.13...3.26)
project(yoga-all)
set(CMAKE_VERBOSE_MAKEFILE on)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/project-defaults.cmake)
file(GLOB yogacore_SRC yoga/*.cpp)
add_library(yogacore STATIC ${yogacore_SRC})
add_subdirectory(yoga)
add_subdirectory(tests)
option(BUILD_FUZZ_TESTS "Build fuzz tests" OFF)
if ('${CMAKE_CXX_COMPILER_ID}' MATCHES 'Clang' AND BUILD_FUZZ_TESTS)
add_subdirectory(fuzz)
endif()
# cmake install config
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
# declare target to install
install(TARGETS yogacore EXPORT yoga-targets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
# install header files
install(DIRECTORY
"${CMAKE_CURRENT_LIST_DIR}/yoga"
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
FILES_MATCHING PATTERN "*.h"
)
# install target config
install(EXPORT yoga-targets
FILE yogaTargets.cmake
NAMESPACE yoga::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/yoga
)
# generate config file
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/yoga-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/yogaConfig.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/yoga
)
# install config file
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/yogaConfig.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/yoga
)
target_link_libraries(yogacore android log)
set_target_properties(yogacore PROPERTIES CXX_STANDARD 11)

View File

@@ -1,76 +1,3 @@
# Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies when
an individual is representing the project or its community in public spaces.
Examples of representing a project or community include using an official
project e-mail address, posting via an official social media account, or acting
as an appointed representative at an online or offline event. Representation of
a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at <opensource-conduct@fb.com>. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please [read the full text](https://code.fb.com/codeofconduct/) so that you can understand what actions will and will not be tolerated.

View File

@@ -8,7 +8,7 @@ Facebook has adopted a Code of Conduct that we expect project participants to ad
## Pull Requests
We actively welcome your pull requests.
1. Fork the repo and create your branch from `main`.
1. Fork the repo and create your branch from `master`.
2. If you've added code that should be tested, add tests
3. If you've changed APIs, update the documentation.
4. Ensure the test suite passes.

View File

@@ -1,32 +0,0 @@
// swift-tools-version:5.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import PackageDescription
let package = Package(
name: "yoga",
products: [
.library(name: "yoga", targets: [ "core" ])
],
targets: [
.target(
name: "core",
path: ".",
sources: [
"yoga"
],
publicHeadersPath: ".",
cxxSettings: [
.headerSearchPath(".")
]
)
],
cxxLanguageStandard: CXXLanguageStandard(rawValue: "c++20")
)

View File

@@ -1,22 +1,14 @@
# Yoga [![Support Ukraine](https://img.shields.io/badge/Support-Ukraine-FFD500?style=flat&labelColor=005BBB)](https://opensource.fb.com/support-ukraine) [![CocoaPods](https://img.shields.io/cocoapods/v/Yoga.svg)](http://cocoapods.org/pods/Yoga) [![npm](https://img.shields.io/npm/v/yoga-layout.svg)](https://www.npmjs.com/package/yoga-layout) [![Maven Central](https://img.shields.io/maven-central/v/com.facebook.yoga/yoga)](https://search.maven.org/artifact/com.facebook.yoga/yoga)
Yoga is an embeddable and performant flexbox layout engine with bindings for multiple languages.
# Yoga [![CocoaPods](https://img.shields.io/cocoapods/v/YogaKit.svg)](http://cocoapods.org/pods/YogaKit) [![npm](https://img.shields.io/npm/v/yoga-layout.svg)](https://www.npmjs.com/package/yoga-layout) [![bintray](https://img.shields.io/bintray/v/facebook/maven/com.facebook.yoga:yoga.svg)](https://bintray.com/facebook/maven/com.facebook.yoga%3Ayoga/_latestVersion) [![NuGet](https://img.shields.io/nuget/v/Facebook.Yoga.svg)](https://www.nuget.org/packages/Facebook.Yoga)
## Building
Yoga builds with [buck](https://buckbuild.com). Make sure you install buck before contributing to Yoga. Yoga's main implementation is in C, with bindings to supported languages and frameworks. When making changes to Yoga please ensure the changes are also propagated to these bindings when applicable.
Yoga's main implementation targets C++ 20 with accompanying build logic in CMake. A wrapper is provided to build the main library and run unit tests.
## Testing
For testing we rely on [gtest](https://github.com/google/googletest) as a submodule. After cloning Yoga run `git submodule init` followed by `git submodule update`.
```sh
./unit_tests <Debug|Release>
```
For any changes you make you should ensure that all the tests are passing. In case you make any fixes or additions to the library please also add tests for that change to ensure we don't break anything in the future. Tests are located in the `tests` directory. Run the tests by executing `buck test //:yoga`.
While not required, this script will use [ninja](https://ninja-build.org/) if it is installed for faster builds.
Yoga is additionally part of the [vcpkg](https://github.com/Microsoft/vcpkg/) collection of ports maintained by Microsoft and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
## Adding Tests
Many of Yoga's tests are automatically generated, using HTML fixtures describing node structure. These are rendered in Chrome to generate an expected layout result for the tree. New fixtures can be added to `gentest/fixtures`.
Instead of manually writing a test which ensures parity with web implementations of Flexbox you can run `gentest/gentest.rb` to generate a test for you. You can write html which you want to verify in Yoga, in `gentest/fixtures` folder, such as the following.
```html
<div id="my_test" style="width: 100px; height: 100px; align-items: center;">
@@ -24,12 +16,33 @@ Many of Yoga's tests are automatically generated, using HTML fixtures describing
</div>
```
To generate new tests from added fixtures:
Run `gentest/gentest.rb` to generate test code and re-run `buck test //:yoga` to validate the behavior. One test case will be generated for every root `div` in the input html.
1. Ensure you have [yarn classic](https://classic.yarnpkg.com) installed.
2. Run `yarn install` to install dependencies for the test generator.
3. Run `yarn gentest` in the `yoga` directory.
You may need to install the latest watir-webdriver gem (`gem install watir-webdriver`) and [ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/) to run `gentest/gentest.rb` Ruby script.
## Debugging
### .NET
.NET testing is not integrated in buck yet, you might need to set up .NET testing environment. We have a script which to launch C# test on macOS, `csharp/tests/Facebook.Yoga/test_macos.sh`.
Yoga provides a VSCode "launch.json" configuration which allows debugging unit tests. Simply add your breakpoints, and run "Debug C++ Unit tests (lldb)" (or "Debug C++ Unit tests (vsdbg)" on Windows).
## Benchmarks
Benchmarks are located in `benchmark/YGBenchmark.c` and can be run with `buck run //benchmark:benchmark`. If you think your change has affected performance please run this before and after your change to validate that nothing has regressed. Benchmarks are run on every commit in CI.
### JavaScript
Installing through NPM
```sh
npm install yoga-layout
```
By default this will install the library and try to build for all platforms (node, browser asm, and standalone webpack). You may receive errors if you do not have the required platform development tools already installed. To preset the platform you'd like to build for you can set a .npmrc property first.
```sh
npm config set yoga-layout:platform standalone
```
This will now only run the standalone webpack build upon install.
## Build Platforms
| name | description |
|----------------|-------------------------------------------------|
| all (default) | Builds all of these platforms. |
| browser | Builds asm js browser version. |
| node | Builds node js version. |
| standalone | Runs webpack. |
| none | Does nothing. You can use the prepackaged libs. |

File diff suppressed because it is too large Load Diff

View File

@@ -1,52 +1,39 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the LICENSE
# file in the root directory of this source tree.
#
Pod::Spec.new do |spec|
spec.name = 'Yoga'
spec.version = '3.0.0'
spec.version = '1.14.0'
spec.license = { :type => 'MIT', :file => "LICENSE" }
spec.homepage = 'https://yogalayout.dev/'
spec.documentation_url = 'https://yogalayout.dev/docs'
spec.homepage = 'https://yogalayout.com/'
spec.documentation_url = 'https://yogalayout.com/docs'
spec.summary = 'An embeddable and performant flexbox layout engine with bindings for multiple languages'
spec.summary = 'Yoga is a cross-platform layout engine which implements Flexbox.'
spec.description = 'Yoga is a cross-platform layout engine enabling maximum collaboration within your team by implementing an API many designers are familiar with, and opening it up to developers across different platforms.'
spec.authors = {'Meta Open Source' => 'opensource@meta.com'}
spec.authors = 'Facebook'
spec.source = {
:git => 'https://github.com/facebook/yoga.git',
:tag => "v#{spec.version.to_s}",
:tag => spec.version.to_s,
}
spec.ios.deployment_target = "13.4"
spec.platforms = { :ios => "8.0", :osx => "10.7", :tvos => "10.0", :watchos => "2.0" }
spec.module_name = 'yoga'
spec.requires_arc = false
spec.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
'HEADER_SEARCH_PATHS' => '"$(PODS_TARGET_SRCROOT)"',
'DEFINES_MODULE' => 'YES'
}
spec.compiler_flags = [
'-fno-omit-frame-pointer',
'-fexceptions',
'-Wall',
'-Werror',
'-Wextra',
'-Wconversion',
'-std=c++20',
'-std=c++1y',
'-fPIC'
]
spec.source_files = 'yoga/**/*.{c,h,cpp}'
spec.public_header_files = 'yoga/{Yoga,YGEnums,YGMacros,YGValue}.h'
spec.swift_version = '5.1'
spec.source_files = 'yoga/**/*.{h,cpp}'
spec.header_mappings_dir = 'yoga'
public_header_files = 'yoga/*.h'
spec.public_header_files = public_header_files
all_header_files = 'yoga/**/*.h'
spec.private_header_files = Dir.glob(all_header_files) - Dir.glob(public_header_files)
spec.preserve_paths = [all_header_files]
end

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:YogaDev/YogaDev.xcodeproj">
</FileRef>
<FileRef
location = "group:ReactYoga.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,350 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
6D4C7FA42249476900CBB1EC /* YGMarker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D4C7F892249476700CBB1EC /* YGMarker.cpp */; };
6D4C7FA52249476900CBB1EC /* YGValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D4C7F8B2249476700CBB1EC /* YGValue.cpp */; };
6D4C7FA62249476900CBB1EC /* YGLayout.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D4C7F902249476700CBB1EC /* YGLayout.cpp */; };
6D4C7FA72249476900CBB1EC /* YGNodePrint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D4C7F922249476700CBB1EC /* YGNodePrint.cpp */; };
6D4C7FA82249476900CBB1EC /* YGStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D4C7F992249476800CBB1EC /* YGStyle.cpp */; };
6D4C7FA92249476900CBB1EC /* log.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D4C7F9A2249476800CBB1EC /* log.cpp */; };
6D4C7FAA2249476900CBB1EC /* YGNode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D4C7F9B2249476800CBB1EC /* YGNode.cpp */; };
6D4C7FAB2249476900CBB1EC /* Yoga.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D4C7F9C2249476800CBB1EC /* Yoga.cpp */; };
6D4C7FAC2249476900CBB1EC /* Utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D4C7F9D2249476800CBB1EC /* Utils.cpp */; };
6D4C7FAD2249476900CBB1EC /* YGEnums.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D4C7F9E2249476800CBB1EC /* YGEnums.cpp */; };
6D4C7FAE2249476900CBB1EC /* YGConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D4C7FA32249476800CBB1EC /* YGConfig.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
6D4C7F76224945B200CBB1EC /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
6D4C7F78224945B200CBB1EC /* libYogaDev.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libYogaDev.a; sourceTree = BUILT_PRODUCTS_DIR; };
6D4C7F892249476700CBB1EC /* YGMarker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YGMarker.cpp; path = ../yoga/YGMarker.cpp; sourceTree = "<group>"; };
6D4C7F8A2249476700CBB1EC /* Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Utils.h; path = ../yoga/Utils.h; sourceTree = "<group>"; };
6D4C7F8B2249476700CBB1EC /* YGValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YGValue.cpp; path = ../yoga/YGValue.cpp; sourceTree = "<group>"; };
6D4C7F8C2249476700CBB1EC /* instrumentation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = instrumentation.h; path = ../yoga/instrumentation.h; sourceTree = "<group>"; };
6D4C7F8D2249476700CBB1EC /* YGStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YGStyle.h; path = ../yoga/YGStyle.h; sourceTree = "<group>"; };
6D4C7F8E2249476700CBB1EC /* YGNodePrint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YGNodePrint.h; path = ../yoga/YGNodePrint.h; sourceTree = "<group>"; };
6D4C7F8F2249476700CBB1EC /* YGMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YGMarker.h; path = ../yoga/YGMarker.h; sourceTree = "<group>"; };
6D4C7F902249476700CBB1EC /* YGLayout.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YGLayout.cpp; path = ../yoga/YGLayout.cpp; sourceTree = "<group>"; };
6D4C7F912249476700CBB1EC /* YGEnums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YGEnums.h; path = ../yoga/YGEnums.h; sourceTree = "<group>"; };
6D4C7F922249476700CBB1EC /* YGNodePrint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YGNodePrint.cpp; path = ../yoga/YGNodePrint.cpp; sourceTree = "<group>"; };
6D4C7F932249476700CBB1EC /* YGMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YGMacros.h; path = ../yoga/YGMacros.h; sourceTree = "<group>"; };
6D4C7F942249476700CBB1EC /* log.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = log.h; path = ../yoga/log.h; sourceTree = "<group>"; };
6D4C7F952249476800CBB1EC /* YGFloatOptional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YGFloatOptional.h; path = ../yoga/YGFloatOptional.h; sourceTree = "<group>"; };
6D4C7F962249476800CBB1EC /* YGNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YGNode.h; path = ../yoga/YGNode.h; sourceTree = "<group>"; };
6D4C7F972249476800CBB1EC /* YGLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YGLayout.h; path = ../yoga/YGLayout.h; sourceTree = "<group>"; };
6D4C7F982249476800CBB1EC /* CompactValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CompactValue.h; path = ../yoga/CompactValue.h; sourceTree = "<group>"; };
6D4C7F992249476800CBB1EC /* YGStyle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YGStyle.cpp; path = ../yoga/YGStyle.cpp; sourceTree = "<group>"; };
6D4C7F9A2249476800CBB1EC /* log.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = log.cpp; path = ../yoga/log.cpp; sourceTree = "<group>"; };
6D4C7F9B2249476800CBB1EC /* YGNode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YGNode.cpp; path = ../yoga/YGNode.cpp; sourceTree = "<group>"; };
6D4C7F9C2249476800CBB1EC /* Yoga.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Yoga.cpp; path = ../yoga/Yoga.cpp; sourceTree = "<group>"; };
6D4C7F9D2249476800CBB1EC /* Utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Utils.cpp; path = ../yoga/Utils.cpp; sourceTree = "<group>"; };
6D4C7F9E2249476800CBB1EC /* YGEnums.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YGEnums.cpp; path = ../yoga/YGEnums.cpp; sourceTree = "<group>"; };
6D4C7F9F2249476800CBB1EC /* Yoga-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "Yoga-internal.h"; path = "../yoga/Yoga-internal.h"; sourceTree = "<group>"; };
6D4C7FA02249476800CBB1EC /* YGValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YGValue.h; path = ../yoga/YGValue.h; sourceTree = "<group>"; };
6D4C7FA12249476800CBB1EC /* Yoga.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Yoga.h; path = ../yoga/Yoga.h; sourceTree = "<group>"; };
6D4C7FA22249476800CBB1EC /* YGConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YGConfig.h; path = ../yoga/YGConfig.h; sourceTree = "<group>"; };
6D4C7FA32249476800CBB1EC /* YGConfig.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = YGConfig.cpp; path = ../yoga/YGConfig.cpp; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
6D4C7F75224945B200CBB1EC /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
6D4C7F6F224945B200CBB1EC = {
isa = PBXGroup;
children = (
6D4C7F982249476800CBB1EC /* CompactValue.h */,
6D4C7F8C2249476700CBB1EC /* instrumentation.h */,
6D4C7F9A2249476800CBB1EC /* log.cpp */,
6D4C7F942249476700CBB1EC /* log.h */,
6D4C7F9D2249476800CBB1EC /* Utils.cpp */,
6D4C7F8A2249476700CBB1EC /* Utils.h */,
6D4C7FA32249476800CBB1EC /* YGConfig.cpp */,
6D4C7FA22249476800CBB1EC /* YGConfig.h */,
6D4C7F9E2249476800CBB1EC /* YGEnums.cpp */,
6D4C7F912249476700CBB1EC /* YGEnums.h */,
6D4C7F952249476800CBB1EC /* YGFloatOptional.h */,
6D4C7F902249476700CBB1EC /* YGLayout.cpp */,
6D4C7F972249476800CBB1EC /* YGLayout.h */,
6D4C7F932249476700CBB1EC /* YGMacros.h */,
6D4C7F892249476700CBB1EC /* YGMarker.cpp */,
6D4C7F8F2249476700CBB1EC /* YGMarker.h */,
6D4C7F9B2249476800CBB1EC /* YGNode.cpp */,
6D4C7F962249476800CBB1EC /* YGNode.h */,
6D4C7F922249476700CBB1EC /* YGNodePrint.cpp */,
6D4C7F8E2249476700CBB1EC /* YGNodePrint.h */,
6D4C7F992249476800CBB1EC /* YGStyle.cpp */,
6D4C7F8D2249476700CBB1EC /* YGStyle.h */,
6D4C7F8B2249476700CBB1EC /* YGValue.cpp */,
6D4C7FA02249476800CBB1EC /* YGValue.h */,
6D4C7F9F2249476800CBB1EC /* Yoga-internal.h */,
6D4C7F9C2249476800CBB1EC /* Yoga.cpp */,
6D4C7FA12249476800CBB1EC /* Yoga.h */,
6D4C7F79224945B200CBB1EC /* Products */,
);
sourceTree = "<group>";
};
6D4C7F79224945B200CBB1EC /* Products */ = {
isa = PBXGroup;
children = (
6D4C7F78224945B200CBB1EC /* libYogaDev.a */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
6D4C7F77224945B200CBB1EC /* YogaDev */ = {
isa = PBXNativeTarget;
buildConfigurationList = 6D4C7F81224945B200CBB1EC /* Build configuration list for PBXNativeTarget "YogaDev" */;
buildPhases = (
6D4C7F74224945B200CBB1EC /* Sources */,
6D4C7F75224945B200CBB1EC /* Frameworks */,
6D4C7F76224945B200CBB1EC /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = YogaDev;
productName = YogaDev;
productReference = 6D4C7F78224945B200CBB1EC /* libYogaDev.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
6D4C7F70224945B200CBB1EC /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1010;
ORGANIZATIONNAME = "Will Wilson";
TargetAttributes = {
6D4C7F77224945B200CBB1EC = {
CreatedOnToolsVersion = 10.1;
};
};
};
buildConfigurationList = 6D4C7F73224945B200CBB1EC /* Build configuration list for PBXProject "YogaDev" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 6D4C7F6F224945B200CBB1EC;
productRefGroup = 6D4C7F79224945B200CBB1EC /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
6D4C7F77224945B200CBB1EC /* YogaDev */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
6D4C7F74224945B200CBB1EC /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6D4C7FAD2249476900CBB1EC /* YGEnums.cpp in Sources */,
6D4C7FAE2249476900CBB1EC /* YGConfig.cpp in Sources */,
6D4C7FAA2249476900CBB1EC /* YGNode.cpp in Sources */,
6D4C7FAB2249476900CBB1EC /* Yoga.cpp in Sources */,
6D4C7FA92249476900CBB1EC /* log.cpp in Sources */,
6D4C7FA62249476900CBB1EC /* YGLayout.cpp in Sources */,
6D4C7FAC2249476900CBB1EC /* Utils.cpp in Sources */,
6D4C7FA82249476900CBB1EC /* YGStyle.cpp in Sources */,
6D4C7FA42249476900CBB1EC /* YGMarker.cpp in Sources */,
6D4C7FA52249476900CBB1EC /* YGValue.cpp in Sources */,
6D4C7FA72249476900CBB1EC /* YGNodePrint.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
6D4C7F7F224945B200CBB1EC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
6D4C7F80224945B200CBB1EC /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.1;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
6D4C7F82224945B200CBB1EC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
6D4C7F83224945B200CBB1EC /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
6D4C7F73224945B200CBB1EC /* Build configuration list for PBXProject "YogaDev" */ = {
isa = XCConfigurationList;
buildConfigurations = (
6D4C7F7F224945B200CBB1EC /* Debug */,
6D4C7F80224945B200CBB1EC /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
6D4C7F81224945B200CBB1EC /* Build configuration list for PBXNativeTarget "YogaDev" */ = {
isa = XCConfigurationList;
buildConfigurations = (
6D4C7F82224945B200CBB1EC /* Debug */,
6D4C7F83224945B200CBB1EC /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 6D4C7F70224945B200CBB1EC /* Project object */;
}

35
YogaKit.podspec Normal file
View File

@@ -0,0 +1,35 @@
#
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the LICENSE
# file in the root directory of this source tree.
#
podspec = Pod::Spec.new do |spec|
spec.name = 'YogaKit'
spec.version = '1.14.0'
spec.license = { :type => 'MIT', :file => "LICENSE" }
spec.homepage = 'https://facebook.github.io/yoga/'
spec.documentation_url = 'https://facebook.github.io/yoga/docs/'
spec.summary = 'Yoga is a cross-platform layout engine which implements Flexbox.'
spec.description = 'Yoga is a cross-platform layout engine enabling maximum collaboration within your team by implementing an API many designers are familiar with, and opening it up to developers across different platforms.'
spec.authors = 'Facebook'
spec.source = {
:git => 'https://github.com/facebook/yoga.git',
:tag => spec.version.to_s,
}
spec.platform = :ios
spec.ios.deployment_target = '8.0'
spec.ios.frameworks = 'UIKit'
spec.dependency 'Yoga', '~> 1.14'
spec.source_files = 'YogaKit/Source/*.{h,m,swift}'
spec.public_header_files = 'YogaKit/Source/{YGLayout,UIView+Yoga}.h'
spec.private_header_files = 'YogaKit/Source/YGLayout+Private.h'
spec.swift_version = '4.0'
end
# See https://github.com/facebook/yoga/pull/366
podspec.attributes_hash["readme"] = "YogaKit/README.md"
podspec

1
YogaKit/.swift-version Normal file
View File

@@ -0,0 +1 @@
3.0.2

64
YogaKit/BUCK Normal file
View File

@@ -0,0 +1,64 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
load("//tools/build_defs/oss:yoga_defs.bzl", "subdir_glob", "yoga_apple_library", "yoga_apple_test", "yoga_dep")
COMPILER_FLAGS = [
"-fobjc-arc",
"-Wconditional-uninitialized",
"-Wdangling-else",
"-Wdeprecated-declarations",
"-Wimplicit-retain-self",
"-Wincomplete-implementation",
"-Wobjc-method-access",
"-Wobjc-missing-super-calls",
"-Wmismatched-return-types",
"-Wreturn-type",
"-Wno-global-constructors",
"-Wno-shadow",
"-Wunused-const-variable",
"-Wunused-function",
"-Wunused-property-ivar",
"-Wunused-result",
"-Wunused-value",
]
yoga_apple_library(
name = "YogaKit",
srcs = glob(["Source/**/*.m"]),
header_namespace = "",
exported_headers = subdir_glob(
[
("", "Source/**/*.h"),
("Source", "**/*.h"),
],
prefix = "YogaKit",
),
compiler_flags = COMPILER_FLAGS,
frameworks = [
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
"$SDKROOT/System/Library/Frameworks/UIKit.framework",
],
header_path_prefix = "",
link_whole = True,
visibility = ["PUBLIC"],
deps = [
yoga_dep(":yoga"),
],
)
yoga_apple_test(
name = "YogaKitTests",
srcs = glob(["Tests/**/*.m"]),
compiler_flags = COMPILER_FLAGS,
frameworks = [
"$PLATFORM_DIR/Developer/Library/Frameworks/XCTest.framework",
"$SDKROOT/System/Library/Frameworks/CoreGraphics.framework",
],
info_plist = "Tests/Info.plist",
visibility = ["PUBLIC"],
deps = [
":YogaKit",
],
)

22
YogaKit/README.md Normal file
View File

@@ -0,0 +1,22 @@
# YogaKit
[![CocoaPods](https://img.shields.io/cocoapods/v/YogaKit.svg?style=flat)](https://cocoapods.org/pods/YogaKit)
[![Platform](https://img.shields.io/badge/platforms-iOS-orange.svg)](https://facebook.github.io/yoga/docs/api/yogakit/)
[![Languages](https://img.shields.io/badge/languages-ObjC%20%7C%20Swift-orange.svg)](https://facebook.github.io/yoga/docs/api/yogakit/)
## Installation
YogaKit is available to install via [CocoaPods](https://cocoapods.org/).
```
pod 'YogaKit', '~> 1.7'
```
## Getting Started
Checkout the docs [here](https://facebook.github.io/yoga/docs/api/yogakit/).
We also have a sample project. To try it out, clone this repo and open `YogaKitSample.xcodeproj` in the [YogaKitSample](https://github.com/facebook/yoga/tree/master/YogaKit/YogaKitSample) directory.
## Contributing
We welcome all pull-requests! At Facebook we sync the open source version of `YogaKit` daily, so we're always testing the latest changes.
See the [CONTRIBUTING.md](https://github.com/facebook/yoga/blob/master/CONTRIBUTING.md) file for how to help out.

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#import "YGLayout.h"
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef void (^YGLayoutConfigurationBlock)(YGLayout *layout);
@interface UIView (Yoga)
/**
The YGLayout that is attached to this view. It is lazily created.
*/
@property (nonatomic, readonly, strong) YGLayout *yoga;
/**
Indicates whether or not Yoga is enabled
*/
@property (nonatomic, readonly, assign) BOOL isYogaEnabled;
/**
In ObjC land, every time you access `view.yoga.*` you are adding another `objc_msgSend`
to your code. If you plan on making multiple changes to YGLayout, it's more performant
to use this method, which uses a single objc_msgSend call.
*/
- (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block
NS_SWIFT_NAME(configureLayout(block:));
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,39 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "UIView+Yoga.h"
#import "YGLayout+Private.h"
#import <objc/runtime.h>
static const void *kYGYogaAssociatedKey = &kYGYogaAssociatedKey;
@implementation UIView (YogaKit)
- (YGLayout *)yoga
{
YGLayout *yoga = objc_getAssociatedObject(self, kYGYogaAssociatedKey);
if (!yoga) {
yoga = [[YGLayout alloc] initWithView:self];
objc_setAssociatedObject(self, kYGYogaAssociatedKey, yoga, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return yoga;
}
- (BOOL)isYogaEnabled
{
return objc_getAssociatedObject(self, kYGYogaAssociatedKey) != nil;
}
- (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block
{
if (block != nil) {
block(self.yoga);
}
}
@end

View File

@@ -0,0 +1,16 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#import "YGLayout.h"
#import <yoga/Yoga.h>
@interface YGLayout ()
@property (nonatomic, assign, readonly) YGNodeRef node;
- (instancetype)initWithView:(UIView *)view;
@end

169
YogaKit/Source/YGLayout.h Normal file
View File

@@ -0,0 +1,169 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
#import <UIKit/UIKit.h>
#import <yoga/YGEnums.h>
#import <yoga/Yoga.h>
#import <yoga/YGMacros.h>
YG_EXTERN_C_BEGIN
extern YGValue YGPointValue(CGFloat value)
NS_SWIFT_UNAVAILABLE("Use the swift Int and FloatingPoint extensions instead");
extern YGValue YGPercentValue(CGFloat value)
NS_SWIFT_UNAVAILABLE("Use the swift Int and FloatingPoint extensions instead");
YG_EXTERN_C_END
typedef NS_OPTIONS(NSInteger, YGDimensionFlexibility) {
YGDimensionFlexibilityFlexibleWidth = 1 << 0,
YGDimensionFlexibilityFlexibleHeight = 1 << 1,
};
@interface YGLayout : NSObject
/**
Make default init unavailable, as it will not initialise YGNode which is
required for the setters and getters of YGLayout's properties to work properly.
*/
- (instancetype)init
__attribute__((unavailable("you are not meant to initialise YGLayout")));
/**
Make default init unavailable, as it will not initialise YGNode which is
required for the setters and getters of YGLayout's properties to work properly.
*/
+ (instancetype)new
__attribute__((unavailable("you are not meant to initialise YGLayout")));
/**
The property that decides if we should include this view when calculating
layout. Defaults to YES.
*/
@property (nonatomic, readwrite, assign, setter=setIncludedInLayout:) BOOL isIncludedInLayout;
/**
The property that decides during layout/sizing whether or not styling properties should be applied.
Defaults to NO.
*/
@property (nonatomic, readwrite, assign, setter=setEnabled:) BOOL isEnabled;
@property (nonatomic, readwrite, assign) YGDirection direction;
@property (nonatomic, readwrite, assign) YGFlexDirection flexDirection;
@property (nonatomic, readwrite, assign) YGJustify justifyContent;
@property (nonatomic, readwrite, assign) YGAlign alignContent;
@property (nonatomic, readwrite, assign) YGAlign alignItems;
@property (nonatomic, readwrite, assign) YGAlign alignSelf;
@property (nonatomic, readwrite, assign) YGPositionType position;
@property (nonatomic, readwrite, assign) YGWrap flexWrap;
@property (nonatomic, readwrite, assign) YGOverflow overflow;
@property (nonatomic, readwrite, assign) YGDisplay display;
@property (nonatomic, readwrite, assign) CGFloat flex;
@property (nonatomic, readwrite, assign) CGFloat flexGrow;
@property (nonatomic, readwrite, assign) CGFloat flexShrink;
@property (nonatomic, readwrite, assign) YGValue flexBasis;
@property (nonatomic, readwrite, assign) YGValue left;
@property (nonatomic, readwrite, assign) YGValue top;
@property (nonatomic, readwrite, assign) YGValue right;
@property (nonatomic, readwrite, assign) YGValue bottom;
@property (nonatomic, readwrite, assign) YGValue start;
@property (nonatomic, readwrite, assign) YGValue end;
@property (nonatomic, readwrite, assign) YGValue marginLeft;
@property (nonatomic, readwrite, assign) YGValue marginTop;
@property (nonatomic, readwrite, assign) YGValue marginRight;
@property (nonatomic, readwrite, assign) YGValue marginBottom;
@property (nonatomic, readwrite, assign) YGValue marginStart;
@property (nonatomic, readwrite, assign) YGValue marginEnd;
@property (nonatomic, readwrite, assign) YGValue marginHorizontal;
@property (nonatomic, readwrite, assign) YGValue marginVertical;
@property (nonatomic, readwrite, assign) YGValue margin;
@property (nonatomic, readwrite, assign) YGValue paddingLeft;
@property (nonatomic, readwrite, assign) YGValue paddingTop;
@property (nonatomic, readwrite, assign) YGValue paddingRight;
@property (nonatomic, readwrite, assign) YGValue paddingBottom;
@property (nonatomic, readwrite, assign) YGValue paddingStart;
@property (nonatomic, readwrite, assign) YGValue paddingEnd;
@property (nonatomic, readwrite, assign) YGValue paddingHorizontal;
@property (nonatomic, readwrite, assign) YGValue paddingVertical;
@property (nonatomic, readwrite, assign) YGValue padding;
@property (nonatomic, readwrite, assign) CGFloat borderLeftWidth;
@property (nonatomic, readwrite, assign) CGFloat borderTopWidth;
@property (nonatomic, readwrite, assign) CGFloat borderRightWidth;
@property (nonatomic, readwrite, assign) CGFloat borderBottomWidth;
@property (nonatomic, readwrite, assign) CGFloat borderStartWidth;
@property (nonatomic, readwrite, assign) CGFloat borderEndWidth;
@property (nonatomic, readwrite, assign) CGFloat borderWidth;
@property (nonatomic, readwrite, assign) YGValue width;
@property (nonatomic, readwrite, assign) YGValue height;
@property (nonatomic, readwrite, assign) YGValue minWidth;
@property (nonatomic, readwrite, assign) YGValue minHeight;
@property (nonatomic, readwrite, assign) YGValue maxWidth;
@property (nonatomic, readwrite, assign) YGValue maxHeight;
// Yoga specific properties, not compatible with flexbox specification
@property (nonatomic, readwrite, assign) CGFloat aspectRatio;
/**
Get the resolved direction of this node. This won't be YGDirectionInherit
*/
@property (nonatomic, readonly, assign) YGDirection resolvedDirection;
/**
Perform a layout calculation and update the frames of the views in the hierarchy with the results.
If the origin is not preserved, the root view's layout results will applied from {0,0}.
*/
- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin
NS_SWIFT_NAME(applyLayout(preservingOrigin:));
/**
Perform a layout calculation and update the frames of the views in the hierarchy with the results.
If the origin is not preserved, the root view's layout results will applied from {0,0}.
*/
- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin
dimensionFlexibility:(YGDimensionFlexibility)dimensionFlexibility
NS_SWIFT_NAME(applyLayout(preservingOrigin:dimensionFlexibility:));
/**
Returns the size of the view if no constraints were given. This could equivalent to calling [self
sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];
*/
@property (nonatomic, readonly, assign) CGSize intrinsicSize;
/**
Returns the size of the view based on provided constraints. Pass NaN for an unconstrained dimension.
*/
- (CGSize)calculateLayoutWithSize:(CGSize)size
NS_SWIFT_NAME(calculateLayout(with:));
/**
Returns the number of children that are using Flexbox.
*/
@property (nonatomic, readonly, assign) NSUInteger numberOfChildren;
/**
Return a BOOL indiciating whether or not we this node contains any subviews that are included in
Yoga's layout.
*/
@property (nonatomic, readonly, assign) BOOL isLeaf;
/**
Return's a BOOL indicating if a view is dirty. When a node is dirty
it usually indicates that it will be remeasured on the next layout pass.
*/
@property (nonatomic, readonly, assign) BOOL isDirty;
/**
Mark that a view's layout needs to be recalculated. Only works for leaf views.
*/
- (void)markDirty;
@end

482
YogaKit/Source/YGLayout.m Normal file
View File

@@ -0,0 +1,482 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "YGLayout+Private.h"
#import "UIView+Yoga.h"
#define YG_PROPERTY(type, lowercased_name, capitalized_name) \
- (type)lowercased_name \
{ \
return YGNodeStyleGet##capitalized_name(self.node); \
} \
\
- (void)set##capitalized_name:(type)lowercased_name \
{ \
YGNodeStyleSet##capitalized_name(self.node, lowercased_name); \
}
#define YG_VALUE_PROPERTY(lowercased_name, capitalized_name) \
- (YGValue)lowercased_name \
{ \
return YGNodeStyleGet##capitalized_name(self.node); \
} \
\
- (void)set##capitalized_name:(YGValue)lowercased_name \
{ \
switch (lowercased_name.unit) { \
case YGUnitUndefined: \
YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \
break; \
case YGUnitPoint: \
YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \
break; \
case YGUnitPercent: \
YGNodeStyleSet##capitalized_name##Percent(self.node, lowercased_name.value); \
break; \
default: \
NSAssert(NO, @"Not implemented"); \
} \
}
#define YG_AUTO_VALUE_PROPERTY(lowercased_name, capitalized_name) \
- (YGValue)lowercased_name \
{ \
return YGNodeStyleGet##capitalized_name(self.node); \
} \
\
- (void)set##capitalized_name:(YGValue)lowercased_name \
{ \
switch (lowercased_name.unit) { \
case YGUnitPoint: \
YGNodeStyleSet##capitalized_name(self.node, lowercased_name.value); \
break; \
case YGUnitPercent: \
YGNodeStyleSet##capitalized_name##Percent(self.node, lowercased_name.value); \
break; \
case YGUnitAuto: \
YGNodeStyleSet##capitalized_name##Auto(self.node); \
break; \
default: \
NSAssert(NO, @"Not implemented"); \
} \
}
#define YG_EDGE_PROPERTY_GETTER(type, lowercased_name, capitalized_name, property, edge) \
- (type)lowercased_name \
{ \
return YGNodeStyleGet##property(self.node, edge); \
}
#define YG_EDGE_PROPERTY_SETTER(lowercased_name, capitalized_name, property, edge) \
- (void)set##capitalized_name:(CGFloat)lowercased_name \
{ \
YGNodeStyleSet##property(self.node, edge, lowercased_name); \
}
#define YG_EDGE_PROPERTY(lowercased_name, capitalized_name, property, edge) \
YG_EDGE_PROPERTY_GETTER(CGFloat, lowercased_name, capitalized_name, property, edge) \
YG_EDGE_PROPERTY_SETTER(lowercased_name, capitalized_name, property, edge)
#define YG_VALUE_EDGE_PROPERTY_SETTER(objc_lowercased_name, objc_capitalized_name, c_name, edge) \
- (void)set##objc_capitalized_name:(YGValue)objc_lowercased_name \
{ \
switch (objc_lowercased_name.unit) { \
case YGUnitUndefined: \
YGNodeStyleSet##c_name(self.node, edge, objc_lowercased_name.value); \
break; \
case YGUnitPoint: \
YGNodeStyleSet##c_name(self.node, edge, objc_lowercased_name.value); \
break; \
case YGUnitPercent: \
YGNodeStyleSet##c_name##Percent(self.node, edge, objc_lowercased_name.value); \
break; \
default: \
NSAssert(NO, @"Not implemented"); \
} \
}
#define YG_VALUE_EDGE_PROPERTY(lowercased_name, capitalized_name, property, edge) \
YG_EDGE_PROPERTY_GETTER(YGValue, lowercased_name, capitalized_name, property, edge) \
YG_VALUE_EDGE_PROPERTY_SETTER(lowercased_name, capitalized_name, property, edge)
#define YG_VALUE_EDGES_PROPERTIES(lowercased_name, capitalized_name) \
YG_VALUE_EDGE_PROPERTY(lowercased_name##Left, capitalized_name##Left, capitalized_name, YGEdgeLeft) \
YG_VALUE_EDGE_PROPERTY(lowercased_name##Top, capitalized_name##Top, capitalized_name, YGEdgeTop) \
YG_VALUE_EDGE_PROPERTY(lowercased_name##Right, capitalized_name##Right, capitalized_name, YGEdgeRight) \
YG_VALUE_EDGE_PROPERTY(lowercased_name##Bottom, capitalized_name##Bottom, capitalized_name, YGEdgeBottom) \
YG_VALUE_EDGE_PROPERTY(lowercased_name##Start, capitalized_name##Start, capitalized_name, YGEdgeStart) \
YG_VALUE_EDGE_PROPERTY(lowercased_name##End, capitalized_name##End, capitalized_name, YGEdgeEnd) \
YG_VALUE_EDGE_PROPERTY(lowercased_name##Horizontal, capitalized_name##Horizontal, capitalized_name, YGEdgeHorizontal) \
YG_VALUE_EDGE_PROPERTY(lowercased_name##Vertical, capitalized_name##Vertical, capitalized_name, YGEdgeVertical) \
YG_VALUE_EDGE_PROPERTY(lowercased_name, capitalized_name, capitalized_name, YGEdgeAll)
YGValue YGPointValue(CGFloat value)
{
return (YGValue) { .value = value, .unit = YGUnitPoint };
}
YGValue YGPercentValue(CGFloat value)
{
return (YGValue) { .value = value, .unit = YGUnitPercent };
}
static YGConfigRef globalConfig;
@interface YGLayout ()
@property (nonatomic, weak, readonly) UIView *view;
@property(nonatomic, assign, readonly) BOOL isUIView;
@end
@implementation YGLayout
@synthesize isEnabled=_isEnabled;
@synthesize isIncludedInLayout=_isIncludedInLayout;
@synthesize node=_node;
+ (void)initialize
{
globalConfig = YGConfigNew();
YGConfigSetExperimentalFeatureEnabled(globalConfig, YGExperimentalFeatureWebFlexBasis, true);
YGConfigSetPointScaleFactor(globalConfig, [UIScreen mainScreen].scale);
}
- (instancetype)initWithView:(UIView*)view
{
if (self = [super init]) {
_view = view;
_node = YGNodeNewWithConfig(globalConfig);
YGNodeSetContext(_node, (__bridge void *) view);
_isEnabled = NO;
_isIncludedInLayout = YES;
_isUIView = [view isMemberOfClass:[UIView class]];
}
return self;
}
- (void)dealloc
{
YGNodeFree(self.node);
}
- (BOOL)isDirty
{
return YGNodeIsDirty(self.node);
}
- (void)markDirty
{
if (self.isDirty || !self.isLeaf) {
return;
}
// Yoga is not happy if we try to mark a node as "dirty" before we have set
// the measure function. Since we already know that this is a leaf,
// this *should* be fine. Forgive me Hack Gods.
const YGNodeRef node = self.node;
if (YGNodeHasMeasureFunc(node)) {
YGNodeSetMeasureFunc(node, YGMeasureView);
}
YGNodeMarkDirty(node);
}
- (NSUInteger)numberOfChildren
{
return YGNodeGetChildCount(self.node);
}
- (BOOL)isLeaf
{
NSAssert([NSThread isMainThread], @"This method must be called on the main thread.");
if (self.isEnabled) {
for (UIView *subview in self.view.subviews) {
YGLayout *const yoga = subview.yoga;
if (yoga.isEnabled && yoga.isIncludedInLayout) {
return NO;
}
}
}
return YES;
}
#pragma mark - Style
- (YGPositionType)position
{
return YGNodeStyleGetPositionType(self.node);
}
- (void)setPosition:(YGPositionType)position
{
YGNodeStyleSetPositionType(self.node, position);
}
YG_PROPERTY(YGDirection, direction, Direction)
YG_PROPERTY(YGFlexDirection, flexDirection, FlexDirection)
YG_PROPERTY(YGJustify, justifyContent, JustifyContent)
YG_PROPERTY(YGAlign, alignContent, AlignContent)
YG_PROPERTY(YGAlign, alignItems, AlignItems)
YG_PROPERTY(YGAlign, alignSelf, AlignSelf)
YG_PROPERTY(YGWrap, flexWrap, FlexWrap)
YG_PROPERTY(YGOverflow, overflow, Overflow)
YG_PROPERTY(YGDisplay, display, Display)
YG_PROPERTY(CGFloat, flex, Flex)
YG_PROPERTY(CGFloat, flexGrow, FlexGrow)
YG_PROPERTY(CGFloat, flexShrink, FlexShrink)
YG_AUTO_VALUE_PROPERTY(flexBasis, FlexBasis)
YG_VALUE_EDGE_PROPERTY(left, Left, Position, YGEdgeLeft)
YG_VALUE_EDGE_PROPERTY(top, Top, Position, YGEdgeTop)
YG_VALUE_EDGE_PROPERTY(right, Right, Position, YGEdgeRight)
YG_VALUE_EDGE_PROPERTY(bottom, Bottom, Position, YGEdgeBottom)
YG_VALUE_EDGE_PROPERTY(start, Start, Position, YGEdgeStart)
YG_VALUE_EDGE_PROPERTY(end, End, Position, YGEdgeEnd)
YG_VALUE_EDGES_PROPERTIES(margin, Margin)
YG_VALUE_EDGES_PROPERTIES(padding, Padding)
YG_EDGE_PROPERTY(borderLeftWidth, BorderLeftWidth, Border, YGEdgeLeft)
YG_EDGE_PROPERTY(borderTopWidth, BorderTopWidth, Border, YGEdgeTop)
YG_EDGE_PROPERTY(borderRightWidth, BorderRightWidth, Border, YGEdgeRight)
YG_EDGE_PROPERTY(borderBottomWidth, BorderBottomWidth, Border, YGEdgeBottom)
YG_EDGE_PROPERTY(borderStartWidth, BorderStartWidth, Border, YGEdgeStart)
YG_EDGE_PROPERTY(borderEndWidth, BorderEndWidth, Border, YGEdgeEnd)
YG_EDGE_PROPERTY(borderWidth, BorderWidth, Border, YGEdgeAll)
YG_AUTO_VALUE_PROPERTY(width, Width)
YG_AUTO_VALUE_PROPERTY(height, Height)
YG_VALUE_PROPERTY(minWidth, MinWidth)
YG_VALUE_PROPERTY(minHeight, MinHeight)
YG_VALUE_PROPERTY(maxWidth, MaxWidth)
YG_VALUE_PROPERTY(maxHeight, MaxHeight)
YG_PROPERTY(CGFloat, aspectRatio, AspectRatio)
#pragma mark - Layout and Sizing
- (YGDirection)resolvedDirection
{
return YGNodeLayoutGetDirection(self.node);
}
- (void)applyLayout
{
[self calculateLayoutWithSize:self.view.bounds.size];
YGApplyLayoutToViewHierarchy(self.view, NO);
}
- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin
{
[self calculateLayoutWithSize:self.view.bounds.size];
YGApplyLayoutToViewHierarchy(self.view, preserveOrigin);
}
- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin dimensionFlexibility:(YGDimensionFlexibility)dimensionFlexibility
{
CGSize size = self.view.bounds.size;
if (dimensionFlexibility & YGDimensionFlexibilityFlexibleWidth) {
size.width = YGUndefined;
}
if (dimensionFlexibility & YGDimensionFlexibilityFlexibleHeight) {
size.height = YGUndefined;
}
[self calculateLayoutWithSize:size];
YGApplyLayoutToViewHierarchy(self.view, preserveOrigin);
}
- (CGSize)intrinsicSize
{
const CGSize constrainedSize = {
.width = YGUndefined,
.height = YGUndefined,
};
return [self calculateLayoutWithSize:constrainedSize];
}
- (CGSize)calculateLayoutWithSize:(CGSize)size
{
NSAssert([NSThread isMainThread], @"Yoga calculation must be done on main.");
NSAssert(self.isEnabled, @"Yoga is not enabled for this view.");
YGAttachNodesFromViewHierachy(self.view);
const YGNodeRef node = self.node;
YGNodeCalculateLayout(
node,
size.width,
size.height,
YGNodeStyleGetDirection(node));
return (CGSize) {
.width = YGNodeLayoutGetWidth(node),
.height = YGNodeLayoutGetHeight(node),
};
}
#pragma mark - Private
static YGSize YGMeasureView(
YGNodeRef node,
float width,
YGMeasureMode widthMode,
float height,
YGMeasureMode heightMode)
{
const CGFloat constrainedWidth = (widthMode == YGMeasureModeUndefined) ? CGFLOAT_MAX : width;
const CGFloat constrainedHeight = (heightMode == YGMeasureModeUndefined) ? CGFLOAT_MAX: height;
UIView *view = (__bridge UIView*) YGNodeGetContext(node);
CGSize sizeThatFits = CGSizeZero;
// The default implementation of sizeThatFits: returns the existing size of
// the view. That means that if we want to layout an empty UIView, which
// already has got a frame set, its measured size should be CGSizeZero, but
// UIKit returns the existing size.
//
// See https://github.com/facebook/yoga/issues/606 for more information.
if (!view.yoga.isUIView || [view.subviews count] > 0) {
sizeThatFits = [view sizeThatFits:(CGSize){
.width = constrainedWidth,
.height = constrainedHeight,
}];
}
return (YGSize) {
.width = YGSanitizeMeasurement(constrainedWidth, sizeThatFits.width, widthMode),
.height = YGSanitizeMeasurement(constrainedHeight, sizeThatFits.height, heightMode),
};
}
static CGFloat YGSanitizeMeasurement(
CGFloat constrainedSize,
CGFloat measuredSize,
YGMeasureMode measureMode)
{
CGFloat result;
if (measureMode == YGMeasureModeExactly) {
result = constrainedSize;
} else if (measureMode == YGMeasureModeAtMost) {
result = MIN(constrainedSize, measuredSize);
} else {
result = measuredSize;
}
return result;
}
static BOOL YGNodeHasExactSameChildren(const YGNodeRef node, NSArray<UIView *> *subviews)
{
if (YGNodeGetChildCount(node) != subviews.count) {
return NO;
}
for (int i=0; i<subviews.count; i++) {
if (YGNodeGetChild(node, i) != subviews[i].yoga.node) {
return NO;
}
}
return YES;
}
static void YGAttachNodesFromViewHierachy(UIView *const view)
{
YGLayout *const yoga = view.yoga;
const YGNodeRef node = yoga.node;
// Only leaf nodes should have a measure function
if (yoga.isLeaf) {
YGRemoveAllChildren(node);
YGNodeSetMeasureFunc(node, YGMeasureView);
} else {
YGNodeSetMeasureFunc(node, NULL);
NSMutableArray<UIView *> *subviewsToInclude = [[NSMutableArray alloc] initWithCapacity:view.subviews.count];
for (UIView *subview in view.subviews) {
if (subview.yoga.isEnabled && subview.yoga.isIncludedInLayout) {
[subviewsToInclude addObject:subview];
}
}
if (!YGNodeHasExactSameChildren(node, subviewsToInclude)) {
YGRemoveAllChildren(node);
for (int i=0; i<subviewsToInclude.count; i++) {
YGNodeInsertChild(node, subviewsToInclude[i].yoga.node, i);
}
}
for (UIView *const subview in subviewsToInclude) {
YGAttachNodesFromViewHierachy(subview);
}
}
}
static void YGRemoveAllChildren(const YGNodeRef node)
{
if (node == NULL) {
return;
}
YGNodeRemoveAllChildren(node);
}
static CGFloat YGRoundPixelValue(CGFloat value)
{
static CGFloat scale;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^(){
scale = [UIScreen mainScreen].scale;
});
return roundf(value * scale) / scale;
}
static void YGApplyLayoutToViewHierarchy(UIView *view, BOOL preserveOrigin)
{
NSCAssert([NSThread isMainThread], @"Framesetting should only be done on the main thread.");
const YGLayout *yoga = view.yoga;
if (!yoga.isIncludedInLayout) {
return;
}
YGNodeRef node = yoga.node;
const CGPoint topLeft = {
YGNodeLayoutGetLeft(node),
YGNodeLayoutGetTop(node),
};
const CGPoint bottomRight = {
topLeft.x + YGNodeLayoutGetWidth(node),
topLeft.y + YGNodeLayoutGetHeight(node),
};
const CGPoint origin = preserveOrigin ? view.frame.origin : CGPointZero;
view.frame = (CGRect) {
.origin = {
.x = YGRoundPixelValue(topLeft.x + origin.x),
.y = YGRoundPixelValue(topLeft.y + origin.y),
},
.size = {
.width = YGRoundPixelValue(bottomRight.x) - YGRoundPixelValue(topLeft.x),
.height = YGRoundPixelValue(bottomRight.y) - YGRoundPixelValue(topLeft.y),
},
};
if (!yoga.isLeaf) {
for (NSUInteger i=0; i<view.subviews.count; i++) {
YGApplyLayoutToViewHierarchy(view.subviews[i], NO);
}
}
}
@end

View File

@@ -0,0 +1,44 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
postfix operator %
extension Int {
public static postfix func %(value: Int) -> YGValue {
return YGValue(value: Float(value), unit: .percent)
}
}
extension Float {
public static postfix func %(value: Float) -> YGValue {
return YGValue(value: value, unit: .percent)
}
}
extension CGFloat {
public static postfix func %(value: CGFloat) -> YGValue {
return YGValue(value: Float(value), unit: .percent)
}
}
extension YGValue : ExpressibleByIntegerLiteral, ExpressibleByFloatLiteral {
public init(integerLiteral value: Int) {
self = YGValue(value: Float(value), unit: .point)
}
public init(floatLiteral value: Float) {
self = YGValue(value: value, unit: .point)
}
public init(_ value: Float) {
self = YGValue(value: value, unit: .point)
}
public init(_ value: CGFloat) {
self = YGValue(value: Float(value), unit: .point)
}
}

22
YogaKit/Tests/Info.plist Normal file
View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.facebook.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@@ -0,0 +1,754 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <XCTest/XCTest.h>
#import <YogaKit/UIView+Yoga.h>
#import <YogaKit/YGLayout+Private.h>
#import <yoga/Yoga.h>
@interface YogaKitTests : XCTestCase
@end
@implementation YogaKitTests
- (void)testConfigureLayoutIsNoOpWithNilBlock
{
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
id block = nil;
XCTAssertNoThrow([view configureLayoutWithBlock:block]);
}
- (void)testConfigureLayoutBlockWorksWithValidBlock
{
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
[view configureLayoutWithBlock:^(YGLayout *layout){
XCTAssertNotNil(layout);
layout.isEnabled = YES;
layout.width = YGPointValue(25);
}];
XCTAssertTrue(view.yoga.isEnabled);
XCTAssertEqual(view.yoga.width.value, 25);
}
- (void)testNodesAreDeallocedWithSingleView
{
__weak YGLayout *layoutRef = nil;
@autoreleasepool {
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
view.yoga.flexBasis = YGPointValue(1);
layoutRef = view.yoga;
XCTAssertNotNil(layoutRef);
view = nil;
}
XCTAssertNil(layoutRef);
}
- (void)testNodesAreDeallocedCascade
{
__weak YGLayout *topLayout = nil;
__weak YGLayout *subviewLayout = nil;
@autoreleasepool {
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
topLayout = view.yoga;
topLayout.flexBasis = YGPointValue(1);
UIView *subview = [[UIView alloc] initWithFrame:CGRectZero];
subviewLayout = subview.yoga;
subviewLayout.flexBasis = YGPointValue(1);
view = nil;
}
XCTAssertNil(topLayout);
XCTAssertNil(subviewLayout);
}
- (void)testIsEnabled
{
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
XCTAssertFalse(view.yoga.isEnabled);
view.yoga.isEnabled = YES;
XCTAssertTrue(view.yoga.isEnabled);
view.yoga.isEnabled = NO;
XCTAssertFalse(view.yoga.isEnabled);
}
- (void)testSizeThatFitsAsserts
{
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
dispatch_sync(dispatch_queue_create("com.facebook.Yoga.testing", DISPATCH_QUEUE_SERIAL), ^(void){
XCTAssertThrows(view.yoga.intrinsicSize);
});
}
- (void)testSizeThatFitsSmoke
{
UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
container.yoga.isEnabled = YES;
container.yoga.flexDirection = YGFlexDirectionRow;
container.yoga.alignItems = YGAlignFlexStart;
UILabel *longTextLabel = [[UILabel alloc] initWithFrame:CGRectZero];
longTextLabel.text = @"This is a very very very very very very very very long piece of text.";
longTextLabel.lineBreakMode = NSLineBreakByTruncatingTail;
longTextLabel.numberOfLines = 1;
longTextLabel.yoga.isEnabled = YES;
longTextLabel.yoga.flexShrink = 1;
[container addSubview:longTextLabel];
UIView *textBadgeView = [[UIView alloc] initWithFrame:CGRectZero];
textBadgeView.yoga.isEnabled = YES;
textBadgeView.yoga.margin = YGPointValue(0);
textBadgeView.yoga.width = YGPointValue(10);
textBadgeView.yoga.height = YGPointValue(10);
[container addSubview:textBadgeView];
const CGSize textBadgeViewSize = textBadgeView.yoga.intrinsicSize;
XCTAssertEqual(textBadgeViewSize.height, 10);
XCTAssertEqual(textBadgeViewSize.width, 10);
const CGSize containerSize = container.yoga.intrinsicSize;
const CGSize longTextLabelSize = longTextLabel.yoga.intrinsicSize;
XCTAssertEqual(longTextLabelSize.height, containerSize.height);
XCTAssertEqual(longTextLabelSize.width + textBadgeView.yoga.intrinsicSize.width, containerSize.width);
}
- (void)testSizeThatFitsEmptyView {
UIView* view = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 200, 200)];
view.yoga.isEnabled = YES;
const CGSize viewSize = view.yoga.intrinsicSize;
XCTAssertEqual(viewSize.height, 0);
XCTAssertEqual(viewSize.width, 0);
}
- (void)testPreservingOrigin
{
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0,0,50,75)];
container.yoga.isEnabled = YES;
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
view.yoga.isEnabled = YES;
view.yoga.flexBasis = YGPointValue(0);
view.yoga.flexGrow = 1;
[container addSubview:view];
UIView *view2 = [[UIView alloc] initWithFrame:CGRectZero];
view2.yoga.isEnabled = YES;
view2.yoga.marginTop = YGPointValue(25);
view2.yoga.flexBasis = YGPointValue(0);
view2.yoga.flexGrow = 1;
[container addSubview:view2];
[container.yoga applyLayoutPreservingOrigin:YES];
XCTAssertEqual(50, view2.frame.origin.y);
[view2.yoga applyLayoutPreservingOrigin:NO];
XCTAssertEqual(25, view2.frame.origin.y);
}
- (void)testContainerWithFlexibleWidthGetsCorrectlySized
{
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0,0,200,200)];
container.yoga.isEnabled = YES;
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
view.yoga.isEnabled = YES;
view.yoga.width = YGPointValue(100);
view.yoga.height = YGPointValue(100);
[container addSubview:view];
[container.yoga applyLayoutPreservingOrigin:YES dimensionFlexibility:YGDimensionFlexibilityFlexibleWidth];
XCTAssertEqual(100, container.frame.size.width);
XCTAssertEqual(200, container.frame.size.height);
}
- (void)testContainerWithFlexibleHeightGetsCorrectlySized
{
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0,0,200,200)];
container.yoga.isEnabled = YES;
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
view.yoga.isEnabled = YES;
view.yoga.width = YGPointValue(100);
view.yoga.height = YGPointValue(100);
[container addSubview:view];
[container.yoga
applyLayoutPreservingOrigin:YES
dimensionFlexibility:YGDimensionFlexibilityFlexibleHeight];
XCTAssertEqual(200, container.frame.size.width);
XCTAssertEqual(100, container.frame.size.height);
}
- (void)testContainerWithFlexibleWidthAndHeightGetsCorrectlySized
{
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0,0,200,200)];
container.yoga.isEnabled = YES;
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
view.yoga.isEnabled = YES;
view.yoga.width = YGPointValue(100);
view.yoga.height = YGPointValue(100);
[container addSubview:view];
[container.yoga
applyLayoutPreservingOrigin:YES
dimensionFlexibility:YGDimensionFlexibilityFlexibleWidth |
YGDimensionFlexibilityFlexibleHeight];
XCTAssertEqual(100, container.frame.size.width);
XCTAssertEqual(100, container.frame.size.height);
}
- (void)testMarkingDirtyOnlyWorksOnLeafNodes
{
UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
container.yoga.isEnabled = YES;
UIView *subview = [[UIView alloc] initWithFrame:CGRectZero];
subview.yoga.isEnabled = YES;
[container addSubview:subview];
XCTAssertFalse(container.yoga.isDirty);
[container.yoga markDirty];
XCTAssertFalse(container.yoga.isDirty);
XCTAssertFalse(subview.yoga.isDirty);
[subview.yoga markDirty];
XCTAssertTrue(subview.yoga.isDirty);
}
- (void)testThatMarkingLeafsAsDirtyWillTriggerASizeRecalculation
{
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 50)];
container.yoga.isEnabled = YES;
container.yoga.flexDirection = YGFlexDirectionRow;
container.yoga.alignItems = YGAlignFlexStart;
UILabel *view = [[UILabel alloc] initWithFrame:CGRectZero];
view.text = @"This is a short text.";
view.numberOfLines = 1;
view.yoga.isEnabled = YES;
[container addSubview:view];
[container.yoga applyLayoutPreservingOrigin:YES];
CGSize const viewSizeAfterFirstPass = view.frame.size;
view.text = @"This is a slightly longer text.";
XCTAssertTrue(CGSizeEqualToSize(view.frame.size, viewSizeAfterFirstPass));
[view.yoga markDirty];
[container.yoga applyLayoutPreservingOrigin:YES];
XCTAssertFalse(CGSizeEqualToSize(view.frame.size, viewSizeAfterFirstPass));
}
- (void)testFrameAndOriginPlacement
{
const CGSize containerSize = CGSizeMake(320, 50);
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)];
container.yoga.isEnabled = YES;
container.yoga.flexDirection = YGFlexDirectionRow;
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
subview1.yoga.isEnabled = YES;
subview1.yoga.flexGrow = 1;
[container addSubview:subview1];
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
subview2.yoga.isEnabled = YES;
subview2.yoga.flexGrow = 1;
[container addSubview:subview2];
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
subview3.yoga.isEnabled = YES;
subview3.yoga.flexGrow = 1;
[container addSubview:subview3];
[container.yoga applyLayoutPreservingOrigin:YES];
XCTAssertEqualWithAccuracy(subview2.frame.origin.x, CGRectGetMaxX(subview1.frame), FLT_EPSILON);
XCTAssertEqualWithAccuracy(subview3.frame.origin.x, CGRectGetMaxX(subview2.frame), FLT_EPSILON);
CGFloat totalWidth = 0;
for (UIView *view in container.subviews) {
totalWidth += view.bounds.size.width;
}
XCTAssertEqual(containerSize.width, totalWidth, @"The container's width is %.6f, the subviews take up %.6f", containerSize.width, totalWidth);
}
- (void)testThatLayoutIsCorrectWhenWeSwapViewOrder
{
const CGSize containerSize = CGSizeMake(300, 50);
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)];
container.yoga.isEnabled = YES;
container.yoga.flexDirection = YGFlexDirectionRow;
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
subview1.yoga.isEnabled = YES;
subview1.yoga.flexGrow = 1;
[container addSubview:subview1];
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
subview2.yoga.isEnabled = YES;
subview2.yoga.flexGrow = 1;
[container addSubview:subview2];
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
subview3.yoga.isEnabled = YES;
subview3.yoga.flexGrow = 1;
[container addSubview:subview3];
[container.yoga applyLayoutPreservingOrigin:YES];
XCTAssertTrue(CGRectEqualToRect(subview1.frame, CGRectMake(0, 0, 100, 50)));
XCTAssertTrue(CGRectEqualToRect(subview2.frame, CGRectMake(100, 0, 100, 50)));
XCTAssertTrue(CGRectEqualToRect(subview3.frame, CGRectMake(200, 0, 100, 50)));
[container exchangeSubviewAtIndex:2 withSubviewAtIndex:0];
subview2.yoga.isIncludedInLayout = NO;
[container.yoga applyLayoutPreservingOrigin:YES];
XCTAssertTrue(CGRectEqualToRect(subview3.frame, CGRectMake(0, 0, 150, 50)));
XCTAssertTrue(CGRectEqualToRect(subview1.frame, CGRectMake(150, 0, 150, 50)));
// this frame shouldn't have been modified since last time.
XCTAssertTrue(CGRectEqualToRect(subview2.frame, CGRectMake(100, 0, 100, 50)));
}
- (void)testThatWeRespectIncludeInLayoutFlag
{
const CGSize containerSize = CGSizeMake(300, 50);
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)];
container.yoga.isEnabled = YES;
container.yoga.flexDirection = YGFlexDirectionRow;
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
subview1.yoga.isEnabled = YES;
subview1.yoga.flexGrow = 1;
[container addSubview:subview1];
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
subview2.yoga.isEnabled = YES;
subview2.yoga.flexGrow = 1;
[container addSubview:subview2];
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
subview3.yoga.isEnabled = YES;
subview3.yoga.flexGrow = 1;
[container addSubview:subview3];
[container.yoga applyLayoutPreservingOrigin:YES];
for (UIView *subview in container.subviews) {
XCTAssertEqual(subview.bounds.size.width, 100);
}
subview3.yoga.isIncludedInLayout = NO;
[container.yoga applyLayoutPreservingOrigin:YES];
XCTAssertEqual(subview1.bounds.size.width, 150);
XCTAssertEqual(subview2.bounds.size.width, 150);
// We don't set the frame to zero, so, it should be set to what it was previously at.
XCTAssertEqual(subview3.bounds.size.width, 100);
}
- (void)testThatNumberOfChildrenIsCorrectWhenWeIgnoreSubviews
{
UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
container.yoga.isEnabled = YES;
container.yoga.flexDirection = YGFlexDirectionRow;
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
subview1.yoga.isEnabled = YES;
subview1.yoga.isIncludedInLayout = NO;
[container addSubview:subview1];
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
subview2.yoga.isEnabled = YES;
subview2.yoga.isIncludedInLayout = NO;
[container addSubview:subview2];
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
subview3.yoga.isEnabled = YES;
subview3.yoga.isIncludedInLayout = YES;
[container addSubview:subview3];
[container.yoga applyLayoutPreservingOrigin:YES];
XCTAssertEqual(container.yoga.numberOfChildren, 1);
subview2.yoga.isIncludedInLayout = YES;
[container.yoga applyLayoutPreservingOrigin:YES];
XCTAssertEqual(container.yoga.numberOfChildren, 2);
}
- (void)testThatViewNotIncludedInFirstLayoutPassAreIncludedInSecond
{
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)];
container.yoga.isEnabled = YES;
container.yoga.flexDirection = YGFlexDirectionRow;
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
subview1.yoga.isEnabled = YES;
subview1.yoga.flexGrow = 1;
[container addSubview:subview1];
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
subview2.yoga.isEnabled = YES;
subview2.yoga.flexGrow = 1;
[container addSubview:subview2];
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
subview3.yoga.isEnabled = YES;
subview3.yoga.flexGrow = 1;
subview3.yoga.isIncludedInLayout = NO;
[container addSubview:subview3];
[container.yoga applyLayoutPreservingOrigin:YES];
XCTAssertEqual(subview1.bounds.size.width, 150);
XCTAssertEqual(subview2.bounds.size.width, 150);
XCTAssertEqual(subview3.bounds.size.width, 0);
subview3.yoga.isIncludedInLayout = YES;
[container.yoga applyLayoutPreservingOrigin:YES];
XCTAssertEqual(subview1.bounds.size.width, 100);
XCTAssertEqual(subview2.bounds.size.width, 100);
XCTAssertEqual(subview3.bounds.size.width, 100);
}
- (void)testIsLeafFlag
{
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
XCTAssertTrue(view.yoga.isLeaf);
for (int i=0; i<10; i++) {
UIView *subview = [[UIView alloc] initWithFrame:CGRectZero];
[view addSubview:subview];
}
XCTAssertTrue(view.yoga.isLeaf);
view.yoga.isEnabled = YES;
view.yoga.width = YGPointValue(50);
XCTAssertTrue(view.yoga.isLeaf);
UIView *const subview = view.subviews[0];
subview.yoga.isEnabled = YES;
subview.yoga.width = YGPointValue(50);
XCTAssertFalse(view.yoga.isLeaf);
}
- (void)testThatWeCorrectlyAttachNestedViews
{
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)];
container.yoga.isEnabled = YES;
container.yoga.flexDirection = YGFlexDirectionColumn;
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
subview1.yoga.isEnabled = YES;
subview1.yoga.width = YGPointValue(100);
subview1.yoga.flexGrow = 1;
subview1.yoga.flexDirection = YGFlexDirectionColumn;
[container addSubview:subview1];
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
subview2.yoga.isEnabled = YES;
subview2.yoga.width = YGPointValue(150);
subview2.yoga.flexGrow = 1;
subview2.yoga.flexDirection = YGFlexDirectionColumn;
[container addSubview:subview2];
for (UIView *view in @[subview1, subview2]) {
UIView *someView = [[UIView alloc] initWithFrame:CGRectZero];
someView.yoga.isEnabled = YES;
someView.yoga.flexGrow = 1;
[view addSubview:someView];
}
[container.yoga applyLayoutPreservingOrigin:YES];
// Add the same amount of new views, reapply layout.
for (UIView *view in @[subview1, subview2]) {
UIView *someView = [[UIView alloc] initWithFrame:CGRectZero];
someView.yoga.isEnabled = YES;
someView.yoga.flexGrow = 1;
[view addSubview:someView];
}
[container.yoga applyLayoutPreservingOrigin:YES];
XCTAssertEqual(subview1.bounds.size.width, 100);
XCTAssertEqual(subview1.bounds.size.height, 25);
for (UIView *subview in subview1.subviews) {
const CGSize subviewSize = subview.bounds.size;
XCTAssertNotEqual(subviewSize.width, 0);
XCTAssertNotEqual(subviewSize.height, 0);
XCTAssertFalse(isnan(subviewSize.height));
XCTAssertFalse(isnan(subviewSize.width));
}
XCTAssertEqual(subview2.bounds.size.width, 150);
XCTAssertEqual(subview2.bounds.size.height, 25);
for (UIView *subview in subview2.subviews) {
const CGSize subviewSize = subview.bounds.size;
XCTAssertNotEqual(subviewSize.width, 0);
XCTAssertNotEqual(subviewSize.height, 0);
XCTAssertFalse(isnan(subviewSize.height));
XCTAssertFalse(isnan(subviewSize.width));
}
}
- (void)testThatANonLeafNodeCanBecomeALeafNode
{
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)];
container.yoga.isEnabled = YES;
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
subview1.yoga.isEnabled = YES;
[container addSubview:subview1];
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
subview2.yoga.isEnabled = YES;
[subview1 addSubview:subview2];
[container.yoga applyLayoutPreservingOrigin:YES];
[subview2 removeFromSuperview];
[container.yoga applyLayoutPreservingOrigin:YES];
}
- (void)testPointPercent
{
XCTAssertEqual(YGPointValue(1).value, 1);
XCTAssertEqual(YGPointValue(1).unit, YGUnitPoint);
XCTAssertEqual(YGPercentValue(2).value, 2);
XCTAssertEqual(YGPercentValue(2).unit, YGUnitPercent);
}
- (void)testPositionalPropertiesWork
{
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
view.yoga.left = YGPointValue(1);
XCTAssertEqual(view.yoga.left.value, 1);
XCTAssertEqual(view.yoga.left.unit, YGUnitPoint);
view.yoga.left = YGPercentValue(2);
XCTAssertEqual(view.yoga.left.value, 2);
XCTAssertEqual(view.yoga.left.unit, YGUnitPercent);
view.yoga.right = YGPointValue(3);
XCTAssertEqual(view.yoga.right.value, 3);
XCTAssertEqual(view.yoga.right.unit, YGUnitPoint);
view.yoga.right = YGPercentValue(4);
XCTAssertEqual(view.yoga.right.value, 4);
XCTAssertEqual(view.yoga.right.unit, YGUnitPercent);
view.yoga.top = YGPointValue(5);
XCTAssertEqual(view.yoga.top.value, 5);
XCTAssertEqual(view.yoga.top.unit, YGUnitPoint);
view.yoga.top = YGPercentValue(6);
XCTAssertEqual(view.yoga.top.value, 6);
XCTAssertEqual(view.yoga.top.unit, YGUnitPercent);
view.yoga.bottom = YGPointValue(7);
XCTAssertEqual(view.yoga.bottom.value, 7);
XCTAssertEqual(view.yoga.bottom.unit, YGUnitPoint);
view.yoga.bottom = YGPercentValue(8);
XCTAssertEqual(view.yoga.bottom.value, 8);
XCTAssertEqual(view.yoga.bottom.unit, YGUnitPercent);
view.yoga.start = YGPointValue(9);
XCTAssertEqual(view.yoga.start.value, 9);
XCTAssertEqual(view.yoga.start.unit, YGUnitPoint);
view.yoga.start = YGPercentValue(10);
XCTAssertEqual(view.yoga.start.value, 10);
XCTAssertEqual(view.yoga.start.unit, YGUnitPercent);
view.yoga.end = YGPointValue(11);
XCTAssertEqual(view.yoga.end.value, 11);
XCTAssertEqual(view.yoga.end.unit, YGUnitPoint);
view.yoga.end = YGPercentValue(12);
XCTAssertEqual(view.yoga.end.value, 12);
XCTAssertEqual(view.yoga.end.unit, YGUnitPercent);
}
- (void)testMarginPropertiesWork
{
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
view.yoga.margin = YGPointValue(1);
XCTAssertEqual(view.yoga.margin.value, 1);
XCTAssertEqual(view.yoga.margin.unit, YGUnitPoint);
view.yoga.margin = YGPercentValue(2);
XCTAssertEqual(view.yoga.margin.value, 2);
XCTAssertEqual(view.yoga.margin.unit, YGUnitPercent);
view.yoga.marginHorizontal = YGPointValue(3);
XCTAssertEqual(view.yoga.marginHorizontal.value, 3);
XCTAssertEqual(view.yoga.marginHorizontal.unit, YGUnitPoint);
view.yoga.marginHorizontal = YGPercentValue(4);
XCTAssertEqual(view.yoga.marginHorizontal.value, 4);
XCTAssertEqual(view.yoga.marginHorizontal.unit, YGUnitPercent);
view.yoga.marginVertical = YGPointValue(5);
XCTAssertEqual(view.yoga.marginVertical.value, 5);
XCTAssertEqual(view.yoga.marginVertical.unit, YGUnitPoint);
view.yoga.marginVertical = YGPercentValue(6);
XCTAssertEqual(view.yoga.marginVertical.value, 6);
XCTAssertEqual(view.yoga.marginVertical.unit, YGUnitPercent);
view.yoga.marginLeft = YGPointValue(7);
XCTAssertEqual(view.yoga.marginLeft.value, 7);
XCTAssertEqual(view.yoga.marginLeft.unit, YGUnitPoint);
view.yoga.marginLeft = YGPercentValue(8);
XCTAssertEqual(view.yoga.marginLeft.value, 8);
XCTAssertEqual(view.yoga.marginLeft.unit, YGUnitPercent);
view.yoga.marginRight = YGPointValue(9);
XCTAssertEqual(view.yoga.marginRight.value, 9);
XCTAssertEqual(view.yoga.marginRight.unit, YGUnitPoint);
view.yoga.marginRight = YGPercentValue(10);
XCTAssertEqual(view.yoga.marginRight.value, 10);
XCTAssertEqual(view.yoga.marginRight.unit, YGUnitPercent);
view.yoga.marginTop = YGPointValue(11);
XCTAssertEqual(view.yoga.marginTop.value, 11);
XCTAssertEqual(view.yoga.marginTop.unit, YGUnitPoint);
view.yoga.marginTop = YGPercentValue(12);
XCTAssertEqual(view.yoga.marginTop.value, 12);
XCTAssertEqual(view.yoga.marginTop.unit, YGUnitPercent);
view.yoga.marginBottom = YGPointValue(13);
XCTAssertEqual(view.yoga.marginBottom.value, 13);
XCTAssertEqual(view.yoga.marginBottom.unit, YGUnitPoint);
view.yoga.marginBottom = YGPercentValue(14);
XCTAssertEqual(view.yoga.marginBottom.value, 14);
XCTAssertEqual(view.yoga.marginBottom.unit, YGUnitPercent);
view.yoga.marginStart = YGPointValue(15);
XCTAssertEqual(view.yoga.marginStart.value, 15);
XCTAssertEqual(view.yoga.marginStart.unit, YGUnitPoint);
view.yoga.marginStart = YGPercentValue(16);
XCTAssertEqual(view.yoga.marginStart.value, 16);
XCTAssertEqual(view.yoga.marginStart.unit, YGUnitPercent);
view.yoga.marginEnd = YGPointValue(17);
XCTAssertEqual(view.yoga.marginEnd.value, 17);
XCTAssertEqual(view.yoga.marginEnd.unit, YGUnitPoint);
view.yoga.marginEnd = YGPercentValue(18);
XCTAssertEqual(view.yoga.marginEnd.value, 18);
XCTAssertEqual(view.yoga.marginEnd.unit, YGUnitPercent);
}
- (void)testPaddingPropertiesWork
{
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
view.yoga.padding = YGPointValue(1);
XCTAssertEqual(view.yoga.padding.value, 1);
XCTAssertEqual(view.yoga.padding.unit, YGUnitPoint);
view.yoga.padding = YGPercentValue(2);
XCTAssertEqual(view.yoga.padding.value, 2);
XCTAssertEqual(view.yoga.padding.unit, YGUnitPercent);
view.yoga.paddingHorizontal = YGPointValue(3);
XCTAssertEqual(view.yoga.paddingHorizontal.value, 3);
XCTAssertEqual(view.yoga.paddingHorizontal.unit, YGUnitPoint);
view.yoga.paddingHorizontal = YGPercentValue(4);
XCTAssertEqual(view.yoga.paddingHorizontal.value, 4);
XCTAssertEqual(view.yoga.paddingHorizontal.unit, YGUnitPercent);
view.yoga.paddingVertical = YGPointValue(5);
XCTAssertEqual(view.yoga.paddingVertical.value, 5);
XCTAssertEqual(view.yoga.paddingVertical.unit, YGUnitPoint);
view.yoga.paddingVertical = YGPercentValue(6);
XCTAssertEqual(view.yoga.paddingVertical.value, 6);
XCTAssertEqual(view.yoga.paddingVertical.unit, YGUnitPercent);
view.yoga.paddingLeft = YGPointValue(7);
XCTAssertEqual(view.yoga.paddingLeft.value, 7);
XCTAssertEqual(view.yoga.paddingLeft.unit, YGUnitPoint);
view.yoga.paddingLeft = YGPercentValue(8);
XCTAssertEqual(view.yoga.paddingLeft.value, 8);
XCTAssertEqual(view.yoga.paddingLeft.unit, YGUnitPercent);
view.yoga.paddingRight = YGPointValue(9);
XCTAssertEqual(view.yoga.paddingRight.value, 9);
XCTAssertEqual(view.yoga.paddingRight.unit, YGUnitPoint);
view.yoga.paddingRight = YGPercentValue(10);
XCTAssertEqual(view.yoga.paddingRight.value, 10);
XCTAssertEqual(view.yoga.paddingRight.unit, YGUnitPercent);
view.yoga.paddingTop = YGPointValue(11);
XCTAssertEqual(view.yoga.paddingTop.value, 11);
XCTAssertEqual(view.yoga.paddingTop.unit, YGUnitPoint);
view.yoga.paddingTop = YGPercentValue(12);
XCTAssertEqual(view.yoga.paddingTop.value, 12);
XCTAssertEqual(view.yoga.paddingTop.unit, YGUnitPercent);
view.yoga.paddingBottom = YGPointValue(13);
XCTAssertEqual(view.yoga.paddingBottom.value, 13);
XCTAssertEqual(view.yoga.paddingBottom.unit, YGUnitPoint);
view.yoga.paddingBottom = YGPercentValue(14);
XCTAssertEqual(view.yoga.paddingBottom.value, 14);
XCTAssertEqual(view.yoga.paddingBottom.unit, YGUnitPercent);
view.yoga.paddingStart = YGPointValue(15);
XCTAssertEqual(view.yoga.paddingStart.value, 15);
XCTAssertEqual(view.yoga.paddingStart.unit, YGUnitPoint);
view.yoga.paddingStart = YGPercentValue(16);
XCTAssertEqual(view.yoga.paddingStart.value, 16);
XCTAssertEqual(view.yoga.paddingStart.unit, YGUnitPercent);
view.yoga.paddingEnd = YGPointValue(17);
XCTAssertEqual(view.yoga.paddingEnd.value, 17);
XCTAssertEqual(view.yoga.paddingEnd.unit, YGUnitPoint);
view.yoga.paddingEnd = YGPercentValue(18);
XCTAssertEqual(view.yoga.paddingEnd.value, 18);
XCTAssertEqual(view.yoga.paddingEnd.unit, YGUnitPercent);
}
- (void)testBorderWidthPropertiesWork
{
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
view.yoga.borderWidth = 1;
XCTAssertEqual(view.yoga.borderWidth, 1);
view.yoga.borderLeftWidth = 2;
XCTAssertEqual(view.yoga.borderLeftWidth, 2);
view.yoga.borderRightWidth = 3;
XCTAssertEqual(view.yoga.borderRightWidth, 3);
view.yoga.borderTopWidth = 4;
XCTAssertEqual(view.yoga.borderTopWidth, 4);
view.yoga.borderBottomWidth = 5;
XCTAssertEqual(view.yoga.borderBottomWidth, 5);
view.yoga.borderStartWidth = 6;
XCTAssertEqual(view.yoga.borderStartWidth, 6);
view.yoga.borderEndWidth = 7;
XCTAssertEqual(view.yoga.borderEndWidth, 7);
}
@end

View File

@@ -0,0 +1,6 @@
use_frameworks!
target 'YogaKitSample' do
pod 'YogaKit', :path => '../../YogaKit.podspec'
pod 'IGListKit', '~> 2.1.0'
end

View File

@@ -0,0 +1,26 @@
PODS:
- IGListKit (2.1.0):
- IGListKit/Default (= 2.1.0)
- IGListKit/Default (2.1.0):
- IGListKit/Diffing
- IGListKit/Diffing (2.1.0)
- Yoga (1.7.0)
- YogaKit (1.7.0):
- Yoga (~> 1.7)
DEPENDENCIES:
- IGListKit (~> 2.1.0)
- YogaKit (from `../../YogaKit.podspec`)
EXTERNAL SOURCES:
YogaKit:
:path: ../../YogaKit.podspec
SPEC CHECKSUMS:
IGListKit: b826c68ef7a4ae1626c09d4d3e1ea7a169e6c36e
Yoga: 2ed1d7accfef3610a67f58c0cf101a0662137f2c
YogaKit: 31576530e8fcae3175469719ec3212397403330b
PODFILE CHECKSUM: 216f8e7127767709e0e43f3711208d238fa5c404
COCOAPODS: 1.1.1

View File

@@ -0,0 +1,529 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
13687D531DF8748400E7C260 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13687D521DF8748400E7C260 /* Assets.xcassets */; };
13687D851DF87D1E00E7C260 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13687D841DF87D1E00E7C260 /* UIKit.framework */; };
13687D871DF87D2400E7C260 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13687D861DF87D2400E7C260 /* Foundation.framework */; };
15A7CB5995C9DAB1C8803834 /* Pods_YogaKitSample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C80A931E90C7F3088CB86822 /* Pods_YogaKitSample.framework */; };
40BD9F461E477A09002790A9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40BD9F451E477A09002790A9 /* AppDelegate.swift */; };
40BD9F4B1E47850C002790A9 /* BasicViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40BD9F4A1E47850C002790A9 /* BasicViewController.swift */; };
40BD9F501E479079002790A9 /* SingleLabelCollectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40BD9F4F1E479079002790A9 /* SingleLabelCollectionCell.swift */; };
40BD9F521E479173002790A9 /* LayoutInclusionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 40BD9F511E479173002790A9 /* LayoutInclusionViewController.swift */; };
638A94481E1F06D100A726AD /* ExamplesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 638A94471E1F06D100A726AD /* ExamplesViewController.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
638A94541E215CC800A726AD /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 13687D3B1DF8748300E7C260 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 13687D421DF8748300E7C260;
remoteInfo = YogaKitSample;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
13687D771DF878A000E7C260 /* yoga */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = include/yoga;
dstSubfolderSpec = 16;
files = (
);
name = yoga;
runOnlyForDeploymentPostprocessing = 0;
};
13687D7B1DF878CE00E7C260 /* YogaKit */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = include/YogaKit;
dstSubfolderSpec = 16;
files = (
);
name = YogaKit;
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
13687D431DF8748400E7C260 /* YogaKitSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = YogaKitSample.app; sourceTree = BUILT_PRODUCTS_DIR; };
13687D521DF8748400E7C260 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
13687D571DF8748400E7C260 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
13687D841DF87D1E00E7C260 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
13687D861DF87D2400E7C260 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
1D2FF4D5FCA6A8C54A4074A3 /* Pods-YogaKitSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-YogaKitSample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-YogaKitSample/Pods-YogaKitSample.debug.xcconfig"; sourceTree = "<group>"; };
40BD9F451E477A09002790A9 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
40BD9F4A1E47850C002790A9 /* BasicViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BasicViewController.swift; path = ViewControllers/BasicViewController.swift; sourceTree = "<group>"; };
40BD9F4F1E479079002790A9 /* SingleLabelCollectionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SingleLabelCollectionCell.swift; path = Views/SingleLabelCollectionCell.swift; sourceTree = "<group>"; };
40BD9F511E479173002790A9 /* LayoutInclusionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LayoutInclusionViewController.swift; path = ViewControllers/LayoutInclusionViewController.swift; sourceTree = "<group>"; };
638A94471E1F06D100A726AD /* ExamplesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExamplesViewController.swift; sourceTree = "<group>"; };
638A944F1E215CC800A726AD /* YogaKitSampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = YogaKitSampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
82F0896A88112E957EF37C7F /* Pods-YogaKitSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-YogaKitSample.release.xcconfig"; path = "Pods/Target Support Files/Pods-YogaKitSample/Pods-YogaKitSample.release.xcconfig"; sourceTree = "<group>"; };
C80A931E90C7F3088CB86822 /* Pods_YogaKitSample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_YogaKitSample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
13687D401DF8748300E7C260 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
13687D871DF87D2400E7C260 /* Foundation.framework in Frameworks */,
13687D851DF87D1E00E7C260 /* UIKit.framework in Frameworks */,
15A7CB5995C9DAB1C8803834 /* Pods_YogaKitSample.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
638A944C1E215CC800A726AD /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
13687D3A1DF8748300E7C260 = {
isa = PBXGroup;
children = (
13687D451DF8748400E7C260 /* YogaKitSample */,
13687D441DF8748400E7C260 /* Products */,
13687D831DF87D1E00E7C260 /* Frameworks */,
E1C759E3C8E84821213ECE8D /* Pods */,
);
sourceTree = "<group>";
};
13687D441DF8748400E7C260 /* Products */ = {
isa = PBXGroup;
children = (
13687D431DF8748400E7C260 /* YogaKitSample.app */,
638A944F1E215CC800A726AD /* YogaKitSampleTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
13687D451DF8748400E7C260 /* YogaKitSample */ = {
isa = PBXGroup;
children = (
40BD9F4E1E47902F002790A9 /* Views */,
40BD9F481E4784B3002790A9 /* ViewControllers */,
638A94471E1F06D100A726AD /* ExamplesViewController.swift */,
13687D521DF8748400E7C260 /* Assets.xcassets */,
13687D571DF8748400E7C260 /* Info.plist */,
40BD9F451E477A09002790A9 /* AppDelegate.swift */,
);
path = YogaKitSample;
sourceTree = "<group>";
};
13687D831DF87D1E00E7C260 /* Frameworks */ = {
isa = PBXGroup;
children = (
13687D861DF87D2400E7C260 /* Foundation.framework */,
13687D841DF87D1E00E7C260 /* UIKit.framework */,
C80A931E90C7F3088CB86822 /* Pods_YogaKitSample.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
40BD9F481E4784B3002790A9 /* ViewControllers */ = {
isa = PBXGroup;
children = (
40BD9F4A1E47850C002790A9 /* BasicViewController.swift */,
40BD9F511E479173002790A9 /* LayoutInclusionViewController.swift */,
);
name = ViewControllers;
sourceTree = "<group>";
};
40BD9F4E1E47902F002790A9 /* Views */ = {
isa = PBXGroup;
children = (
40BD9F4F1E479079002790A9 /* SingleLabelCollectionCell.swift */,
);
name = Views;
sourceTree = "<group>";
};
E1C759E3C8E84821213ECE8D /* Pods */ = {
isa = PBXGroup;
children = (
1D2FF4D5FCA6A8C54A4074A3 /* Pods-YogaKitSample.debug.xcconfig */,
82F0896A88112E957EF37C7F /* Pods-YogaKitSample.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
13687D421DF8748300E7C260 /* YogaKitSample */ = {
isa = PBXNativeTarget;
buildConfigurationList = 13687D5A1DF8748400E7C260 /* Build configuration list for PBXNativeTarget "YogaKitSample" */;
buildPhases = (
513B543F92B2E4F4D1EE1CE7 /* [CP] Check Pods Manifest.lock */,
13687D771DF878A000E7C260 /* yoga */,
13687D7B1DF878CE00E7C260 /* YogaKit */,
13687D3F1DF8748300E7C260 /* Sources */,
13687D401DF8748300E7C260 /* Frameworks */,
13687D411DF8748300E7C260 /* Resources */,
FA2FB9DD6471BDD3FBCE503B /* [CP] Embed Pods Frameworks */,
6E01EB987F1564F3D71EBE5A /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = YogaKitSample;
productName = YogaKitSample;
productReference = 13687D431DF8748400E7C260 /* YogaKitSample.app */;
productType = "com.apple.product-type.application";
};
638A944E1E215CC800A726AD /* YogaKitSampleTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 638A94561E215CC800A726AD /* Build configuration list for PBXNativeTarget "YogaKitSampleTests" */;
buildPhases = (
638A944B1E215CC800A726AD /* Sources */,
638A944C1E215CC800A726AD /* Frameworks */,
638A944D1E215CC800A726AD /* Resources */,
);
buildRules = (
);
dependencies = (
638A94551E215CC800A726AD /* PBXTargetDependency */,
);
name = YogaKitSampleTests;
productName = YogaKitSampleTests;
productReference = 638A944F1E215CC800A726AD /* YogaKitSampleTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
13687D3B1DF8748300E7C260 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0820;
ORGANIZATIONNAME = facebook;
TargetAttributes = {
13687D421DF8748300E7C260 = {
CreatedOnToolsVersion = 8.1;
LastSwiftMigration = 0820;
ProvisioningStyle = Automatic;
};
638A944E1E215CC800A726AD = {
CreatedOnToolsVersion = 8.2.1;
ProvisioningStyle = Automatic;
TestTargetID = 13687D421DF8748300E7C260;
};
};
};
buildConfigurationList = 13687D3E1DF8748300E7C260 /* Build configuration list for PBXProject "YogaKitSample" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 13687D3A1DF8748300E7C260;
productRefGroup = 13687D441DF8748400E7C260 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
13687D421DF8748300E7C260 /* YogaKitSample */,
638A944E1E215CC800A726AD /* YogaKitSampleTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
13687D411DF8748300E7C260 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
13687D531DF8748400E7C260 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
638A944D1E215CC800A726AD /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
513B543F92B2E4F4D1EE1CE7 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
6E01EB987F1564F3D71EBE5A /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-YogaKitSample/Pods-YogaKitSample-resources.sh\"\n";
showEnvVarsInLog = 0;
};
FA2FB9DD6471BDD3FBCE503B /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-YogaKitSample/Pods-YogaKitSample-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
13687D3F1DF8748300E7C260 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
40BD9F501E479079002790A9 /* SingleLabelCollectionCell.swift in Sources */,
40BD9F521E479173002790A9 /* LayoutInclusionViewController.swift in Sources */,
638A94481E1F06D100A726AD /* ExamplesViewController.swift in Sources */,
40BD9F4B1E47850C002790A9 /* BasicViewController.swift in Sources */,
40BD9F461E477A09002790A9 /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
638A944B1E215CC800A726AD /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
638A94551E215CC800A726AD /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 13687D421DF8748300E7C260 /* YogaKitSample */;
targetProxy = 638A94541E215CC800A726AD /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
13687D581DF8748400E7C260 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.1;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
13687D591DF8748400E7C260 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.1;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
13687D5B1DF8748400E7C260 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 1D2FF4D5FCA6A8C54A4074A3 /* Pods-YogaKitSample.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
INFOPLIST_FILE = YogaKitSample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKitSample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_INSTALL_OBJC_HEADER = NO;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
};
name = Debug;
};
13687D5C1DF8748400E7C260 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 82F0896A88112E957EF37C7F /* Pods-YogaKitSample.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
INFOPLIST_FILE = YogaKitSample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKitSample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_INSTALL_OBJC_HEADER = NO;
SWIFT_VERSION = 3.0;
};
name = Release;
};
638A94571E215CC800A726AD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
INFOPLIST_FILE = YogaKitSampleTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKitSampleTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/YogaKitSample.app/YogaKitSample";
};
name = Debug;
};
638A94581E215CC800A726AD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
INFOPLIST_FILE = YogaKitSampleTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKitSampleTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/YogaKitSample.app/YogaKitSample";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
13687D3E1DF8748300E7C260 /* Build configuration list for PBXProject "YogaKitSample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
13687D581DF8748400E7C260 /* Debug */,
13687D591DF8748400E7C260 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
13687D5A1DF8748400E7C260 /* Build configuration list for PBXNativeTarget "YogaKitSample" */ = {
isa = XCConfigurationList;
buildConfigurations = (
13687D5B1DF8748400E7C260 /* Debug */,
13687D5C1DF8748400E7C260 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
638A94561E215CC800A726AD /* Build configuration list for PBXNativeTarget "YogaKitSampleTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
638A94571E215CC800A726AD /* Debug */,
638A94581E215CC800A726AD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 13687D3B1DF8748300E7C260 /* Project object */;
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:YogaKitSample.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0820"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13687D421DF8748300E7C260"
BuildableName = "YogaKitSample.app"
BlueprintName = "YogaKitSample"
ReferencedContainer = "container:YogaKitSample.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "638A944E1E215CC800A726AD"
BuildableName = "YogaKitSampleTests.xctest"
BlueprintName = "YogaKitSampleTests"
ReferencedContainer = "container:YogaKitSample.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13687D421DF8748300E7C260"
BuildableName = "YogaKitSample.app"
BlueprintName = "YogaKitSample"
ReferencedContainer = "container:YogaKitSample.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13687D421DF8748300E7C260"
BuildableName = "YogaKitSample.app"
BlueprintName = "YogaKitSample"
ReferencedContainer = "container:YogaKitSample.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13687D421DF8748300E7C260"
BuildableName = "YogaKitSample.app"
BlueprintName = "YogaKitSample"
ReferencedContainer = "container:YogaKitSample.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:YogaKitSample.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,27 @@
/**
* Copyright 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE-examples file in the root directory of this source tree.
*/
import Foundation
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func applicationDidFinishLaunching(_ application: UIApplication) {
self.window = UIWindow(frame: UIScreen.main.bounds)
if let window = self.window {
let navigationController = UINavigationController(rootViewController: ExamplesViewController())
navigationController.navigationBar.isTranslucent = false
window.rootViewController = navigationController
window.backgroundColor = .white
window.makeKeyAndVisible()
}
}
}

View File

@@ -0,0 +1,74 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Yoga-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Yoga-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Yoga-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Yoga-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Yoga-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Yoga-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Yoga-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "57x57",
"idiom" : "iphone",
"filename" : "Yoga-57x57@1x.png",
"scale" : "1x"
},
{
"size" : "57x57",
"idiom" : "iphone",
"filename" : "Yoga-57x57@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Yoga-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Yoga-60x60@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

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

View File

@@ -0,0 +1,100 @@
/**
* Copyright 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE-examples file in the root directory of this source tree.
*/
import UIKit
import IGListKit
private final class ExampleModel {
let title: String
let controllerClass: UIViewController.Type
init(title: String, controllerClass: UIViewController.Type) {
self.title = title
self.controllerClass = controllerClass
}
}
extension ExampleModel: IGListDiffable {
fileprivate func diffIdentifier() -> NSObjectProtocol {
return title as NSString
}
fileprivate func isEqual(toDiffableObject object: IGListDiffable?) -> Bool {
guard let otherObj = object as? ExampleModel else { return false }
return (title == otherObj.title) &&
(controllerClass == otherObj.controllerClass)
}
}
final class ExamplesViewController: UIViewController, IGListAdapterDataSource, IGListSingleSectionControllerDelegate {
private lazy var adapter: IGListAdapter = {
return IGListAdapter(updater: IGListAdapterUpdater(), viewController: self, workingRangeSize: 0)
}()
private let collectionView = IGListCollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
// Update this to array to create more examples.
private let models: [ExampleModel] = [ExampleModel(title: "Basic Layout", controllerClass: BasicViewController.self),
ExampleModel(title: "Exclude Views in Layout", controllerClass: LayoutInclusionViewController.self)]
//MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
title = "Examples"
view.addSubview(collectionView)
adapter.collectionView = collectionView
adapter.dataSource = self
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView.frame = view.bounds
}
//MARK: IGListAdapterDataSource
func objects(for listAdapter: IGListAdapter) -> [IGListDiffable] {
return models as [IGListDiffable]
}
func listAdapter(_ listAdapter: IGListAdapter, sectionControllerFor object: Any) -> IGListSectionController {
let sizeBlock: IGListSingleSectionCellSizeBlock = { (model, context) in
return CGSize(width: (context?.containerSize.width)!, height: 75.0)
}
let configureBlock: IGListSingleSectionCellConfigureBlock = { (model, cell) in
guard let m = model as? ExampleModel, let c = cell as? SingleLabelCollectionCell else {
return
}
c.label.text = m.title
}
let sectionController = IGListSingleSectionController(cellClass: SingleLabelCollectionCell.self,
configureBlock: configureBlock,
sizeBlock: sizeBlock)
sectionController.selectionDelegate = self
return sectionController
}
func emptyView(for listAdapter: IGListAdapter) -> UIView? { return nil }
//MARK: IGListSingleSectionControllerDelegate
func didSelect(_ sectionController: IGListSingleSectionController) {
let section = adapter.section(for: sectionController)
let model = models[section]
let controller = model.controllerClass.init()
controller.title = model.title
self.navigationController?.pushViewController(controller, animated: true)
}
}

View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string></string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,71 @@
/**
* Copyright 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE-examples file in the root directory of this source tree.
*/
import UIKit
import IGListKit
import YogaKit
struct DemoItem {
let name: String
root.backgroundColor = .red
root.yoga.isEnabled = true
root.yoga.width = YGValue(self.view.bounds.size.width)
root.yoga.height = YGValue(self.view.bounds.size.height)
root.yoga.alignItems = .center
}
final class SwiftViewController: UIViewController, IGListAdapterDataSource {
lazy var adapter: IGListAdapter = {
return IGListAdapter(updater: IGListAdapterUpdater(), viewController: self, workingRangeSize: 0)
}()
let collectionView = IGListCollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
//MARK: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
title = "YogaKit Examples"
view.addSubview(collectionView)
adapter.collectionView = collectionView
adapter.dataSource = self
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
collectionView.frame = view.bounds
}
//MARK: IGListAdapterDataSource
func objects(for listAdapter: IGListAdapter) -> [IGListDiffable] {
return ["Dustin" as IGListDiffable, "Ryan" as IGListDiffable]
}
func listAdapter(_ listAdapter: IGListAdapter, sectionControllerFor object: Any) -> IGListSectionController {
let sizeBlock: IGListSingleSectionCellSizeBlock = { (model, context) in
return CGSize(width: (context?.containerSize.width)!, height: 100.0)
}
let configureBlock: IGListSingleSectionCellConfigureBlock = { (model, cell) in
guard let m = model as? String else {
return
}
cell.backgroundColor = (m == "Dustin") ? .blue : .red
}
return IGListSingleSectionController(cellClass: UICollectionViewCell.self,
configureBlock: configureBlock,
sizeBlock: sizeBlock)
}
func emptyView(for listAdapter: IGListAdapter) -> UIView? {
return nil
}
}

View File

@@ -0,0 +1,56 @@
/**
* Copyright 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE-examples file in the root directory of this source tree.
*/
#import "ViewController.h"
#import <YogaKit/UIView+Yoga.h>
@implementation ViewController
- (void)viewDidLoad
{
UIView *root = self.view;
root.backgroundColor = [UIColor redColor];
root.yoga.isEnabled = YES;
root.yoga.width = YGPointValue(self.view.bounds.size.width);
root.yoga.height = YGPointValue(self.view.bounds.size.height);
root.yoga.alignItems = YGAlignCenter;
root.yoga.justifyContent = YGJustifyCenter;
UIView *child1 = [UIView new];
child1.backgroundColor = [UIColor blueColor];
child1.yoga.isEnabled = YES;
child1.yoga.width = YGPointValue(100);
child1.yoga.height = YGPointValue(100);
UIView *child2 = [UIView new];
child2.backgroundColor = [UIColor greenColor];
child2.frame = (CGRect) {
.size = {
.width = 200,
.height = 100,
}
};
UIView *child3 = [UIView new];
child3.backgroundColor = [UIColor yellowColor];
child3.frame = (CGRect) {
.size = {
.width = 100,
.height = 100,
}
};
[child2 addSubview:child3];
[root addSubview:child1];
[root addSubview:child2];
[root.yoga applyLayoutPreservingOrigin:NO];
}
@end

View File

@@ -0,0 +1,54 @@
/**
* Copyright 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE-examples file in the root directory of this source tree.
*/
import UIKit
import YogaKit
final class BasicViewController: UIViewController {
override func viewDidLoad() {
let containerSize = self.view.bounds.size
let root = self.view!
root.backgroundColor = .white
root.configureLayout { (layout) in
layout.isEnabled = true
layout.width = YGValue(containerSize.width)
layout.height = YGValue(containerSize.height)
layout.alignItems = .center
layout.justifyContent = .center
}
let child1 = UIView()
child1.backgroundColor = .blue
child1.configureLayout { (layout) in
layout.isEnabled = true
layout.width = 100
layout.height = 10
layout.marginBottom = 25
}
root.addSubview(child1)
let child2 = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
child2.backgroundColor = .green
child2.configureLayout { (layout) in
layout.isEnabled = true
layout.alignSelf = .flexEnd
}
root.addSubview(child2)
let child3 = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
child3.backgroundColor = .yellow
child3.configureLayout { (layout) in
layout.isEnabled = true
layout.alignSelf = .flexStart
}
root.addSubview(child3)
root.yoga.applyLayout(preservingOrigin: true)
}
}

View File

@@ -0,0 +1,80 @@
/**
* Copyright 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE-examples file in the root directory of this source tree.
*/
import UIKit
import YogaKit
final class LayoutInclusionViewController: UIViewController {
private let button: UIButton = UIButton(type: .system)
private let disappearingView: UIView = UIView(frame: .zero)
private let contentView: UIView = UIView(frame: .zero)
override func viewDidLoad() {
let root = self.view!
root.backgroundColor = .white
root.configureLayout { (layout) in
layout.isEnabled = true
layout.flexDirection = .column
layout.justifyContent = .spaceAround
}
contentView.backgroundColor = .clear
contentView.layer.borderColor = UIColor.lightGray.cgColor
contentView.layer.borderWidth = 1.0
contentView.configureLayout { (layout) in
layout.isEnabled = true
layout.height = 300
layout.width = YGValue(self.view.bounds.size.width)
layout.flexDirection = .row
layout.justifyContent = .center
layout.paddingHorizontal = 25
}
self.view.addSubview(contentView)
let redView = UIView(frame: .zero)
redView.backgroundColor = .red
redView.configureLayout { (layout) in
layout.isEnabled = true
layout.flexGrow = 1
layout.flexShrink = 1
}
contentView.addSubview(redView)
disappearingView.backgroundColor = .blue
disappearingView.configureLayout { (layout) in
layout.isEnabled = true
layout.flexGrow = 1
}
contentView.addSubview(disappearingView)
button.setTitle("Add Blue View", for: UIControlState.selected)
button.setTitle("Remove Blue View", for: UIControlState.normal)
button.addTarget(self, action: #selector(buttonWasTapped), for: UIControlEvents.touchUpInside)
button.configureLayout { (layout) in
layout.isEnabled = true
layout.height = 300
layout.width = 300
layout.alignSelf = .center
}
root.addSubview(button)
root.yoga.applyLayout(preservingOrigin: false)
}
// MARK - UIButton Action
func buttonWasTapped() {
button.isSelected = !button.isSelected
button.isUserInteractionEnabled = false
disappearingView.yoga.isIncludedInLayout = !disappearingView.yoga.isIncludedInLayout
disappearingView.isHidden = !disappearingView.isHidden
contentView.yoga.applyLayout(preservingOrigin: true)
button.isUserInteractionEnabled = true
}
}

View File

@@ -0,0 +1,49 @@
/**
* Copyright 2014-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE-examples file in the root directory of this source tree.
*/
import UIKit
import YogaKit
final class SingleLabelCollectionCell: UICollectionViewCell {
let label: UILabel = UILabel(frame: .zero)
override init(frame: CGRect) {
super.init(frame: frame)
contentView.configureLayout { (layout) in
layout.isEnabled = true
layout.flexDirection = .column
layout.justifyContent = .flexEnd
}
label.textAlignment = .center
label.numberOfLines = 1
label.yoga.isIncludedInLayout = false
contentView.addSubview(label)
let border = UIView(frame: .zero)
border.backgroundColor = .lightGray
border.configureLayout { (layout) in
layout.isEnabled = true
layout.height = 0.5
layout.marginHorizontal = 25
}
contentView.addSubview(border)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
contentView.yoga.applyLayout(preservingOrigin: false)
label.frame = contentView.bounds
}
}

30
android/BUCK Normal file
View File

@@ -0,0 +1,30 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
load("//tools/build_defs/oss:yoga_defs.bzl", "ANDROID_JAVA_TARGET", "ANDROID_RES_TARGET", "INFER_ANNOTATIONS_TARGET", "JAVA_TARGET", "PROGRUARD_ANNOTATIONS_TARGET", "yoga_android_aar", "yoga_android_resource")
yoga_android_aar(
name = "android",
manifest_skeleton = "src/main/AndroidManifest.xml",
visibility = [
"PUBLIC",
],
deps = [
ANDROID_JAVA_TARGET,
ANDROID_RES_TARGET,
INFER_ANNOTATIONS_TARGET,
JAVA_TARGET,
PROGRUARD_ANNOTATIONS_TARGET,
],
)
yoga_android_resource(
name = "res",
package = "com.facebook.yoga.android",
res = "src/main/res",
visibility = [
"PUBLIC",
],
)

21
android/README.md Normal file
View File

@@ -0,0 +1,21 @@
# YogaLayout [![Platform](https://img.shields.io/badge/platforms-Android-orange.svg)](https://facebook.github.io/yoga/docs/api/android/) [![Languages](https://img.shields.io/badge/languages-Java-orange.svg)](https://facebook.github.io/yoga/docs/api/android/) [![Download](https://img.shields.io/bintray/v/facebook/maven/com.facebook.yoga.android:yoga-layout.svg)](https://bintray.com/facebook/maven/com.facebook.yoga.android%3Ayoga-layout/_latestVersion)
## Installation
YogaLayout is available via jcenter:
compile 'com.facebook.yoga.android:yoga-layout:1.2.0'
## Getting Started
Check out the docs [here](https://facebook.github.io/yoga/docs/api/android/).
We also have a sample project. To try it, clone the repo and run (with a device attached)
buck install -r android/sample
## Contributing
We welcome all pull-requests! At Facebook we sync the open source version of YogaKit daily, so we're always testing the latest changes.
See the CONTRIBUTING file for how to help out.

52
android/build.gradle Normal file
View File

@@ -0,0 +1,52 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
apply plugin: 'com.jfrog.bintray'
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'maven-publish'
version = VERSION_NAME
group = GROUP
android {
compileSdkVersion rootProject.compileSdkVersion
buildToolsVersion rootProject.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.minSdkVersion
targetSdkVersion rootProject.targetSdkVersion
}
compileOptions {
targetCompatibility rootProject.targetCompatibilityVersion
sourceCompatibility rootProject.sourceCompatibilityVersion
}
}
dependencies {
api project(':yoga')
}
task sourcesJar(type: Jar) {
classifier = 'source'
from android.sourceSets.main.java.srcDirs
}
task javadoc(type: Javadoc) {
failOnError false
source = android.sourceSets.main.java.sourceFiles
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
classpath += configurations.compile
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
apply from: rootProject.file('gradle/release.gradle')

12
android/gradle.properties Normal file
View File

@@ -0,0 +1,12 @@
#
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the LICENSE
# file in the root directory of this source tree.
#
GROUP=com.facebook.yoga.android
POM_NAME=YogaLayout
POM_DESCRIPTION=YogaLayout
POM_ARTIFACT_ID=yoga-layout
POM_PACKAGING=aar

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2014-present, Facebook, Inc.
All rights reserved.
This source code is licensed under the license found in the
LICENSE-examples file in the root directory of this source tree.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.facebook.samples.yoga"
android:versionCode="1"
android:versionName="1.0"
>
<variable name="applicationId" value="com.facebook.yoga"/>
<variable name="app_label" value="Yoga Sample App"/>
<uses-sdk
android:minSdkVersion="15"
android:targetSdkVersion="19"
/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
android:allowBackup="false"
android:theme="@style/NoTitleBarWhiteBG"
android:supportsRtl="true"
>
<activity
android:name=".MainActivity"
android:exported="true"
>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".BenchmarkActivity"
android:exported="false"
/>
</application>
</manifest>

36
android/sample/BUCK Normal file
View File

@@ -0,0 +1,36 @@
# Copyright 2014-present, Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the license found in the
# LICENSE-examples file in the root directory of this source tree.
load("//tools/build_defs:fb_native_wrapper.bzl", "fb_native")
load("//tools/build_defs/oss:yoga_defs.bzl", "ANDROID_RES_TARGET", "ANDROID_SAMPLE_JAVA_TARGET", "ANDROID_SAMPLE_RES_TARGET", "yoga_android_binary", "yoga_android_resource")
yoga_android_binary(
name = "sample",
keystore = ":debug_keystore",
manifest = "AndroidManifest.xml",
deps = [
ANDROID_SAMPLE_JAVA_TARGET,
ANDROID_SAMPLE_RES_TARGET,
],
)
yoga_android_resource(
name = "res",
package = "com.facebook.samples.yoga",
res = "res",
visibility = [
"PUBLIC",
],
deps = [
ANDROID_RES_TARGET,
],
)
fb_native.keystore(
name = "debug_keystore",
properties = "debug.keystore.properties",
store = "debug.keystore",
)

Binary file not shown.

View File

@@ -0,0 +1,3 @@
key.alias=androiddebugkey
key.store.password=android
key.alias.password=android

View File

@@ -0,0 +1,21 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the license found in the
# LICENSE-examples file in the root directory of this source tree.
load("//tools/build_defs/oss:yoga_defs.bzl", "ANDROID_JAVA_TARGET", "ANDROID_SAMPLE_RES_TARGET", "ANDROID_SUPPORT_TARGET", "APPCOMPAT_TARGET", "SOLOADER_TARGET", "yoga_android_library")
yoga_android_library(
name = "yoga",
srcs = glob(["**/*.java"]),
visibility = [
"PUBLIC",
],
deps = [
ANDROID_JAVA_TARGET,
ANDROID_SAMPLE_RES_TARGET,
ANDROID_SUPPORT_TARGET,
APPCOMPAT_TARGET,
SOLOADER_TARGET,
],
)

View File

@@ -0,0 +1,117 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
package com.facebook.samples.yoga;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.Menu;
import android.support.v7.app.ActionBar;
import com.facebook.samples.yoga.R;
import com.facebook.yoga.android.YogaViewLayoutFactory;
public class BenchmarkActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
LayoutInflater.from(this).setFactory(YogaViewLayoutFactory.getInstance());
super.onCreate(savedInstanceState);
setContentView(R.layout.benchmark_select_layout);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setAdapter(new PagerAdapter(getSupportFragmentManager()));
final ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.TabListener tabListener = new ActionBar.TabListener() {
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setCurrentItem(tab.getPosition());
}
public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
}
};
actionBar.addTab(
actionBar.newTab()
.setText("Inflate")
.setTabListener(tabListener));
actionBar.addTab(
actionBar.newTab()
.setText("Measure")
.setTabListener(tabListener));
actionBar.addTab(
actionBar.newTab()
.setText("Layout")
.setTabListener(tabListener));
viewPager.setOnPageChangeListener(
new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
// When swiping between pages, select the
// corresponding tab.
actionBar.setSelectedNavigationItem(position);
}
});
viewPager.setOffscreenPageLimit(3);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.action_bar_benchmark, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// There is only one option
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
this.finish();
return true;
}
public static class PagerAdapter extends FragmentPagerAdapter {
public PagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int i) {
switch (i) {
case 0:
return new BenchmarkInflate();
case 1:
return new BenchmarkMeasure();
default:
return new BenchmarkLayout();
}
}
@Override
public int getCount() {
return 3;
}
}
}

View File

@@ -0,0 +1,197 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
package com.facebook.samples.yoga;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.lang.Math;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.text.DateFormat;
import java.util.Date;
import android.content.Context;
import android.util.Log;
import android.os.Environment;
import static java.util.Collections.sort;
public class BenchmarkAggregator {
private final int GRAPH_WIDTH = 30;
private final int GRAPH_HEIGHT = 6;
private List<Long> times;
private boolean tracing;
private long lastTraceStart;
private boolean statsFresh;
private long mean;
private long variance;
private long stddev;
private long min;
private long max;
private long p10;
private long p50;
private long p90;
private String name;
public BenchmarkAggregator(String name) {
times = new ArrayList<>();
tracing = false;
this.name = name;
}
public void startTrace() {
if (tracing) {
throw new RuntimeException("Cannot start trace while running previous one");
}
tracing = true;
lastTraceStart = System.nanoTime();
}
public void endTrace() {
if (!tracing) {
throw new RuntimeException("Cannot stop trace if none are running!");
}
times.add(System.nanoTime() - lastTraceStart);
tracing = false;
statsFresh = false;
}
private void computeStats() {
if (statsFresh) {
return;
}
sort(times);
min = Long.MAX_VALUE;
max = -1;
mean = 0;
for (long f: times) {
mean += f;
if (f < min) {
min = f;
}
if (f > max) {
max = f;
}
}
mean /= times.size();
variance = 0;
for (long f: times) {
variance += (f-mean)*(f-mean);
}
variance /= times.size();
stddev = (long) Math.sqrt((double) variance);
p10 = times.get(times.size()*10/100);
p50 = times.get(times.size()*50/100);
p90 = times.get(times.size()*90/100);
statsFresh = true;
}
public String toString() {
computeStats();
return String.format(
"%s:\n" +
"| %d samples\n" +
"| Mean %.3f\u00B1%.3fms\n" + // plusminus
"| Min %.3fms ; Max %.3fms\n" +
"| p10 %.3fms ; p50 %.3fms ; p90 %.3fms\n" +
"%s",
name,
times.size(),
mean/10e6,
stddev/10e6,
min/10e6,
max/10e6,
p10/10e6,
p50/10e6,
p90/10e6,
makeGraph());
}
private String makeGraph() {
char canvas[][] = new char[GRAPH_HEIGHT][GRAPH_WIDTH];
for (int i = 0; i < GRAPH_HEIGHT; i++)
for (int j = 0; j < GRAPH_WIDTH; j++)
canvas[i][j] = ' ';
long bucketSize = (p90 - p10) / GRAPH_WIDTH+1;
int bucketCount[] = new int[GRAPH_WIDTH];
for (long time : times) {
if (time<p90 && time>p10) {
bucketCount[(int) ((time - p10) / bucketSize)]++;
}
}
int maxBucket = 0;
for (int i = 0; i < GRAPH_WIDTH; i++)
if (bucketCount[i] > maxBucket) {
maxBucket = bucketCount[i];
}
for (int i = 0; i < GRAPH_HEIGHT; i++)
for (int j = 0; j < GRAPH_WIDTH; j++)
if (i < bucketCount[j] * GRAPH_HEIGHT / maxBucket) {
canvas[i][j] = 'Z';
}
String graph = new String();
for (int i = 0; i < GRAPH_HEIGHT; i++)
{
int percentage = 100 * (GRAPH_HEIGHT - i - 1) * maxBucket / (times.size() * GRAPH_HEIGHT);
graph += String.format("| %2d%% ", percentage);
for (int j = 0; j < GRAPH_WIDTH; j++)
graph += canvas[GRAPH_HEIGHT-1-i][j];
graph += '\n';
}
graph += "| p10";
for (int i = 0; i < GRAPH_WIDTH-6; i++)
graph += " ";
graph += "p90\n";
return graph;
}
/**
* Dumps the collected times to a file on the device. This allows us to grab the raw data
* and perform more in-depth analysis.
*/
public void dump(Context context) {
String state = Environment.getExternalStorageState();
if (!Environment.MEDIA_MOUNTED.equals(state)) {
Log.e("YogaLayoutBenchmark","No external file storage");
return;
}
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
String filename = format.format(new Date()) + "_" + name.replace(' ','_');
File file = new File(context.getExternalFilesDir(
Environment.DIRECTORY_DOCUMENTS), filename);
try {
PrintWriter printWriter = new PrintWriter(file);
for (long l : times) {
printWriter.println(l);
}
printWriter.close();
Log.i("YogaLayoutBenchmark","Benchmark data saved in "+file.getPath());
} catch (java.io.IOException e) {
Log.e("YogaLayoutBenchmark", "Could not save benchmark data", e);
}
}
}

View File

@@ -0,0 +1,114 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
package com.facebook.samples.yoga;
import java.util.Random;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.ArrayAdapter;
import android.widget.AdapterView;
import com.facebook.samples.yoga.R;
import com.facebook.yoga.android.YogaLayout;
public class BenchmarkFragment extends Fragment implements AdapterView.OnItemSelectedListener {
private LayoutInflater mInflater;
protected com.facebook.yoga.android.YogaLayout rootLayout;
protected int yogaLayout;
protected int linearLayout;
static final Random random = new Random();
static void randomizeText(View root) {
if (root instanceof TextView) {
((TextView) root).setText("" + random.nextInt(1000));
((TextView) root).setTextSize(10 + random.nextInt(20));
ViewParent parent = root.getParent();
if (parent instanceof YogaLayout) {
((YogaLayout) parent).invalidate(root);
}
} else if (root instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) root).getChildCount(); i++) {
randomizeText(((ViewGroup) root).getChildAt(i));
}
}
}
public BenchmarkFragment() {
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(
LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
mInflater = inflater;
rootLayout = (YogaLayout) inflater.inflate(
R.layout.benchmark_fragment,
container,
false);
Spinner benchmarkSelect = (Spinner) rootLayout.findViewById(R.id.benchmarkSelect);
String[] items = new String[]{"Basic", "Typical", "Nested"};
ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_spinner_dropdown_item, items);
benchmarkSelect.setAdapter(adapter);
benchmarkSelect.setOnItemSelectedListener(this);
return rootLayout;
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
switch (pos) {
case 0:
yogaLayout = R.layout.benchmark_layout_1;
linearLayout = R.layout.benchmark_layout_1_linear;
break;
case 1:
yogaLayout = R.layout.benchmark_layout_2;
linearLayout = R.layout.benchmark_layout_2_linear;
break;
case 2:
default:
yogaLayout = R.layout.benchmark_layout_3;
linearLayout = R.layout.benchmark_layout_3_linear;
break;
}
updatePreview();
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
yogaLayout = R.layout.benchmark_layout_1;
linearLayout = R.layout.benchmark_layout_1_linear;
updatePreview();
}
private void updatePreview() {
LinearLayout previewLayout = (LinearLayout) rootLayout.findViewById(R.id.preview);
View v = mInflater.inflate(yogaLayout, rootLayout, false);
v.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT));
previewLayout.removeAllViews();
previewLayout.addView(v);
}
}

View File

@@ -0,0 +1,69 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
package com.facebook.samples.yoga;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import android.widget.Button;
import android.view.ViewGroup;
import android.util.Log;
import com.facebook.samples.yoga.R;
public class BenchmarkInflate extends BenchmarkFragment {
@Override
public View onCreateView(
LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
Button b = (Button) rootLayout.findViewById(R.id.btn);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startBenchmark();
}
});
return rootLayout;
}
protected void startBenchmark() {
LayoutInflater inflater = LayoutInflater.from(getActivity());
TextView textView = (TextView) rootLayout.findViewById(R.id.text);
final int ITERATIONS = 500;
inflater.inflate(yogaLayout, null);
inflater.inflate(linearLayout, null);
BenchmarkAggregator yogaInflationAggregator = new BenchmarkAggregator("Yoga Inflate");
BenchmarkAggregator linearInflationAggregator = new BenchmarkAggregator("Linear Inflate");
for (int i = 0; i < ITERATIONS; i++) {
yogaInflationAggregator.startTrace();
inflater.inflate(yogaLayout, null);
yogaInflationAggregator.endTrace();
linearInflationAggregator.startTrace();
inflater.inflate(linearLayout, null);
linearInflationAggregator.endTrace();
}
textView.setText(
yogaInflationAggregator.toString()+
"\n"+
linearInflationAggregator.toString());
Log.i(
"YogaLayoutBenchmark",
yogaInflationAggregator.toString()+
"\n"+
linearInflationAggregator.toString());
rootLayout.invalidate();
}
}

View File

@@ -0,0 +1,78 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
package com.facebook.samples.yoga;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import com.facebook.samples.yoga.R;
import java.util.Random;
public class BenchmarkLayout extends BenchmarkFragment {
@Override
public View onCreateView(
LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
Button b = (Button) rootLayout.findViewById(R.id.btn);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startBenchmark();
}
});
return rootLayout;
}
protected void startBenchmark() {
LayoutInflater inflater = LayoutInflater.from(getActivity());
TextView textView = (TextView) rootLayout.findViewById(R.id.text);
Random random = new Random();
final int ITERATIONS = 500;
BenchmarkAggregator yogaInflationAggregator = new BenchmarkAggregator("Yoga Layout");
BenchmarkAggregator linearInflationAggregator = new BenchmarkAggregator("Linear Layout");
View yogaView = inflater.inflate(yogaLayout, null);
View linearView = inflater.inflate(linearLayout, null);
for (int i = 0; i < ITERATIONS; i++) {
randomizeText(yogaView);
randomizeText(linearView);
yogaView.measure(
View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY));
linearView.measure(
View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY));
yogaInflationAggregator.startTrace();
yogaView.layout(0, 0, yogaView.getMeasuredWidth(), yogaView.getMeasuredHeight());
yogaInflationAggregator.endTrace();
linearInflationAggregator.startTrace();
linearView.layout(0, 0, linearView.getMeasuredWidth(), linearView.getMeasuredHeight());
linearInflationAggregator.endTrace();
}
textView.setText(
yogaInflationAggregator.toString()+
"\n"+
linearInflationAggregator.toString());
Log.i(
"YogaLayoutBenchmark",
yogaInflationAggregator.toString()+
"\n"+
linearInflationAggregator.toString());
}
}

View File

@@ -0,0 +1,79 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
package com.facebook.samples.yoga;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import com.facebook.samples.yoga.R;
import java.util.Random;
public class BenchmarkMeasure extends BenchmarkFragment {
@Override
public View onCreateView(
LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
Button b = (Button) rootLayout.findViewById(R.id.btn);
b.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startBenchmark();
}
});
return rootLayout;
}
protected void startBenchmark() {
LayoutInflater inflater = LayoutInflater.from(getActivity());
TextView textView = (TextView) rootLayout.findViewById(R.id.text);
Random random = new Random();
final int ITERATIONS = 500;
BenchmarkAggregator yogaMeasureAggregator = new BenchmarkAggregator("Yoga Measure");
BenchmarkAggregator linearMeasureAggregator = new BenchmarkAggregator("Linear Measure");
View yogaView = inflater.inflate(yogaLayout, null);
View linearView = inflater.inflate(linearLayout, null);
for (int i = 0; i < ITERATIONS; i++) {
randomizeText(yogaView);
randomizeText(linearView);
yogaMeasureAggregator.startTrace();
yogaView.measure(
View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY));
yogaMeasureAggregator.endTrace();
linearMeasureAggregator.startTrace();
linearView.measure(
View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY));
linearMeasureAggregator.endTrace();
}
textView.setText(
yogaMeasureAggregator.toString()+
"\n"+
linearMeasureAggregator.toString());
Log.i(
"YogaLayoutBenchmark",
yogaMeasureAggregator.toString()+
"\n"+
linearMeasureAggregator.toString());
yogaMeasureAggregator.dump(getActivity());
linearMeasureAggregator.dump(getActivity());
}
}

View File

@@ -0,0 +1,52 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the LICENSE
* file in the root directory of this source tree.
*/
package com.facebook.samples.yoga;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.Menu;
import com.facebook.samples.yoga.R;
import com.facebook.soloader.SoLoader;
import com.facebook.yoga.android.YogaViewLayoutFactory;
/**
* An activity to show off Yoga in Android. This activity shows a simple layout (defined in
* {@code main_layout.xml}) that shows off the awesome functionality of the Yoga layout engine
* as well as some optimisations on layout systems that it facilitates.
*/
public class MainActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
LayoutInflater.from(this).setFactory(YogaViewLayoutFactory.getInstance());
super.onCreate(savedInstanceState);
SoLoader.init(this, false);
setContentView(R.layout.main_layout);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.action_bar_home, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// There is only one option
Intent intent = new Intent(this, BenchmarkActivity.class);
startActivity(intent);
this.finish();
return true;
}
}

Some files were not shown because too many files have changed in this diff Show More