Compare commits
362 Commits
v2016.11.28.00
...
1.5.0
Author | SHA1 | Date | |
---|---|---|---|
|
2c91e1e7d2 | ||
|
c3982b6c1e | ||
|
ae33c6c19c | ||
|
bcd68b997f | ||
|
fcfa1b9f01 | ||
|
d9a0822517 | ||
|
097e99b699 | ||
|
ff7bec703b | ||
|
c7ab004922 | ||
|
91230ae177 | ||
|
40eba60cf5 | ||
|
fb4cfed20d | ||
|
d3a9a84ac4 | ||
|
accad5366f | ||
|
8eca67e257 | ||
|
40e1bf6ce3 | ||
|
7b89a1dd48 | ||
|
203577724e | ||
|
e3dbef7cbd | ||
|
0ee3303791 | ||
|
83fddd8af6 | ||
|
77c05b5ff6 | ||
|
7c324f058c | ||
|
3db38f2a80 | ||
|
f6b17183c5 | ||
|
8f9d7e243e | ||
|
fde4db9383 | ||
|
3178e3bf15 | ||
|
cdfd05c742 | ||
|
76f6a54327 | ||
|
c91e4b3566 | ||
|
e24561bcef | ||
|
363e941867 | ||
|
3fb2c1888c | ||
|
aa5b296ac7 | ||
|
f2b5d0fef7 | ||
|
0684795a89 | ||
|
2ffc23f400 | ||
|
dc4d16401f | ||
|
849de89a58 | ||
|
f8a2903d02 | ||
|
60977de242 | ||
|
cb612bcfbe | ||
|
6be1c2cdb4 | ||
|
034ab0b3b1 | ||
|
8c50347f3c | ||
|
9f76fb6980 | ||
|
8b0ff0a25c | ||
|
8891ea1a7a | ||
|
ede2ad94bc | ||
|
eacf3cdbb4 | ||
|
3569a13b74 | ||
|
b2a96ec744 | ||
|
a505adb2b7 | ||
|
906b6e52f8 | ||
|
3292337754 | ||
|
eb4af86e3c | ||
|
1b3e971549 | ||
|
4615eee2d8 | ||
|
7c57245943 | ||
|
0d100ad7e9 | ||
|
0235789863 | ||
|
c080a46571 | ||
|
5f050cb590 | ||
|
25f14a1917 | ||
|
e9927377b5 | ||
|
3ea76f8a9b | ||
|
8a45ed9671 | ||
|
1520749351 | ||
|
f66f52d1ba | ||
|
49e18738c3 | ||
|
586b57009a | ||
|
5112564f08 | ||
|
34726a9926 | ||
|
5884ab7b76 | ||
|
60db018ce4 | ||
|
6b002bad3d | ||
|
5b173c1b61 | ||
|
bc2fb5c7ab | ||
|
ebdf82f491 | ||
|
36f6fa9861 | ||
|
91a34bb875 | ||
|
d342fb1879 | ||
|
b283572453 | ||
|
62a74a5ef9 | ||
|
a14aeb27bb | ||
|
249d010dad | ||
|
9b13fdeae4 | ||
|
794b6b35ce | ||
|
dcff4d3db2 | ||
|
b94466e502 | ||
|
11052053d8 | ||
|
6ab3984bba | ||
|
136e0c7e52 | ||
|
7e2ef926ea | ||
|
061981fb23 | ||
|
3d6fb2f2e5 | ||
|
a8e6123d47 | ||
|
406c8a2117 | ||
|
0445962bd4 | ||
|
09f0c2d8ce | ||
|
8dea884a69 | ||
|
57898762a2 | ||
|
01bf8d7b6c | ||
|
af8d55c08e | ||
|
53398b42c6 | ||
|
1bf142e048 | ||
|
0405c4f77d | ||
|
61595763b0 | ||
|
f6ecc8da7b | ||
|
32792a0de5 | ||
|
c3d60b55bd | ||
|
17be6718ee | ||
|
abf912b729 | ||
|
5bc0197c78 | ||
|
62f47190fb | ||
|
a706f4c97c | ||
|
feb365a77b | ||
|
b2a4e67fee | ||
|
e7d2792009 | ||
|
0fde1424f0 | ||
|
29fd447f0c | ||
|
7047d96087 | ||
|
6336e641f4 | ||
|
ecabe757a2 | ||
|
37c48257ae | ||
|
8668e43f6d | ||
|
785713c9c0 | ||
|
b523402eda | ||
|
3790635af1 | ||
|
b940fadb7e | ||
|
3ef2970032 | ||
|
4372aa16d3 | ||
|
3346f9511a | ||
|
1cd7363bea | ||
|
17e3dca9f9 | ||
|
533f560ce0 | ||
|
6a60d4893e | ||
|
51dd082682 | ||
|
47d8d9d22b | ||
|
d6d4dcb141 | ||
|
37ec1774a7 | ||
|
3ad4d7dd6e | ||
|
e596091fa2 | ||
|
4f5c7ed6af | ||
|
60ffa1953b | ||
|
5519a73087 | ||
|
67717a7872 | ||
|
4522d4b8aa | ||
|
d7ca339c27 | ||
|
6b39165801 | ||
|
78ade6cfb5 | ||
|
3f68b4f76b | ||
|
521aab5fcc | ||
|
42492596b3 | ||
|
b24e728666 | ||
|
4fe0b810e1 | ||
|
8deed174f5 | ||
|
2184547094 | ||
|
8eda4dc040 | ||
|
4d4db92a46 | ||
|
ea8b7e0c91 | ||
|
6928957096 | ||
|
b680b726d1 | ||
|
fbd692c449 | ||
|
2199a7908d | ||
|
59704f1508 | ||
|
20536923d6 | ||
|
bba7289537 | ||
|
04d1ccc085 | ||
|
a7e7c5eb52 | ||
|
9d2839f8ca | ||
|
1146013e9e | ||
|
8a91c0a0e5 | ||
|
a1c75454e9 | ||
|
ad3963daa6 | ||
|
a66339d63c | ||
|
d0bdd4dc91 | ||
|
d24078be31 | ||
|
f251648726 | ||
|
b587ecb30f | ||
|
a580712b2f | ||
|
ce5d52b54e | ||
|
55fe6f0bc9 | ||
|
abf142ea3f | ||
|
ae9f89b5d1 | ||
|
058761e16e | ||
|
ad8c6225fd | ||
|
1cbadf5f54 | ||
|
e7021715b8 | ||
|
0d2749a3fd | ||
|
76fbd628e1 | ||
|
15309d2bdd | ||
|
4f6924a0c1 | ||
|
063f65d065 | ||
|
adf8691093 | ||
|
6a7ad2125d | ||
|
247aa26d3e | ||
|
3c9f620c77 | ||
|
e0e2a61dfc | ||
|
168ae4099d | ||
|
6ceb4af2d4 | ||
|
240c2dd657 | ||
|
a5b94ebd0c | ||
|
5037c2f365 | ||
|
ef05404bee | ||
|
3db493665e | ||
|
737f1cc67c | ||
|
b5c2b09780 | ||
|
46817a38c3 | ||
|
52f3471405 | ||
|
e567502750 | ||
|
c1cdc1de58 | ||
|
f2c41f366f | ||
|
56d06e27cf | ||
|
93e327f4a5 | ||
|
687668a4b3 | ||
|
cfeac79130 | ||
|
4227e36ca5 | ||
|
be1c9f249e | ||
|
511a129a7e | ||
|
d62ca8c518 | ||
|
30413265c7 | ||
|
bd5d8a77c9 | ||
|
326ae15532 | ||
|
9afb65da34 | ||
|
fe7643c84a | ||
|
6daad3ae66 | ||
|
44590b8907 | ||
|
4400b52aab | ||
|
c217553cf8 | ||
|
6ad5003149 | ||
|
7c77b0e48c | ||
|
7b36118df4 | ||
|
7f0dbe5356 | ||
|
b87fc217df | ||
|
625dc4bf44 | ||
|
34736a4929 | ||
|
4f37cde043 | ||
|
7df60376ff | ||
|
7fa4adb0d9 | ||
|
abb91ae77b | ||
|
a4b1ac83f4 | ||
|
8775cdc13f | ||
|
db732ce9fa | ||
|
7c09244c39 | ||
|
2cc2a5f2ff | ||
|
e4b50f2a8d | ||
|
a2a84532ff | ||
|
d391323129 | ||
|
ab28ecf31b | ||
|
a4bab68802 | ||
|
e3cfacf0cb | ||
|
8d74e01f41 | ||
|
5404bb13d4 | ||
|
be8773fee0 | ||
|
0bcec80dfe | ||
|
2c8c2bffda | ||
|
d70f289e73 | ||
|
498a5980e8 | ||
|
8021c5d968 | ||
|
c536ab214d | ||
|
adb81e2a1e | ||
|
c4a3e12add | ||
|
a3d7d72421 | ||
|
47266b9ae8 | ||
|
e39f13a8ea | ||
|
c04604dbc0 | ||
|
1782646723 | ||
|
78e64e3d5b | ||
|
0acb620159 | ||
|
9982295e10 | ||
|
8ed71b2777 | ||
|
969b3709db | ||
|
e2a7938b26 | ||
|
70a4221b9e | ||
|
8d320ceac2 | ||
|
c169a98be6 | ||
|
6d48307c8d | ||
|
e539ecc9aa | ||
|
bf5eeaf61e | ||
|
a36faf89e3 | ||
|
29c44e281c | ||
|
1877a97898 | ||
|
bf6602ebff | ||
|
6bcf0e3a50 | ||
|
d0aeabb8f0 | ||
|
956df20c64 | ||
|
7108454455 | ||
|
663a93912b | ||
|
a85bd4ad2a | ||
|
6f462a72bf | ||
|
352f592767 | ||
|
f2080e520f | ||
|
cd78291de5 | ||
|
ab595d1875 | ||
|
597544e30a | ||
|
9f59a13836 | ||
|
12017e49bd | ||
|
abad796c44 | ||
|
92137273a2 | ||
|
f1ab289022 | ||
|
a302b76d59 | ||
|
4717594e93 | ||
|
df0f76bba5 | ||
|
e43c9f66ff | ||
|
0df58d8aa2 | ||
|
ff1a0e1eb8 | ||
|
ed765fe508 | ||
|
1b5eb7da5e | ||
|
071f576db9 | ||
|
3d10ba5f72 | ||
|
85b8386ba1 | ||
|
7ec3607446 | ||
|
835bb1cd9c | ||
|
9d35dce63e | ||
|
74fb205083 | ||
|
ba0bb10366 | ||
|
0296511f2c | ||
|
04fe81f88f | ||
|
98bbc15435 | ||
|
25b206ac53 | ||
|
88a4e44fd4 | ||
|
642ea07d6f | ||
|
e85c5ce39d | ||
|
cf753af247 | ||
|
12efe604bb | ||
|
f36f545d75 | ||
|
8fcd544c81 | ||
|
73662ebf83 | ||
|
47a8ec06a1 | ||
|
b611fac20b | ||
|
b11155423c | ||
|
40371cbf2d | ||
|
613590b0d8 | ||
|
4710a65f7a | ||
|
901f65ca05 | ||
|
72cf6806de | ||
|
1b7ae2ed3d | ||
|
c6100d0771 | ||
|
6339467b6d | ||
|
dda24b1e23 | ||
|
f7cc614d67 | ||
|
4bbf35832e | ||
|
b9feb10420 | ||
|
42b6f6b6e5 | ||
|
07cf47baad | ||
|
686289814d | ||
|
bb37e65ab1 | ||
|
31b961d8b3 | ||
|
4a578284a5 | ||
|
c5bbcd78ae | ||
|
4fbe0495b4 | ||
|
ff3d2e1691 | ||
|
684a36d6cf | ||
|
7d74e1cb66 | ||
|
b32b6029de | ||
|
5fa42cd1b0 | ||
|
6318801470 | ||
|
97d524fa96 | ||
|
c31df519e0 | ||
|
0240d09949 |
@@ -1,2 +1,9 @@
|
||||
[cxx]
|
||||
gtest_dep = //lib/gtest:gtest
|
||||
[android]
|
||||
target = android-23
|
||||
[ndk]
|
||||
ndk_version = 13.1.3345770
|
||||
compiler = clang
|
||||
app_platform = android-21
|
||||
cpu_abis = arm64, armv7, x86, x86_64
|
||||
|
17
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Report
|
||||
|
||||
- [ ] I have searched [existing issues](https://github.com/facebook/yoga/issues) and this is not a duplicate
|
||||
|
||||
# Issues and Steps to Reproduce
|
||||
***Replaces this with steps to repro your issue.***
|
||||
|
||||
# Expected Behavior
|
||||
***Describe what you expected would happen.***
|
||||
|
||||
# Actual Behavior
|
||||
***Describe what actually happened.***
|
||||
|
||||
# Link to Code
|
||||
***If you have some code that maintainers can clone/test for themselves, bugs can be resolved much faster. Please paste a link here.***
|
||||
|
||||
***When applicable, use this [fiddle](https://jsfiddle.net/emilsjolander/jckmwztt/) to post a web repro.***
|
57
.gitignore
vendored
@@ -5,6 +5,63 @@
|
||||
/.buckconfig.local
|
||||
/.buckd
|
||||
/gentest/test.html
|
||||
.buckversion
|
||||
|
||||
# Jekyll
|
||||
/.sass-cache/
|
||||
/_site/
|
||||
|
||||
# Visual studio code
|
||||
.vscode
|
||||
*.pdb
|
||||
*.tlog
|
||||
*.obj
|
||||
*.pch
|
||||
*.log
|
||||
*.orig
|
||||
|
||||
# Xcode
|
||||
## Build generated
|
||||
build/
|
||||
DerivedData/
|
||||
|
||||
## Various settings
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata/
|
||||
|
||||
## Other
|
||||
*.moved-aside
|
||||
*.xcuserstate
|
||||
|
||||
## Obj-C/Swift specific
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.dSYM.zip
|
||||
*.dSYM
|
||||
|
||||
# CocoaPods
|
||||
#
|
||||
# We recommend against adding the Pods directory to your .gitignore. However
|
||||
# you should judge for yourself, the pros and cons are mentioned at:
|
||||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
||||
#
|
||||
Pods/
|
||||
|
||||
# Carthage
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from Carthage dependencies.
|
||||
# Carthage/Checkouts
|
||||
|
||||
Carthage/Build
|
||||
|
||||
# Gradle
|
||||
.gradle
|
||||
# NDK/CMake
|
||||
.externalNativeBuild
|
||||
|
10
.hgignore
@@ -1,10 +0,0 @@
|
||||
.DS_STORE
|
||||
|
||||
/buck-cache/
|
||||
/buck-out/
|
||||
/.buckconfig.local
|
||||
/.buckd
|
||||
/gentest/test.html
|
||||
|
||||
# Visual studio code
|
||||
.vscode
|
1
.swift-version
Normal file
@@ -0,0 +1 @@
|
||||
3.0
|
128
.travis.yml
@@ -6,25 +6,121 @@
|
||||
# of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
os: osx
|
||||
osx_image: xcode7.3
|
||||
osx_image: xcode8.2
|
||||
language: cpp
|
||||
compiler: clang
|
||||
|
||||
env:
|
||||
- TARGET=c
|
||||
- TARGET=java
|
||||
- TARGET=net
|
||||
- TARGET=ios
|
||||
- TARGET=js
|
||||
- TARGET=android
|
||||
|
||||
before_install:
|
||||
- brew update
|
||||
- brew tap facebook/fb
|
||||
- brew install buck
|
||||
- brew cask install java
|
||||
- brew outdated xctool || brew upgrade xctool
|
||||
- brew install mono
|
||||
- export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)
|
||||
- export PATH=$JAVA_HOME/bin:$PATH
|
||||
- openssl aes-256-cbc -K $encrypted_d27e803291ff_key -iv $encrypted_d27e803291ff_iv -in scripts/setup-keys.enc -d >> gradle.properties
|
||||
- brew update > /dev/null
|
||||
- brew install --HEAD facebook/fb/buck
|
||||
|
||||
# Java
|
||||
- |
|
||||
if [[ $TARGET = "java" ]]; then
|
||||
brew cask install java &&
|
||||
export JAVA_HOME=$(/usr/libexec/java_home -v 1.8) &&
|
||||
export PATH=$JAVA_HOME/bin:$PATH
|
||||
fi
|
||||
|
||||
# .NET
|
||||
- |
|
||||
if [[ $TARGET = "net" ]]; then
|
||||
brew install mono
|
||||
fi
|
||||
|
||||
# iOS
|
||||
- |
|
||||
if [[ $TARGET = "ios" ]]; then
|
||||
brew outdated xctool || brew upgrade xctool;
|
||||
gem install xcpretty --no-document --quiet;
|
||||
gem install cocoapods --pre --no-document --quiet;
|
||||
pod repo update --silent;
|
||||
pod install --project-directory=YogaKit/YogaKitSample/;
|
||||
fi
|
||||
|
||||
# Emscripten (used for js tests)
|
||||
# Note: cannot be ran on Linux (because it will compile Clang from its sources :|)
|
||||
- |
|
||||
if [[ $TARGET = "js" ]]; then
|
||||
wget -O /tmp/emsdk-portable.tar.gz https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz &&
|
||||
tar xf /tmp/emsdk-portable.tar.gz -C /tmp/ &&
|
||||
/tmp/emsdk-portable/emsdk install latest 2>&1 | grep -v '^x ' &&
|
||||
/tmp/emsdk-portable/emsdk activate latest
|
||||
fi
|
||||
|
||||
# Android
|
||||
- |
|
||||
if [[ $TARGET = "android" ]]; then
|
||||
brew cask install java;
|
||||
export JAVA_HOME=$(/usr/libexec/java_home -v 1.8);
|
||||
export PATH=$JAVA_HOME/bin:$PATH;
|
||||
brew install caskroom/cask/android-sdk;
|
||||
export ANDROID_SDK=/usr/local/Cellar/android-sdk/24.4.1_1;
|
||||
export ANDROID_HOME=/usr/local/Cellar/android-sdk/24.4.1_1;
|
||||
brew install lib32stdc++6 lib32z1;
|
||||
echo y | $ANDROID_SDK/tools/android update sdk --filter android-19,addon-google_apis-google-19,build-tools-19.1.0 --no-ui;
|
||||
echo y | $ANDROID_SDK/tools/android update sdk -u;
|
||||
fi
|
||||
|
||||
# JavaScript
|
||||
- |
|
||||
if [[ $TARGET = "js" ]]; then (
|
||||
cd javascript &&
|
||||
npm install &&
|
||||
unset CC && unset CXX && unset LINK &&
|
||||
source /tmp/emsdk-portable/emsdk_env.sh &&
|
||||
npm run build:browser
|
||||
) fi
|
||||
|
||||
script:
|
||||
- buck test //:CSSLayout
|
||||
- buck test //java:java
|
||||
- buck test //CSSLayoutKit:CSSLayoutKit --config cxx.default_platform=iphonesimulator-x86_64 --config cxx.cflags=-DTRAVIS_CI
|
||||
- sh csharp/tests/Facebook.CSSLayout/test_macos.sh
|
||||
- buck run //benchmark:benchmark
|
||||
- git checkout HEAD^
|
||||
- buck run //benchmark:benchmark
|
||||
# C
|
||||
- |
|
||||
if [[ $TARGET = "c" ]]; then
|
||||
buck test --verbose 0 //:yoga &&
|
||||
buck run --verbose 0 //benchmark:benchmark &&
|
||||
git checkout HEAD^ &&
|
||||
buck run --verbose 0 //benchmark:benchmark
|
||||
fi
|
||||
|
||||
# Java
|
||||
- |
|
||||
if [[ $TARGET = "java" ]]; then
|
||||
buck test --verbose 0 //java:java
|
||||
fi
|
||||
|
||||
# .NET
|
||||
- |
|
||||
if [[ $TARGET = "net" ]]; then
|
||||
sh csharp/tests/Facebook.Yoga/test_macos.sh
|
||||
fi
|
||||
|
||||
# iOS
|
||||
- |
|
||||
if [[ $TARGET = "ios" ]]; then
|
||||
buck test --verbose 0 //YogaKit:YogaKitTests --config cxx.default_platform=iphonesimulator-x86_64 &&
|
||||
set -o pipefail &&
|
||||
xcodebuild build -workspace YogaKit/YogaKitSample/YogaKitSample.xcworkspace -scheme YogaKitSample -sdk iphonesimulator | xcpretty -c
|
||||
fi
|
||||
|
||||
# Android
|
||||
- |
|
||||
if [[ $TARGET = "android" ]]; then
|
||||
buck build --verbose 0 //android/sample:sample
|
||||
fi
|
||||
|
||||
# JavaScript
|
||||
- |
|
||||
if [[ $TARGET = "js" ]]; then (
|
||||
cd javascript &&
|
||||
npm run test:all &&
|
||||
npm run bench
|
||||
) fi
|
||||
|
59
BUCK
@@ -5,44 +5,41 @@
|
||||
# LICENSE file in the root directory of this source tree. An additional grant
|
||||
# of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
include_defs('//CSSLAYOUT_DEFS')
|
||||
|
||||
BASE_COMPILER_FLAGS = [
|
||||
'-fno-omit-frame-pointer',
|
||||
'-fexceptions',
|
||||
'-Wall',
|
||||
'-Werror',
|
||||
'-O3',
|
||||
]
|
||||
include_defs("//YOGA_DEFS")
|
||||
|
||||
GMOCK_OVERRIDE_FLAGS = [
|
||||
# gmock does not mark mocked methods as override, ignore the warnings in tests
|
||||
'-Wno-inconsistent-missing-override',
|
||||
# gmock does not mark mocked methods as override, ignore the warnings in tests
|
||||
"-Wno-inconsistent-missing-override",
|
||||
]
|
||||
|
||||
COMPILER_FLAGS = BASE_COMPILER_FLAGS + ['-std=c11']
|
||||
TEST_COMPILER_FLAGS = BASE_COMPILER_FLAGS + GMOCK_OVERRIDE_FLAGS + ['-std=c++11']
|
||||
COMPILER_FLAGS = LIBRARY_COMPILER_FLAGS + [
|
||||
"-std=c11",
|
||||
]
|
||||
|
||||
TEST_COMPILER_FLAGS = BASE_COMPILER_FLAGS + GMOCK_OVERRIDE_FLAGS + ["-std=c++11"]
|
||||
|
||||
cxx_library(
|
||||
name = 'CSSLayout',
|
||||
srcs = glob(['CSSLayout/*.c']),
|
||||
tests=[':tests'],
|
||||
exported_headers = subdir_glob([('', 'CSSLayout/*.h')]),
|
||||
header_namespace = '',
|
||||
force_static = True,
|
||||
compiler_flags = COMPILER_FLAGS,
|
||||
deps = [],
|
||||
visibility = ['PUBLIC'],
|
||||
name = "yoga",
|
||||
srcs = glob(["yoga/*.c"]),
|
||||
compiler_flags = COMPILER_FLAGS,
|
||||
exported_headers = subdir_glob([("", "yoga/*.h")]),
|
||||
header_namespace = "",
|
||||
soname = "libyogacore.$(ext)",
|
||||
tests = [":YogaTests"],
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [] if THIS_IS_FBOBJC else [
|
||||
yoga_dep("lib/fb:ndklog"),
|
||||
],
|
||||
)
|
||||
|
||||
cxx_test(
|
||||
name = 'tests',
|
||||
contacts = ['emilsj@fb.com'],
|
||||
srcs = glob(['tests/*.cpp']),
|
||||
compiler_flags = TEST_COMPILER_FLAGS,
|
||||
deps = [
|
||||
':CSSLayout',
|
||||
GTEST_TARGET,
|
||||
],
|
||||
visibility = ['PUBLIC'],
|
||||
name = "YogaTests",
|
||||
srcs = glob(["tests/*.cpp"]),
|
||||
compiler_flags = TEST_COMPILER_FLAGS,
|
||||
contacts = ["emilsj@fb.com"],
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
":yoga",
|
||||
GTEST_TARGET,
|
||||
],
|
||||
)
|
||||
|
17
CMakeLists.txt
Normal file
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# Copyright (c) 2014-present, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the BSD-style license found in the
|
||||
# LICENSE file in the root directory of this source tree. An additional grant
|
||||
# of patent rights can be found in the PATENTS file in the same directory.
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.4.1)
|
||||
|
||||
set(CMAKE_VERBOSE_MAKEFILE on)
|
||||
|
||||
file(GLOB yogacore_SRC yoga/*.c)
|
||||
add_library(yogacore STATIC ${yogacore_SRC})
|
||||
|
||||
target_link_libraries(yogacore android log)
|
@@ -1,10 +1,7 @@
|
||||
# Contributing to css-layout
|
||||
# Contributing to yoga
|
||||
We want to make contributing to this project as easy and transparent as
|
||||
possible.
|
||||
|
||||
## Our Development Process
|
||||
All the development is happening on GitHub first and we have internal tools to sync down to Facebook codebase.
|
||||
|
||||
## Pull Requests
|
||||
We actively welcome your pull requests.
|
||||
1. Fork the repo and create your branch from `master`.
|
||||
@@ -32,5 +29,5 @@ outlined on that page and do not file a public issue.
|
||||
* format.sh
|
||||
|
||||
## License
|
||||
By contributing to css-layout, you agree that your contributions will be licensed
|
||||
By contributing to yoga, you agree that your contributions will be licensed
|
||||
under its BSD license.
|
@@ -1,24 +0,0 @@
|
||||
|
||||
CSSLAYOUT_ROOT = '//...'
|
||||
INFER_ANNOTATIONS_TARGET = '//lib/infer-annotations:infer-annotations'
|
||||
JSR_305_TARGET = '//lib/jsr-305:jsr-305'
|
||||
JUNIT_TARGET = '//lib/junit:junit'
|
||||
PROGRUARD_ANNOTATIONS_TARGET = '//java/com/facebook/proguard/annotations:annotations'
|
||||
SOLOADER_TARGET = '//lib/soloader:soloader'
|
||||
GTEST_TARGET = '//lib/gtest:gtest'
|
||||
JNI_TARGET = '//lib/jni:jni'
|
||||
FBJNI_TARGET = '//lib/fb:fbjni'
|
||||
|
||||
CXX_LIBRARY_WHITELIST = [
|
||||
'//lib/fb:fbjni',
|
||||
'//java:jni',
|
||||
]
|
||||
|
||||
def csslayout_dep(dep):
|
||||
return '//' + dep
|
||||
|
||||
class allow_unsafe_import:
|
||||
def __enter__(self):
|
||||
pass
|
||||
def __exit__(self, type, value, traceback):
|
||||
pass
|
@@ -1,108 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
typedef enum CSSOverflow {
|
||||
CSSOverflowVisible,
|
||||
CSSOverflowHidden,
|
||||
CSSOverflowScroll,
|
||||
CSSOverflowCount,
|
||||
} CSSOverflow;
|
||||
|
||||
typedef enum CSSJustify {
|
||||
CSSJustifyFlexStart,
|
||||
CSSJustifyCenter,
|
||||
CSSJustifyFlexEnd,
|
||||
CSSJustifySpaceBetween,
|
||||
CSSJustifySpaceAround,
|
||||
CSSJustifyCount,
|
||||
} CSSJustify;
|
||||
|
||||
typedef enum CSSFlexDirection {
|
||||
CSSFlexDirectionColumn,
|
||||
CSSFlexDirectionColumnReverse,
|
||||
CSSFlexDirectionRow,
|
||||
CSSFlexDirectionRowReverse,
|
||||
CSSFlexDirectionCount,
|
||||
} CSSFlexDirection;
|
||||
|
||||
typedef enum CSSAlign {
|
||||
CSSAlignAuto,
|
||||
CSSAlignFlexStart,
|
||||
CSSAlignCenter,
|
||||
CSSAlignFlexEnd,
|
||||
CSSAlignStretch,
|
||||
CSSAlignCount,
|
||||
} CSSAlign;
|
||||
|
||||
typedef enum CSSEdge {
|
||||
CSSEdgeLeft,
|
||||
CSSEdgeTop,
|
||||
CSSEdgeRight,
|
||||
CSSEdgeBottom,
|
||||
CSSEdgeStart,
|
||||
CSSEdgeEnd,
|
||||
CSSEdgeHorizontal,
|
||||
CSSEdgeVertical,
|
||||
CSSEdgeAll,
|
||||
CSSEdgeCount,
|
||||
} CSSEdge;
|
||||
|
||||
typedef enum CSSWrap {
|
||||
CSSWrapNoWrap,
|
||||
CSSWrapWrap,
|
||||
CSSWrapCount,
|
||||
} CSSWrap;
|
||||
|
||||
typedef enum CSSDirection {
|
||||
CSSDirectionInherit,
|
||||
CSSDirectionLTR,
|
||||
CSSDirectionRTL,
|
||||
CSSDirectionCount,
|
||||
} CSSDirection;
|
||||
|
||||
typedef enum CSSExperimentalFeature {
|
||||
CSSExperimentalFeatureRounding,
|
||||
CSSExperimentalFeatureWebFlexBasis,
|
||||
CSSExperimentalFeatureCount,
|
||||
} CSSExperimentalFeature;
|
||||
|
||||
typedef enum CSSLogLevel {
|
||||
CSSLogLevelError,
|
||||
CSSLogLevelWarn,
|
||||
CSSLogLevelInfo,
|
||||
CSSLogLevelDebug,
|
||||
CSSLogLevelVerbose,
|
||||
CSSLogLevelCount,
|
||||
} CSSLogLevel;
|
||||
|
||||
typedef enum CSSDimension {
|
||||
CSSDimensionWidth,
|
||||
CSSDimensionHeight,
|
||||
CSSDimensionCount,
|
||||
} CSSDimension;
|
||||
|
||||
typedef enum CSSMeasureMode {
|
||||
CSSMeasureModeUndefined,
|
||||
CSSMeasureModeExactly,
|
||||
CSSMeasureModeAtMost,
|
||||
CSSMeasureModeCount,
|
||||
} CSSMeasureMode;
|
||||
|
||||
typedef enum CSSPositionType {
|
||||
CSSPositionTypeRelative,
|
||||
CSSPositionTypeAbsolute,
|
||||
CSSPositionTypeCount,
|
||||
} CSSPositionType;
|
||||
|
||||
typedef enum CSSPrintOptions {
|
||||
CSSPrintOptionsLayout = 1,
|
||||
CSSPrintOptionsStyle = 2,
|
||||
CSSPrintOptionsChildren = 4,
|
||||
CSSPrintOptionsCount,
|
||||
} CSSPrintOptions;
|
@@ -1,184 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
// Not defined in MSVC++
|
||||
#ifndef NAN
|
||||
static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff};
|
||||
#define NAN (*(const float *) __nan)
|
||||
#endif
|
||||
|
||||
#define CSSUndefined NAN
|
||||
|
||||
#include "CSSEnums.h"
|
||||
#include "CSSMacros.h"
|
||||
|
||||
CSS_EXTERN_C_BEGIN
|
||||
|
||||
typedef struct CSSSize {
|
||||
float width;
|
||||
float height;
|
||||
} CSSSize;
|
||||
|
||||
typedef struct CSSNode *CSSNodeRef;
|
||||
typedef CSSSize (*CSSMeasureFunc)(CSSNodeRef node,
|
||||
float width,
|
||||
CSSMeasureMode widthMode,
|
||||
float height,
|
||||
CSSMeasureMode heightMode);
|
||||
typedef void (*CSSPrintFunc)(CSSNodeRef node);
|
||||
typedef int (*CSSLogger)(CSSLogLevel level, const char *format, va_list args);
|
||||
|
||||
typedef void *(*CSSMalloc)(size_t size);
|
||||
typedef void *(*CSSCalloc)(size_t count, size_t size);
|
||||
typedef void *(*CSSRealloc)(void *ptr, size_t size);
|
||||
typedef void (*CSSFree)(void *ptr);
|
||||
|
||||
// CSSNode
|
||||
WIN_EXPORT CSSNodeRef CSSNodeNew(void);
|
||||
WIN_EXPORT void CSSNodeInit(const CSSNodeRef node);
|
||||
WIN_EXPORT void CSSNodeFree(const CSSNodeRef node);
|
||||
WIN_EXPORT void CSSNodeFreeRecursive(const CSSNodeRef node);
|
||||
WIN_EXPORT void CSSNodeReset(const CSSNodeRef node);
|
||||
WIN_EXPORT int32_t CSSNodeGetInstanceCount(void);
|
||||
|
||||
WIN_EXPORT void CSSNodeInsertChild(const CSSNodeRef node,
|
||||
const CSSNodeRef child,
|
||||
const uint32_t index);
|
||||
WIN_EXPORT void CSSNodeRemoveChild(const CSSNodeRef node, const CSSNodeRef child);
|
||||
WIN_EXPORT CSSNodeRef CSSNodeGetChild(const CSSNodeRef node, const uint32_t index);
|
||||
WIN_EXPORT uint32_t CSSNodeChildCount(const CSSNodeRef node);
|
||||
|
||||
WIN_EXPORT void CSSNodeCalculateLayout(const CSSNodeRef node,
|
||||
const float availableWidth,
|
||||
const float availableHeight,
|
||||
const CSSDirection parentDirection);
|
||||
|
||||
// Mark a node as dirty. Only valid for nodes with a custom measure function
|
||||
// set.
|
||||
// CSSLayout knows when to mark all other nodes as dirty but because nodes with
|
||||
// measure functions
|
||||
// depends on information not known to CSSLayout they must perform this dirty
|
||||
// marking manually.
|
||||
WIN_EXPORT void CSSNodeMarkDirty(const CSSNodeRef node);
|
||||
WIN_EXPORT bool CSSNodeIsDirty(const CSSNodeRef node);
|
||||
|
||||
WIN_EXPORT void CSSNodePrint(const CSSNodeRef node, const CSSPrintOptions options);
|
||||
|
||||
WIN_EXPORT bool CSSValueIsUndefined(const float value);
|
||||
|
||||
WIN_EXPORT bool CSSNodeCanUseCachedMeasurement(const CSSMeasureMode widthMode,
|
||||
const float width,
|
||||
const CSSMeasureMode heightMode,
|
||||
const float height,
|
||||
const CSSMeasureMode lastWidthMode,
|
||||
const float lastWidth,
|
||||
const CSSMeasureMode lastHeightMode,
|
||||
const float lastHeight,
|
||||
const float lastComputedWidth,
|
||||
const float lastComputedHeight,
|
||||
const float marginRow,
|
||||
const float marginColumn);
|
||||
|
||||
WIN_EXPORT void CSSNodeCopyStyle(const CSSNodeRef dstNode, const CSSNodeRef srcNode);
|
||||
|
||||
#define CSS_NODE_PROPERTY(type, name, paramName) \
|
||||
WIN_EXPORT void CSSNodeSet##name(const CSSNodeRef node, type paramName); \
|
||||
WIN_EXPORT type CSSNodeGet##name(const CSSNodeRef node);
|
||||
|
||||
#define CSS_NODE_STYLE_PROPERTY(type, name, paramName) \
|
||||
WIN_EXPORT void CSSNodeStyleSet##name(const CSSNodeRef node, const type paramName); \
|
||||
WIN_EXPORT type CSSNodeStyleGet##name(const CSSNodeRef node);
|
||||
|
||||
#define CSS_NODE_STYLE_EDGE_PROPERTY(type, name, paramName) \
|
||||
WIN_EXPORT void CSSNodeStyleSet##name(const CSSNodeRef node, \
|
||||
const CSSEdge edge, \
|
||||
const type paramName); \
|
||||
WIN_EXPORT type CSSNodeStyleGet##name(const CSSNodeRef node, const CSSEdge edge);
|
||||
|
||||
#define CSS_NODE_LAYOUT_PROPERTY(type, name) \
|
||||
WIN_EXPORT type CSSNodeLayoutGet##name(const CSSNodeRef node);
|
||||
|
||||
CSS_NODE_PROPERTY(void *, Context, context);
|
||||
CSS_NODE_PROPERTY(CSSMeasureFunc, MeasureFunc, measureFunc);
|
||||
CSS_NODE_PROPERTY(CSSPrintFunc, PrintFunc, printFunc);
|
||||
CSS_NODE_PROPERTY(bool, HasNewLayout, hasNewLayout);
|
||||
|
||||
CSS_NODE_STYLE_PROPERTY(CSSDirection, Direction, direction);
|
||||
CSS_NODE_STYLE_PROPERTY(CSSFlexDirection, FlexDirection, flexDirection);
|
||||
CSS_NODE_STYLE_PROPERTY(CSSJustify, JustifyContent, justifyContent);
|
||||
CSS_NODE_STYLE_PROPERTY(CSSAlign, AlignContent, alignContent);
|
||||
CSS_NODE_STYLE_PROPERTY(CSSAlign, AlignItems, alignItems);
|
||||
CSS_NODE_STYLE_PROPERTY(CSSAlign, AlignSelf, alignSelf);
|
||||
CSS_NODE_STYLE_PROPERTY(CSSPositionType, PositionType, positionType);
|
||||
CSS_NODE_STYLE_PROPERTY(CSSWrap, FlexWrap, flexWrap);
|
||||
CSS_NODE_STYLE_PROPERTY(CSSOverflow, Overflow, overflow);
|
||||
|
||||
WIN_EXPORT void CSSNodeStyleSetFlex(const CSSNodeRef node, const float flex);
|
||||
CSS_NODE_STYLE_PROPERTY(float, FlexGrow, flexGrow);
|
||||
CSS_NODE_STYLE_PROPERTY(float, FlexShrink, flexShrink);
|
||||
CSS_NODE_STYLE_PROPERTY(float, FlexBasis, flexBasis);
|
||||
|
||||
CSS_NODE_STYLE_EDGE_PROPERTY(float, Position, position);
|
||||
CSS_NODE_STYLE_EDGE_PROPERTY(float, Margin, margin);
|
||||
CSS_NODE_STYLE_EDGE_PROPERTY(float, Padding, padding);
|
||||
CSS_NODE_STYLE_EDGE_PROPERTY(float, Border, border);
|
||||
|
||||
CSS_NODE_STYLE_PROPERTY(float, Width, width);
|
||||
CSS_NODE_STYLE_PROPERTY(float, Height, height);
|
||||
CSS_NODE_STYLE_PROPERTY(float, MinWidth, minWidth);
|
||||
CSS_NODE_STYLE_PROPERTY(float, MinHeight, minHeight);
|
||||
CSS_NODE_STYLE_PROPERTY(float, MaxWidth, maxWidth);
|
||||
CSS_NODE_STYLE_PROPERTY(float, MaxHeight, maxHeight);
|
||||
|
||||
// Yoga specific properties, not compatible with flexbox specification
|
||||
// Aspect ratio control the size of the undefined dimension of a node.
|
||||
// - On a node with a set width/height aspect ratio control the size of the unset dimension
|
||||
// - On a node with a set flex basis aspect ratio controls the size of the node in the cross axis if
|
||||
// unset
|
||||
// - On a node with a measure function aspect ratio works as though the measure function measures
|
||||
// the flex basis
|
||||
// - On a node with flex grow/shrink aspect ratio controls the size of the node in the cross axis if
|
||||
// unset
|
||||
// - Aspect ratio takes min/max dimensions into account
|
||||
CSS_NODE_STYLE_PROPERTY(float, AspectRatio, aspectRatio);
|
||||
|
||||
CSS_NODE_LAYOUT_PROPERTY(float, Left);
|
||||
CSS_NODE_LAYOUT_PROPERTY(float, Top);
|
||||
CSS_NODE_LAYOUT_PROPERTY(float, Right);
|
||||
CSS_NODE_LAYOUT_PROPERTY(float, Bottom);
|
||||
CSS_NODE_LAYOUT_PROPERTY(float, Width);
|
||||
CSS_NODE_LAYOUT_PROPERTY(float, Height);
|
||||
CSS_NODE_LAYOUT_PROPERTY(CSSDirection, Direction);
|
||||
|
||||
WIN_EXPORT void CSSLayoutSetLogger(CSSLogger logger);
|
||||
WIN_EXPORT void CSSLog(CSSLogLevel level, const char *message, ...);
|
||||
|
||||
WIN_EXPORT void CSSLayoutSetExperimentalFeatureEnabled(CSSExperimentalFeature feature,
|
||||
bool enabled);
|
||||
WIN_EXPORT bool CSSLayoutIsExperimentalFeatureEnabled(CSSExperimentalFeature feature);
|
||||
|
||||
WIN_EXPORT void CSSLayoutSetMemoryFuncs(CSSMalloc cssMalloc,
|
||||
CSSCalloc cssCalloc,
|
||||
CSSRealloc cssRealloc,
|
||||
CSSFree cssFree);
|
||||
|
||||
CSS_EXTERN_C_END
|
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define CSS_EXTERN_C_BEGIN extern "C" {
|
||||
#define CSS_EXTERN_C_END }
|
||||
#else
|
||||
#define CSS_EXTERN_C_BEGIN
|
||||
#define CSS_EXTERN_C_END
|
||||
#endif
|
||||
|
||||
#ifdef _WINDLL
|
||||
#define WIN_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define WIN_EXPORT
|
||||
#endif
|
||||
|
||||
#ifndef FB_ASSERTIONS_ENABLED
|
||||
#define FB_ASSERTIONS_ENABLED 1
|
||||
#endif
|
||||
|
||||
#if FB_ASSERTIONS_ENABLED
|
||||
#define CSS_ABORT() abort()
|
||||
#else
|
||||
#define CSS_ABORT()
|
||||
#endif
|
||||
|
||||
#ifndef CSS_ASSERT
|
||||
#define CSS_ASSERT(X, message) \
|
||||
if (!(X)) { \
|
||||
CSSLog(CSSLogLevelError, "%s", message); \
|
||||
CSS_ABORT(); \
|
||||
}
|
||||
#endif
|
@@ -1,104 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#include "CSSNodeList.h"
|
||||
|
||||
extern CSSMalloc gCSSMalloc;
|
||||
extern CSSRealloc gCSSRealloc;
|
||||
extern CSSFree gCSSFree;
|
||||
|
||||
struct CSSNodeList {
|
||||
uint32_t capacity;
|
||||
uint32_t count;
|
||||
CSSNodeRef *items;
|
||||
};
|
||||
|
||||
CSSNodeListRef CSSNodeListNew(const uint32_t initialCapacity) {
|
||||
const CSSNodeListRef list = gCSSMalloc(sizeof(struct CSSNodeList));
|
||||
CSS_ASSERT(list != NULL, "Could not allocate memory for list");
|
||||
|
||||
list->capacity = initialCapacity;
|
||||
list->count = 0;
|
||||
list->items = gCSSMalloc(sizeof(CSSNodeRef) * list->capacity);
|
||||
CSS_ASSERT(list->items != NULL, "Could not allocate memory for items");
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void CSSNodeListFree(const CSSNodeListRef list) {
|
||||
if (list) {
|
||||
gCSSFree(list->items);
|
||||
gCSSFree(list);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t CSSNodeListCount(const CSSNodeListRef list) {
|
||||
if (list) {
|
||||
return list->count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CSSNodeListAdd(CSSNodeListRef *listp, const CSSNodeRef node) {
|
||||
if (!*listp) {
|
||||
*listp = CSSNodeListNew(4);
|
||||
}
|
||||
CSSNodeListInsert(listp, node, (*listp)->count);
|
||||
}
|
||||
|
||||
void CSSNodeListInsert(CSSNodeListRef *listp, const CSSNodeRef node, const uint32_t index) {
|
||||
if (!*listp) {
|
||||
*listp = CSSNodeListNew(4);
|
||||
}
|
||||
CSSNodeListRef list = *listp;
|
||||
|
||||
if (list->count == list->capacity) {
|
||||
list->capacity *= 2;
|
||||
list->items = gCSSRealloc(list->items, sizeof(CSSNodeRef) * list->capacity);
|
||||
CSS_ASSERT(list->items != NULL, "Could not extend allocation for items");
|
||||
}
|
||||
|
||||
for (uint32_t i = list->count; i > index; i--) {
|
||||
list->items[i] = list->items[i - 1];
|
||||
}
|
||||
|
||||
list->count++;
|
||||
list->items[index] = node;
|
||||
}
|
||||
|
||||
CSSNodeRef CSSNodeListRemove(const CSSNodeListRef list, const uint32_t index) {
|
||||
const CSSNodeRef removed = list->items[index];
|
||||
list->items[index] = NULL;
|
||||
|
||||
for (uint32_t i = index; i < list->count - 1; i++) {
|
||||
list->items[i] = list->items[i + 1];
|
||||
list->items[i + 1] = NULL;
|
||||
}
|
||||
|
||||
list->count--;
|
||||
return removed;
|
||||
}
|
||||
|
||||
CSSNodeRef CSSNodeListDelete(const CSSNodeListRef list, const CSSNodeRef node) {
|
||||
for (uint32_t i = 0; i < list->count; i++) {
|
||||
if (list->items[i] == node) {
|
||||
return CSSNodeListRemove(list, i);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CSSNodeRef CSSNodeListGet(const CSSNodeListRef list, const uint32_t index) {
|
||||
if (CSSNodeListCount(list) > 0) {
|
||||
return list->items[index];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "CSSLayout.h"
|
||||
#include "CSSMacros.h"
|
||||
|
||||
CSS_EXTERN_C_BEGIN
|
||||
|
||||
typedef struct CSSNodeList *CSSNodeListRef;
|
||||
|
||||
CSSNodeListRef CSSNodeListNew(const uint32_t initialCapacity);
|
||||
void CSSNodeListFree(const CSSNodeListRef list);
|
||||
uint32_t CSSNodeListCount(const CSSNodeListRef list);
|
||||
void CSSNodeListAdd(CSSNodeListRef *listp, const CSSNodeRef node);
|
||||
void CSSNodeListInsert(CSSNodeListRef *listp, const CSSNodeRef node, const uint32_t index);
|
||||
CSSNodeRef CSSNodeListRemove(const CSSNodeListRef list, const uint32_t index);
|
||||
CSSNodeRef CSSNodeListDelete(const CSSNodeListRef list, const CSSNodeRef node);
|
||||
CSSNodeRef CSSNodeListGet(const CSSNodeListRef list, const uint32_t index);
|
||||
|
||||
CSS_EXTERN_C_END
|
@@ -1,59 +0,0 @@
|
||||
# Copyright (c) 2014-present, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the BSD-style license found in the
|
||||
# LICENSE file in the root directory of this source tree. An additional grant
|
||||
# of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
include_defs('//CSSLAYOUT_DEFS')
|
||||
|
||||
UIKIT_CSSLAYOUT_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',
|
||||
]
|
||||
|
||||
apple_library(
|
||||
name = 'CSSLayoutKit',
|
||||
compiler_flags = UIKIT_CSSLAYOUT_COMPILER_FLAGS,
|
||||
tests = [':CSSLayoutKitTests'],
|
||||
srcs = glob(['*.m']),
|
||||
exported_headers = glob(['*.h']),
|
||||
frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/Foundation.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/UIKit.framework',
|
||||
],
|
||||
deps = [
|
||||
csslayout_dep(':CSSLayout'),
|
||||
],
|
||||
visibility = ['PUBLIC'],
|
||||
)
|
||||
|
||||
apple_test(
|
||||
name = 'CSSLayoutKitTests',
|
||||
compiler_flags = UIKIT_CSSLAYOUT_COMPILER_FLAGS,
|
||||
info_plist = 'Tests/Info.plist',
|
||||
srcs = glob(['Tests/**/*.m']),
|
||||
frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/CoreGraphics.framework',
|
||||
'$PLATFORM_DIR/Developer/Library/Frameworks/XCTest.framework',
|
||||
],
|
||||
deps = [
|
||||
':CSSLayoutKit',
|
||||
],
|
||||
visibility = ['PUBLIC'],
|
||||
)
|
@@ -1,271 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "UIView+CSSLayout.h"
|
||||
|
||||
@interface CSSLayoutKitTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation CSSLayoutKitTests
|
||||
|
||||
#ifndef TRAVIS_CI
|
||||
|
||||
- (void)testNodesAreDeallocedWithSingleView
|
||||
{
|
||||
XCTAssertEqual(0, CSSNodeGetInstanceCount());
|
||||
|
||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[view css_setFlexBasis:1];
|
||||
XCTAssertEqual(1, CSSNodeGetInstanceCount());
|
||||
view = nil;
|
||||
|
||||
XCTAssertEqual(0, CSSNodeGetInstanceCount());
|
||||
}
|
||||
|
||||
- (void)testNodesAreDeallocedCascade
|
||||
{
|
||||
XCTAssertEqual(0, CSSNodeGetInstanceCount());
|
||||
|
||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[view css_setFlexBasis:1];
|
||||
|
||||
for (int i=0; i<10; i++) {
|
||||
UIView *subview = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview css_setFlexBasis:1];
|
||||
[view addSubview:subview];
|
||||
}
|
||||
XCTAssertEqual(11, CSSNodeGetInstanceCount());
|
||||
view = nil;
|
||||
|
||||
XCTAssertEqual(0, CSSNodeGetInstanceCount());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
- (void)testUsesFlexbox
|
||||
{
|
||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
XCTAssertFalse([view css_usesFlexbox]);
|
||||
|
||||
[view css_setUsesFlexbox:YES];
|
||||
XCTAssertTrue([view css_usesFlexbox]);
|
||||
|
||||
[view css_setUsesFlexbox:NO];
|
||||
XCTAssertFalse([view css_usesFlexbox]);
|
||||
}
|
||||
|
||||
- (void)testSizeThatFitsAsserts
|
||||
{
|
||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
dispatch_sync(dispatch_queue_create("com.facebook.CSSLayout.testing", DISPATCH_QUEUE_SERIAL), ^(void){
|
||||
XCTAssertThrows([view css_intrinsicSize]);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)testSizeThatFitsSmoke
|
||||
{
|
||||
UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[container css_setUsesFlexbox:YES];
|
||||
[container css_setFlexDirection:CSSFlexDirectionRow];
|
||||
[container css_setAlignItems:CSSAlignFlexStart];
|
||||
|
||||
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 css_setUsesFlexbox:YES];
|
||||
[longTextLabel css_setFlexShrink:1];
|
||||
[container addSubview:longTextLabel];
|
||||
|
||||
UIView *textBadgeView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[textBadgeView css_setUsesFlexbox:YES];
|
||||
[textBadgeView css_setMargin:3.0 forEdge:CSSEdgeLeft];
|
||||
[textBadgeView css_setWidth:10];
|
||||
[textBadgeView css_setHeight:10];
|
||||
[container addSubview:textBadgeView];
|
||||
|
||||
const CGSize containerSize = [container css_intrinsicSize];
|
||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(514,21), containerSize), @"Size is actually %@", NSStringFromCGSize(containerSize));
|
||||
}
|
||||
|
||||
- (void)testFrameAndOriginPlacement
|
||||
{
|
||||
const CGSize containerSize = CGSizeMake(320, 50);
|
||||
|
||||
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)];
|
||||
[container css_setUsesFlexbox:YES];
|
||||
[container css_setFlexDirection:CSSFlexDirectionRow];
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
UIView *subview = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview css_setUsesFlexbox:YES];
|
||||
[subview css_setFlexGrow:1];
|
||||
|
||||
[container addSubview:subview];
|
||||
}
|
||||
[container css_applyLayout];
|
||||
|
||||
XCTAssertFalse(CGRectIntersectsRect([container.subviews objectAtIndex:0].frame, [container.subviews objectAtIndex:1].frame));
|
||||
XCTAssertFalse(CGRectIntersectsRect([container.subviews objectAtIndex:1].frame, [container.subviews objectAtIndex:2].frame));
|
||||
XCTAssertFalse(CGRectIntersectsRect([container.subviews objectAtIndex:0].frame, [container.subviews objectAtIndex:2].frame));
|
||||
|
||||
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 css_setUsesFlexbox:YES];
|
||||
[container css_setFlexDirection:CSSFlexDirectionRow];
|
||||
|
||||
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview1 css_setUsesFlexbox:YES];
|
||||
[subview1 css_setFlexGrow:1];
|
||||
[container addSubview:subview1];
|
||||
|
||||
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview2 css_setUsesFlexbox:YES];
|
||||
[subview2 css_setFlexGrow:1];
|
||||
[container addSubview:subview2];
|
||||
|
||||
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview3 css_setUsesFlexbox:YES];
|
||||
[subview3 css_setFlexGrow:1];
|
||||
[container addSubview:subview3];
|
||||
|
||||
[container css_applyLayout];
|
||||
|
||||
XCTAssertTrue(CGRectEqualToRect(subview1.frame, CGRectMake(0, 0, 100, 50)));
|
||||
XCTAssertTrue(CGRectEqualToRect(subview2.frame, CGRectMake(100, 0, 100, 50)), @"It's actually %@", NSStringFromCGRect(subview2.frame));
|
||||
XCTAssertTrue(CGRectEqualToRect(subview3.frame, CGRectMake(200, 0, 100, 50)));
|
||||
|
||||
[container exchangeSubviewAtIndex:2 withSubviewAtIndex:0];
|
||||
[subview2 css_setIncludeInLayout:NO];
|
||||
[container css_applyLayout];
|
||||
|
||||
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 css_setUsesFlexbox:YES];
|
||||
[container css_setFlexDirection:CSSFlexDirectionRow];
|
||||
|
||||
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview1 css_setUsesFlexbox:YES];
|
||||
[subview1 css_setFlexGrow:1];
|
||||
[container addSubview:subview1];
|
||||
|
||||
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview2 css_setUsesFlexbox:YES];
|
||||
[subview2 css_setFlexGrow:1];
|
||||
[container addSubview:subview2];
|
||||
|
||||
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview3 css_setUsesFlexbox:YES];
|
||||
[subview3 css_setFlexGrow:1];
|
||||
[container addSubview:subview3];
|
||||
|
||||
[container css_applyLayout];
|
||||
|
||||
for (UIView *view in container.subviews) {
|
||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(100, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(view.bounds.size));
|
||||
}
|
||||
|
||||
[subview3 css_setIncludeInLayout:NO];
|
||||
[container css_applyLayout];
|
||||
|
||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview1.bounds.size));
|
||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview2.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview2.bounds.size));
|
||||
|
||||
// We don't set the frame to zero, so, it should be set to what it was previously at.
|
||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(100, 50), subview3.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview3.bounds.size));
|
||||
}
|
||||
|
||||
- (void)testThatNumberOfChildrenIsCorrectWhenWeIgnoreSubviews
|
||||
{
|
||||
UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[container css_setUsesFlexbox:YES];
|
||||
[container css_setFlexDirection:CSSFlexDirectionRow];
|
||||
|
||||
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview1 css_setUsesFlexbox:YES];
|
||||
[subview1 css_setIncludeInLayout:NO];
|
||||
[container addSubview:subview1];
|
||||
|
||||
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview2 css_setUsesFlexbox:YES];
|
||||
[subview2 css_setIncludeInLayout:NO];
|
||||
[container addSubview:subview2];
|
||||
|
||||
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview3 css_setUsesFlexbox:YES];
|
||||
[subview3 css_setIncludeInLayout:YES];
|
||||
[container addSubview:subview3];
|
||||
|
||||
[container css_applyLayout];
|
||||
XCTAssertEqual(1, [container css_numberOfChildren]);
|
||||
|
||||
[subview2 css_setIncludeInLayout:YES];
|
||||
[container css_applyLayout];
|
||||
XCTAssertEqual(2, [container css_numberOfChildren]);
|
||||
}
|
||||
|
||||
- (void)testThatViewNotIncludedInFirstLayoutPassAreIncludedInSecond
|
||||
{
|
||||
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)];
|
||||
[container css_setUsesFlexbox:YES];
|
||||
[container css_setFlexDirection:CSSFlexDirectionRow];
|
||||
|
||||
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview1 css_setUsesFlexbox:YES];
|
||||
[subview1 css_setFlexGrow:1];
|
||||
[container addSubview:subview1];
|
||||
|
||||
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview2 css_setUsesFlexbox:YES];
|
||||
[subview2 css_setFlexGrow:1];
|
||||
[container addSubview:subview2];
|
||||
|
||||
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview3 css_setUsesFlexbox:YES];
|
||||
[subview3 css_setFlexGrow:1];
|
||||
[subview3 css_setIncludeInLayout:NO];
|
||||
[container addSubview:subview3];
|
||||
|
||||
[container css_applyLayout];
|
||||
|
||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview1.bounds.size));
|
||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview2.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview2.bounds.size));
|
||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeZero, subview3.bounds.size), @"Actual size %@", NSStringFromCGSize(subview3.bounds.size));
|
||||
|
||||
[subview3 css_setIncludeInLayout:YES];
|
||||
[container css_applyLayout];
|
||||
for (UIView *view in container.subviews) {
|
||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(100, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(view.bounds.size));
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
@@ -1,72 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <CSSLayout/CSSLayout.h>
|
||||
|
||||
@interface UIView (CSSLayout)
|
||||
|
||||
/**
|
||||
The property that decides if we should include this view when calculating layout. Defaults to YES.
|
||||
*/
|
||||
@property (nonatomic, readwrite, assign, setter=css_setIncludeInLayout:) BOOL css_includeInLayout;
|
||||
|
||||
/**
|
||||
The property that decides during layout/sizing whether or not css_* properties should be applied. Defaults to NO.
|
||||
*/
|
||||
@property (nonatomic, readwrite, assign, setter=css_setUsesFlexbox:) BOOL css_usesFlexbox;
|
||||
|
||||
- (void)css_setDirection:(CSSDirection)direction;
|
||||
- (void)css_setFlexDirection:(CSSFlexDirection)flexDirection;
|
||||
- (void)css_setJustifyContent:(CSSJustify)justifyContent;
|
||||
- (void)css_setAlignContent:(CSSAlign)alignContent;
|
||||
- (void)css_setAlignItems:(CSSAlign)alignItems;
|
||||
- (void)css_setAlignSelf:(CSSAlign)alignSelf;
|
||||
- (void)css_setPositionType:(CSSPositionType)positionType;
|
||||
- (void)css_setFlexWrap:(CSSWrap)flexWrap;
|
||||
|
||||
- (void)css_setFlexGrow:(CGFloat)flexGrow;
|
||||
- (void)css_setFlexShrink:(CGFloat)flexShrink;
|
||||
- (void)css_setFlexBasis:(CGFloat)flexBasis;
|
||||
|
||||
- (void)css_setPosition:(CGFloat)position forEdge:(CSSEdge)edge;
|
||||
- (void)css_setMargin:(CGFloat)margin forEdge:(CSSEdge)edge;
|
||||
- (void)css_setPadding:(CGFloat)padding forEdge:(CSSEdge)edge;
|
||||
|
||||
- (void)css_setWidth:(CGFloat)width;
|
||||
- (void)css_setHeight:(CGFloat)height;
|
||||
- (void)css_setMinWidth:(CGFloat)minWidth;
|
||||
- (void)css_setMinHeight:(CGFloat)minHeight;
|
||||
- (void)css_setMaxWidth:(CGFloat)maxWidth;
|
||||
- (void)css_setMaxHeight:(CGFloat)maxHeight;
|
||||
|
||||
// Yoga specific properties, not compatible with flexbox specification
|
||||
- (void)css_setAspectRatio:(CGFloat)aspectRatio;
|
||||
|
||||
/**
|
||||
Get the resolved direction of this node. This won't be CSSDirectionInherit
|
||||
*/
|
||||
- (CSSDirection)css_resolvedDirection;
|
||||
|
||||
/**
|
||||
Perform a layout calculation and update the frames of the views in the hierarchy with th results
|
||||
*/
|
||||
- (void)css_applyLayout;
|
||||
|
||||
/**
|
||||
Returns the size of the view if no constraints were given. This could equivalent to calling [self sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];
|
||||
*/
|
||||
- (CGSize)css_intrinsicSize;
|
||||
|
||||
/**
|
||||
Returns the number of children that are using Flexbox.
|
||||
*/
|
||||
- (NSUInteger)css_numberOfChildren;
|
||||
|
||||
@end
|
@@ -1,379 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "UIView+CSSLayout.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@interface CSSNodeBridge : NSObject
|
||||
@property (nonatomic, assign, readonly) CSSNodeRef cnode;
|
||||
@end
|
||||
|
||||
@implementation CSSNodeBridge
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
CSSLayoutSetExperimentalFeatureEnabled(CSSExperimentalFeatureWebFlexBasis, true);
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if ([super init]) {
|
||||
_cnode = CSSNodeNew();
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
CSSNodeFree(_cnode);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation UIView (CSSLayout)
|
||||
|
||||
- (BOOL)css_usesFlexbox
|
||||
{
|
||||
NSNumber *usesFlexbox = objc_getAssociatedObject(self, @selector(css_usesFlexbox));
|
||||
return [usesFlexbox boolValue];
|
||||
}
|
||||
|
||||
- (BOOL)css_includeInLayout
|
||||
{
|
||||
NSNumber *includeInLayout = objc_getAssociatedObject(self, @selector(css_includeInLayout));
|
||||
return (includeInLayout != nil) ? [includeInLayout boolValue] : YES;
|
||||
}
|
||||
|
||||
- (NSUInteger)css_numberOfChildren
|
||||
{
|
||||
return CSSNodeChildCount([self cssNode]);
|
||||
}
|
||||
|
||||
#pragma mark - Setters
|
||||
|
||||
- (void)css_setIncludeInLayout:(BOOL)includeInLayout
|
||||
{
|
||||
objc_setAssociatedObject(
|
||||
self,
|
||||
@selector(css_includeInLayout),
|
||||
@(includeInLayout),
|
||||
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)css_setUsesFlexbox:(BOOL)enabled
|
||||
{
|
||||
objc_setAssociatedObject(
|
||||
self,
|
||||
@selector(css_usesFlexbox),
|
||||
@(enabled),
|
||||
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)css_setDirection:(CSSDirection)direction
|
||||
{
|
||||
CSSNodeStyleSetDirection([self cssNode], direction);
|
||||
}
|
||||
|
||||
- (void)css_setFlexDirection:(CSSFlexDirection)flexDirection
|
||||
{
|
||||
CSSNodeStyleSetFlexDirection([self cssNode], flexDirection);
|
||||
}
|
||||
|
||||
- (void)css_setJustifyContent:(CSSJustify)justifyContent
|
||||
{
|
||||
CSSNodeStyleSetJustifyContent([self cssNode], justifyContent);
|
||||
}
|
||||
|
||||
- (void)css_setAlignContent:(CSSAlign)alignContent
|
||||
{
|
||||
CSSNodeStyleSetAlignContent([self cssNode], alignContent);
|
||||
}
|
||||
|
||||
- (void)css_setAlignItems:(CSSAlign)alignItems
|
||||
{
|
||||
CSSNodeStyleSetAlignItems([self cssNode], alignItems);
|
||||
}
|
||||
|
||||
- (void)css_setAlignSelf:(CSSAlign)alignSelf
|
||||
{
|
||||
CSSNodeStyleSetAlignSelf([self cssNode], alignSelf);
|
||||
}
|
||||
|
||||
- (void)css_setPositionType:(CSSPositionType)positionType
|
||||
{
|
||||
CSSNodeStyleSetPositionType([self cssNode], positionType);
|
||||
}
|
||||
|
||||
- (void)css_setFlexWrap:(CSSWrap)flexWrap
|
||||
{
|
||||
CSSNodeStyleSetFlexWrap([self cssNode], flexWrap);
|
||||
}
|
||||
|
||||
- (void)css_setFlexGrow:(CGFloat)flexGrow
|
||||
{
|
||||
CSSNodeStyleSetFlexGrow([self cssNode], flexGrow);
|
||||
}
|
||||
|
||||
- (void)css_setFlexShrink:(CGFloat)flexShrink
|
||||
{
|
||||
CSSNodeStyleSetFlexShrink([self cssNode], flexShrink);
|
||||
}
|
||||
|
||||
- (void)css_setFlexBasis:(CGFloat)flexBasis
|
||||
{
|
||||
CSSNodeStyleSetFlexBasis([self cssNode], flexBasis);
|
||||
}
|
||||
|
||||
- (void)css_setPosition:(CGFloat)position forEdge:(CSSEdge)edge
|
||||
{
|
||||
CSSNodeStyleSetPosition([self cssNode], edge, position);
|
||||
}
|
||||
|
||||
- (void)css_setMargin:(CGFloat)margin forEdge:(CSSEdge)edge
|
||||
{
|
||||
CSSNodeStyleSetMargin([self cssNode], edge, margin);
|
||||
}
|
||||
|
||||
- (void)css_setPadding:(CGFloat)padding forEdge:(CSSEdge)edge
|
||||
{
|
||||
CSSNodeStyleSetPadding([self cssNode], edge, padding);
|
||||
}
|
||||
|
||||
- (void)css_setWidth:(CGFloat)width
|
||||
{
|
||||
CSSNodeStyleSetWidth([self cssNode], width);
|
||||
}
|
||||
|
||||
- (void)css_setHeight:(CGFloat)height
|
||||
{
|
||||
CSSNodeStyleSetHeight([self cssNode], height);
|
||||
}
|
||||
|
||||
- (void)css_setMinWidth:(CGFloat)minWidth
|
||||
{
|
||||
CSSNodeStyleSetMinWidth([self cssNode], minWidth);
|
||||
}
|
||||
|
||||
- (void)css_setMinHeight:(CGFloat)minHeight
|
||||
{
|
||||
CSSNodeStyleSetMinHeight([self cssNode], minHeight);
|
||||
}
|
||||
|
||||
- (void)css_setMaxWidth:(CGFloat)maxWidth
|
||||
{
|
||||
CSSNodeStyleSetMaxWidth([self cssNode], maxWidth);
|
||||
}
|
||||
|
||||
- (void)css_setMaxHeight:(CGFloat)maxHeight
|
||||
{
|
||||
CSSNodeStyleSetMaxHeight([self cssNode], maxHeight);
|
||||
}
|
||||
|
||||
- (void)css_setAspectRatio:(CGFloat)aspectRatio
|
||||
{
|
||||
CSSNodeStyleSetAspectRatio([self cssNode], aspectRatio);
|
||||
}
|
||||
|
||||
#pragma mark - Layout and Sizing
|
||||
|
||||
- (CSSDirection)css_resolvedDirection
|
||||
{
|
||||
return CSSNodeLayoutGetDirection([self cssNode]);
|
||||
}
|
||||
|
||||
- (void)css_applyLayout
|
||||
{
|
||||
[self calculateLayoutWithSize:self.bounds.size];
|
||||
CSSApplyLayoutToViewHierarchy(self);
|
||||
}
|
||||
|
||||
- (CGSize)css_intrinsicSize
|
||||
{
|
||||
const CGSize constrainedSize = {
|
||||
.width = CSSUndefined,
|
||||
.height = CSSUndefined,
|
||||
};
|
||||
return [self calculateLayoutWithSize:constrainedSize];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (CSSNodeRef)cssNode
|
||||
{
|
||||
CSSNodeBridge *node = objc_getAssociatedObject(self, @selector(cssNode));
|
||||
if (!node) {
|
||||
node = [CSSNodeBridge new];
|
||||
CSSNodeSetContext(node.cnode, (__bridge void *) self);
|
||||
objc_setAssociatedObject(self, @selector(cssNode), node, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
return node.cnode;
|
||||
}
|
||||
|
||||
- (CGSize)calculateLayoutWithSize:(CGSize)size
|
||||
{
|
||||
NSAssert([NSThread isMainThread], @"CSS Layout calculation must be done on main.");
|
||||
NSAssert([self css_usesFlexbox], @"CSS Layout is not enabled for this view.");
|
||||
|
||||
CSSAttachNodesFromViewHierachy(self);
|
||||
|
||||
const CSSNodeRef node = [self cssNode];
|
||||
CSSNodeCalculateLayout(
|
||||
node,
|
||||
size.width,
|
||||
size.height,
|
||||
CSSNodeStyleGetDirection(node));
|
||||
|
||||
return (CGSize) {
|
||||
.width = CSSNodeLayoutGetWidth(node),
|
||||
.height = CSSNodeLayoutGetHeight(node),
|
||||
};
|
||||
}
|
||||
|
||||
static CSSSize CSSMeasureView(
|
||||
CSSNodeRef node,
|
||||
float width,
|
||||
CSSMeasureMode widthMode,
|
||||
float height,
|
||||
CSSMeasureMode heightMode)
|
||||
{
|
||||
const CGFloat constrainedWidth = (widthMode == CSSMeasureModeUndefined) ? CGFLOAT_MAX : width;
|
||||
const CGFloat constrainedHeight = (heightMode == CSSMeasureModeUndefined) ? CGFLOAT_MAX: height;
|
||||
|
||||
UIView *view = (__bridge UIView*) CSSNodeGetContext(node);
|
||||
const CGSize sizeThatFits = [view sizeThatFits:(CGSize) {
|
||||
.width = constrainedWidth,
|
||||
.height = constrainedHeight,
|
||||
}];
|
||||
|
||||
return (CSSSize) {
|
||||
.width = CSSSanitizeMeasurement(constrainedWidth, sizeThatFits.width, widthMode),
|
||||
.height = CSSSanitizeMeasurement(constrainedHeight, sizeThatFits.height, heightMode),
|
||||
};
|
||||
}
|
||||
|
||||
static CGFloat CSSSanitizeMeasurement(
|
||||
CGFloat constrainedSize,
|
||||
CGFloat measuredSize,
|
||||
CSSMeasureMode measureMode)
|
||||
{
|
||||
CGFloat result;
|
||||
if (measureMode == CSSMeasureModeExactly) {
|
||||
result = constrainedSize;
|
||||
} else if (measureMode == CSSMeasureModeAtMost) {
|
||||
result = MIN(constrainedSize, measuredSize);
|
||||
} else {
|
||||
result = measuredSize;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void CSSAttachNodesFromViewHierachy(UIView *view) {
|
||||
CSSNodeRef node = [view cssNode];
|
||||
|
||||
// Only leaf nodes should have a measure function
|
||||
if (![view css_usesFlexbox] || view.subviews.count == 0) {
|
||||
CSSNodeSetMeasureFunc(node, CSSMeasureView);
|
||||
CSSRemoveAllChildren(node);
|
||||
} else {
|
||||
CSSNodeSetMeasureFunc(node, NULL);
|
||||
|
||||
// Create a list of all the subviews that we are going to use for layout.
|
||||
NSMutableArray<UIView *> *subviewsToInclude = [[NSMutableArray alloc] initWithCapacity:view.subviews.count];
|
||||
for (UIView *subview in view.subviews) {
|
||||
if ([subview css_includeInLayout]) {
|
||||
[subviewsToInclude addObject:subview];
|
||||
}
|
||||
}
|
||||
|
||||
BOOL shouldReconstructChildList = NO;
|
||||
if (CSSNodeChildCount(node) != subviewsToInclude.count) {
|
||||
shouldReconstructChildList = YES;
|
||||
} else {
|
||||
for (int i = 0; i < subviewsToInclude.count; i++) {
|
||||
if (CSSNodeGetChild(node, i) != [subviewsToInclude[i] cssNode]) {
|
||||
shouldReconstructChildList = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldReconstructChildList) {
|
||||
CSSRemoveAllChildren(node);
|
||||
|
||||
for (int i = 0 ; i < subviewsToInclude.count; i++) {
|
||||
UIView *const subview = subviewsToInclude[i];
|
||||
CSSNodeInsertChild(node, [subview cssNode], i);
|
||||
CSSAttachNodesFromViewHierachy(subview);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CSSRemoveAllChildren(const CSSNodeRef node)
|
||||
{
|
||||
if (node == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (CSSNodeChildCount(node) > 0) {
|
||||
CSSNodeRemoveChild(node, CSSNodeGetChild(node, CSSNodeChildCount(node) - 1));
|
||||
}
|
||||
}
|
||||
|
||||
static CGFloat CSSRoundPixelValue(CGFloat value)
|
||||
{
|
||||
static CGFloat scale;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^(){
|
||||
scale = [UIScreen mainScreen].scale;
|
||||
});
|
||||
|
||||
return round(value * scale) / scale;
|
||||
}
|
||||
|
||||
static void CSSApplyLayoutToViewHierarchy(UIView *view) {
|
||||
NSCAssert([NSThread isMainThread], @"Framesetting should only be done on the main thread.");
|
||||
if (![view css_includeInLayout]) {
|
||||
return;
|
||||
}
|
||||
|
||||
CSSNodeRef node = [view cssNode];
|
||||
const CGPoint topLeft = {
|
||||
CSSNodeLayoutGetLeft(node),
|
||||
CSSNodeLayoutGetTop(node),
|
||||
};
|
||||
|
||||
const CGPoint bottomRight = {
|
||||
topLeft.x + CSSNodeLayoutGetWidth(node),
|
||||
topLeft.y + CSSNodeLayoutGetHeight(node),
|
||||
};
|
||||
|
||||
view.frame = (CGRect) {
|
||||
.origin = {
|
||||
.x = CSSRoundPixelValue(topLeft.x),
|
||||
.y = CSSRoundPixelValue(topLeft.y),
|
||||
},
|
||||
.size = {
|
||||
.width = CSSRoundPixelValue(bottomRight.x) - CSSRoundPixelValue(topLeft.x),
|
||||
.height = CSSRoundPixelValue(bottomRight.y) - CSSRoundPixelValue(topLeft.y),
|
||||
},
|
||||
};
|
||||
|
||||
const BOOL isLeaf = ![view css_usesFlexbox] || view.subviews.count == 0;
|
||||
if (!isLeaf) {
|
||||
for (NSUInteger i = 0; i < view.subviews.count; i++) {
|
||||
CSSApplyLayoutToViewHierarchy(view.subviews[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
BSD License
|
||||
|
||||
For css-layout software
|
||||
For yoga software
|
||||
|
||||
Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||
|
||||
|
9
LICENSE-examples
Normal file
@@ -0,0 +1,9 @@
|
||||
The examples provided by Facebook are for non-commercial testing and evaluation
|
||||
purposes only. Facebook reserves all rights not expressly granted.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
2
PATENTS
@@ -1,6 +1,6 @@
|
||||
Additional Grant of Patent Rights Version 2
|
||||
|
||||
"Software" means the CSS Layout software distributed by Facebook, Inc.
|
||||
"Software" means the yoga software distributed by Facebook, Inc.
|
||||
|
||||
Facebook, Inc. (“Facebook”) hereby grants to each recipient of the Software
|
||||
(“you”) a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
|
||||
|
167
README.md
@@ -1,159 +1,40 @@
|
||||
# CSSLayout [](https://travis-ci.org/facebook/css-layout)
|
||||
# Yoga [](http://cocoapods.org/pods/YogaKit) [](https://www.npmjs.com/package/yoga-layout) [](https://bintray.com/facebook/maven/com.facebook.yoga%3Ayoga/_latestVersion) [](https://www.nuget.org/packages/Facebook.Yoga)
|
||||
|
||||
## Goals
|
||||
CSSLayout is a cross-platform implementation of flexbox. The goal of CSSLayout is allow native developers to have the same expressive layout system as developers developing for the modern web are used to. CSSLayout allows developers for web, android, iOS, and windows to use the same layout primitives across platforms. This saves time, increases collaboration between platform teams, and makes it easier for developers to work on multiple platforms.
|
||||
[](https://travis-ci.org/facebook/yoga)
|
||||
[](https://travis-ci.org/facebook/yoga)
|
||||
[](https://travis-ci.org/facebook/yoga)
|
||||
[](https://travis-ci.org/facebook/yoga)
|
||||
[](https://travis-ci.org/facebook/yoga)
|
||||
[](https://travis-ci.org/facebook/yoga)
|
||||
|
||||
The goal of CSSLayout is not to re-implement all of css. CSSLayout only targets flexbox, and does not have any plans on implementing support for tables, floats, or any other css concepts. CSSLayout also does not plan on supporting styling properties which do not affect layout such as color or background properties.
|
||||
[]()
|
||||
[]()
|
||||
|
||||
## 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.
|
||||
|
||||
## Differences from web
|
||||
CSSLayout tries to stay as close as possible to the web implementation of flexbox. There are however certain cases where CSSLayout differs from the web implementation.
|
||||
## 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`.
|
||||
|
||||
### Default values
|
||||
CSSLayout has chosen to make changes to the default values of certain properties. These default values were chosen based on our usage of the library. When testing layout with tools such as JSFiddle you can apply the following css style to ensure the defaults match those of CSSLayout. Or fork the [following JSFiddle](http://jsfiddle.net/vjeux/y11txxv9/).
|
||||
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`.
|
||||
|
||||
```css
|
||||
div, span {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
flex-shrink: 0;
|
||||
align-content: flex-start;
|
||||
|
||||
border: 0 solid black;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
```
|
||||
|
||||
- `box-sizing: border-box` is the most convenient way to express the relation between `width` and `borderWidth`.
|
||||
- Everything is `display: flex` by default. All the behaviors of `block` and `inline-block` can be expressed in term of `flex` but not the opposite.
|
||||
- All the flex elements are oriented from top to bottom, left to right and do not shrink. This is how things are laid out using the default CSS settings and what you'd expect.
|
||||
- Everything is `position: relative`. This makes `position: absolute` target the direct parent and not some parent which is either `relative` or `absolute`. If you want to position an element relative to something else, you should move it in the DOM instead of relying of CSS. It also makes `top, left, right, bottom` do something when not specifying `position: absolute`.
|
||||
|
||||
### Size units
|
||||
CSSLayout currently only supports pixel sizes. The reason being that we have not seen the need for any other units. We would like to support percentage units sometime in the future.
|
||||
|
||||
### -start and -end properties
|
||||
We think supporting RTL locales is very important. Therefor CSSLayout supports non-standards -start and -end suffixed versions of margin, padding, border, and position.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
### C
|
||||
The full API can be found in `CSSLayout/CSSLayout.h`.
|
||||
|
||||
```c
|
||||
CSSNodeRef root = CSSNodeNew();
|
||||
CSSNodeStyleSetWidth(root, 100);
|
||||
CSSNodeStyleSetHeight(root, 100);
|
||||
|
||||
for (uint32_t i = 0; i < 10; i++) {
|
||||
CSSNodeRef child = CSSNodeNew();
|
||||
CSSNodeStyleSetHeight(child, 10);
|
||||
CSSNodeInsertChild(root, child, 0);
|
||||
}
|
||||
|
||||
CSSNodeCalculateLayout(root, CSSUndefined, CSSUndefined, CSSDirectionLTR);
|
||||
|
||||
// Get for resulting layout
|
||||
CSSNodeLayoutGetLeft(root);
|
||||
CSSNodeLayoutGetTop(root);
|
||||
CSSNodeLayoutGetWidth(root);
|
||||
CSSNodeLayoutGetHeight(root);
|
||||
```
|
||||
|
||||
### Java
|
||||
The full API can be found in `java/com/facebook/csslayout/CSSNode.java`.
|
||||
|
||||
```java
|
||||
CSSNode root = new CSSNode();
|
||||
root.setStyleWidth(100);
|
||||
root.setStyleHeight(100);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
CSSNode child = new CSSNode();
|
||||
child.setStyleHeight(10);
|
||||
root.addChildAt(child, 0);
|
||||
}
|
||||
|
||||
root.calculateLayout(new CSSLayoutContext());
|
||||
|
||||
// Get for resulting layout
|
||||
root.getLayoutX();
|
||||
root.getLayoutY();
|
||||
root.getLayoutWidth();
|
||||
root.getLayoutHeight();
|
||||
```
|
||||
|
||||
### UIKit
|
||||
The full API can be found in `CSSLayoutKit/UIView+CSSLayout.h`.
|
||||
|
||||
```objective-c
|
||||
UIView *root = [UIView new];
|
||||
[root css_setUsesFlexbox:YES];
|
||||
[root css_setWidth:100];
|
||||
[root css_setHeight:100];
|
||||
|
||||
for (NSUInteger i = 0; i < 10; i++) {
|
||||
UIView *child = [UIView new];
|
||||
[child css_setUsesFlexbox:YES];
|
||||
[child css_setHeight:10];
|
||||
[root addSubview:child];
|
||||
}
|
||||
|
||||
// Resulting layout will be set on the UIView hierarchy frames.
|
||||
[root css_applyLayout];
|
||||
```
|
||||
|
||||
### .NET
|
||||
The full API can be found in `csharp/Facebook.CSSLayout/CSSNode.cs`.
|
||||
|
||||
```csharp
|
||||
var root = new CSSNode();
|
||||
root.StyleWidth = 100;
|
||||
root.StyleHeight = 100;
|
||||
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
var child = new CSSNode();
|
||||
child.StyleHeight = 10;
|
||||
root.Insert(0, child);
|
||||
}
|
||||
|
||||
// Get for resulting layout
|
||||
root.LayoutX;
|
||||
root.LayoutY;
|
||||
root.LayoutWidth;
|
||||
root.LayoutHeight;
|
||||
```
|
||||
|
||||
## Contributing
|
||||
To contribute to CSSLayout you need to first install [buck](https://buckbuild.com) which is the build system used by CSSLayout. CSSLayout is implemented in C with language bindings for Java, Objective-C, and .NET. When making changes to `CSSLayout/CSSLayout.h` please ensure to update `java/jni/CSSJNI.h`, `java/com/facebook/csslayout/CSSNode.java`, `uikit/CSSLayout/UIView+CSSLayout.m`, and `csharp/Facebook.CSSLayout/CSSNode.cs` to reflect the API change. Before submitting any code please run `format.sh` to ensure the code matches the project's code style.
|
||||
|
||||
Before making any larger changes to CSSLayout please open an issue with a RFC so the changes can be discussed first. Generally we are very open to changes and improvements that will benefit the community.
|
||||
|
||||
### Testing
|
||||
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 at least one test to ensure we don't break anything in the future. Tests are located in `tests/CSSLayoutTest.cpp`. Run the tests by executing `buck test //:CSSLayout`.
|
||||
|
||||
Instead of manually writing a test which ensures parity with web implementations of flexbox you can run `gentest/gentest.rb` to generated a test for you. You can write html which you want to verify in CSSLayout, in `gentest/fixtures` folder, such as the following.
|
||||
Instead of manually writing a test which ensures parity with web implementations of Flexbox you can run `gentest/gentest.rb` to generated 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 style="width: 100px; height: 100px; align-items: center;">
|
||||
<div id="my_test" style="width: 100px; height: 100px; align-items: center;">
|
||||
<div style="width: 50px; height: 50px;"></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Run `gentest/gentest.rb` to generate test code and re-run `buck test //:CSSLayout` to validate the behavior. One test case will be generated for every root `div` in the input html.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
#### .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.CSSLayout/test_macos.sh`.
|
||||
### .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`.
|
||||
|
||||
### Benchmarks
|
||||
Benchmarks are located in `benchmarks/CSSBenchmark.c` and can be run with `buck run //benchmarks:benchmarks`. If you think your change has affected performance please run this before and after your change to validate that nothing has regressed.
|
||||
## Code style
|
||||
For the main C implementation of Yoga clang-format is used to ensure a consistent code style. Please run `bash format.sh` before submitting a pull request. For other languages just try to follow the current code style.
|
||||
|
||||
## 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.
|
||||
|
47
YOGA_DEFS
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
YOGA_ROOTS = ['//...']
|
||||
JAVA_TARGET = '//java:java'
|
||||
INFER_ANNOTATIONS_TARGET = '//lib/infer-annotations:infer-annotations'
|
||||
JSR_305_TARGET = '//lib/jsr-305:jsr-305'
|
||||
JUNIT_TARGET = '//lib/junit:junit'
|
||||
PROGRUARD_ANNOTATIONS_TARGET = '//java/proguard-annotations/src/main/java/com/facebook/proguard/annotations:annotations'
|
||||
SOLOADER_TARGET = '//lib/soloader:soloader'
|
||||
GTEST_TARGET = '//lib/gtest:gtest'
|
||||
JNI_TARGET = '//lib/jni:jni'
|
||||
FBJNI_TARGET = '//lib/fb:fbjni'
|
||||
FBJNI_JAVA_TARGET = '//lib/fb/src/main/java/com/facebook/jni:jni'
|
||||
APPCOMPAT_TARGET = '//lib/appcompat:appcompat'
|
||||
ANDROID_SUPPORT_TARGET = '//lib/android-support:android-support'
|
||||
ANDROID_TARGET = '//android:android'
|
||||
ANDROID_JAVA_TARGET = '//android/src/main/java/com/facebook/yoga/android:android'
|
||||
ANDROID_RES_TARGET = '//android:res'
|
||||
ANDROID_SAMPLE_JAVA_TARGET = '//android/sample/java/com/facebook/samples/yoga:yoga'
|
||||
ANDROID_SAMPLE_RES_TARGET = '//android/sample:res'
|
||||
|
||||
THIS_IS_FBOBJC = False
|
||||
|
||||
CXX_LIBRARY_WHITELIST = [
|
||||
'//:yoga',
|
||||
'//lib/fb:fbjni',
|
||||
'//java:jni',
|
||||
]
|
||||
|
||||
BASE_COMPILER_FLAGS = [
|
||||
'-fno-omit-frame-pointer',
|
||||
'-fexceptions',
|
||||
'-Wall',
|
||||
'-Werror',
|
||||
'-O3',
|
||||
]
|
||||
|
||||
LIBRARY_COMPILER_FLAGS = BASE_COMPILER_FLAGS + [
|
||||
'-fPIC',
|
||||
]
|
||||
|
||||
def yoga_dep(dep):
|
||||
return '//' + dep
|
||||
|
||||
with allow_unsafe_import():
|
||||
import os.path
|
||||
def isdir(filename):
|
||||
return os.path.isdir(filename)
|
28
Yoga.podspec
Normal file
@@ -0,0 +1,28 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = 'Yoga'
|
||||
spec.version = '1.3.0'
|
||||
spec.license = { :type => 'BSD', :file => "LICENSE" }
|
||||
spec.homepage = 'https://facebook.github.io/yoga/'
|
||||
spec.documentation_url = 'https://facebook.github.io/yoga/docs/api/c/'
|
||||
|
||||
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 => '1.3.0',
|
||||
}
|
||||
|
||||
spec.module_name = 'yoga'
|
||||
spec.requires_arc = false
|
||||
spec.compiler_flags = [
|
||||
'-fno-omit-frame-pointer',
|
||||
'-fexceptions',
|
||||
'-Wall',
|
||||
'-Werror',
|
||||
'-std=c11',
|
||||
'-fPIC'
|
||||
]
|
||||
spec.source_files = 'yoga/**/*.{c,h}'
|
||||
end
|
29
YogaKit.podspec
Normal file
@@ -0,0 +1,29 @@
|
||||
podspec = Pod::Spec.new do |spec|
|
||||
spec.name = 'YogaKit'
|
||||
spec.version = '1.3.0'
|
||||
spec.license = { :type => 'BSD', :file => "LICENSE" }
|
||||
spec.homepage = 'https://facebook.github.io/yoga/'
|
||||
spec.documentation_url = 'https://facebook.github.io/yoga/docs/api/yogakit/'
|
||||
|
||||
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 => '1.3.0',
|
||||
}
|
||||
|
||||
spec.platform = :ios
|
||||
spec.ios.deployment_target = '7.0'
|
||||
spec.ios.frameworks = 'UIKit'
|
||||
|
||||
spec.dependency 'Yoga', '~> 1.3'
|
||||
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'
|
||||
end
|
||||
|
||||
# See https://github.com/facebook/yoga/pull/366
|
||||
podspec.attributes_hash["readme"] = "YogaKit/README.md"
|
||||
podspec
|
1
YogaKit/.swift-version
Normal file
@@ -0,0 +1 @@
|
||||
3.0.2
|
58
YogaKit/BUCK
Normal file
@@ -0,0 +1,58 @@
|
||||
# Copyright (c) 2014-present, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the BSD-style license found in the
|
||||
# LICENSE file in the root directory of this source tree. An additional grant
|
||||
# of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
include_defs("//YOGA_DEFS")
|
||||
|
||||
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",
|
||||
]
|
||||
|
||||
apple_library(
|
||||
name = "YogaKit",
|
||||
srcs = glob(["Source/**/*.m"]),
|
||||
compiler_flags = COMPILER_FLAGS,
|
||||
exported_headers = glob(["Source/**/*.h"]),
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
"$SDKROOT/System/Library/Frameworks/UIKit.framework",
|
||||
],
|
||||
visibility = ["PUBLIC"],
|
||||
deps = [
|
||||
yoga_dep(":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",
|
||||
],
|
||||
)
|
46
YogaKit/CHANGELOG.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# CHANGELOG
|
||||
|
||||
The changelog for `YogaKit`.
|
||||
|
||||
1.2.0 (**upcoming release**)
|
||||
-----
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- `applyLayout()` has now been changed to `applyLayout(preservingOrigin:)`.
|
||||
|
||||
- Computed properties are no longer reflected in getter's of the affected properties.
|
||||
```swift
|
||||
// OLD
|
||||
view.yoga.margin = 10
|
||||
view.yoga.marginTop // 10
|
||||
view.yoga.marginLeft // 10
|
||||
|
||||
// NEW
|
||||
view.yoga.margin = 10
|
||||
view.yoga.marginTop // 0
|
||||
view.yoga.marginLeft // 0
|
||||
```
|
||||
|
||||
### Enhancements
|
||||
|
||||
- Pixel Rounding now uses `roundf()` instead of `round()`.
|
||||
|
||||
- There is now a method that allows "bulk" updates to YGLayout.
|
||||
```objc
|
||||
[view configureLayoutWithBlock:^(YGLayout *layout) {
|
||||
layout.isEnabled = YES;
|
||||
layout.width = 50;
|
||||
layout.height = 50;
|
||||
}];
|
||||
```
|
||||
|
||||
```swift
|
||||
view.configureLayout { (layout) in
|
||||
layout.isEnabled = true
|
||||
layout.width = 50
|
||||
layout.height = 50
|
||||
}
|
||||
```
|
||||
|
||||
- Added new `isDirty` property, and make `markDirty` a little more performant.
|
22
YogaKit/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# YogaKit
|
||||
|
||||
[](https://cocoapods.org/pods/YogaKit)
|
||||
[](https://facebook.github.io/yoga/docs/api/yogakit/)
|
||||
[](https://facebook.github.io/yoga/docs/api/yogakit/)
|
||||
|
||||
## Installation
|
||||
YogaKit is available to install via [CocoaPods](https://cocoapods.org/).
|
||||
|
||||
```
|
||||
pod 'YogaKit', '~> 1.3'
|
||||
```
|
||||
|
||||
## 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.
|
34
YogaKit/Source/UIView+Yoga.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "YGLayout.h"
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void (^YGLayoutConfigurationBlock)(YGLayout *);
|
||||
|
||||
@interface UIView (Yoga)
|
||||
|
||||
/**
|
||||
The YGLayout that is attached to this view. It is lazily created.
|
||||
*/
|
||||
@property (nonatomic, readonly, strong) YGLayout *yoga;
|
||||
|
||||
/**
|
||||
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
|
36
YogaKit/Source/UIView+Yoga.m
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
- (void)configureLayoutWithBlock:(YGLayoutConfigurationBlock)block
|
||||
{
|
||||
if (block != nil) {
|
||||
block(self.yoga);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
19
YogaKit/Source/YGLayout+Private.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import "YGLayout.h"
|
||||
#import <yoga/Yoga.h>
|
||||
|
||||
@interface YGLayout ()
|
||||
|
||||
@property (nonatomic, assign, readonly) YGNodeRef node;
|
||||
|
||||
- (instancetype)initWithView:(UIView *)view;
|
||||
|
||||
@end
|
145
YogaKit/Source/YGLayout.h
Normal file
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <yoga/YGEnums.h>
|
||||
#import <yoga/Yoga.h>
|
||||
|
||||
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");
|
||||
|
||||
typedef NS_OPTIONS(NSInteger, YGDimensionFlexibility) {
|
||||
YGDimensionFlexibilityFlexibleWidth = 1 << 0,
|
||||
YGDimensionFlexibilityFlexibleHeigth = 1 << 1,
|
||||
};
|
||||
|
||||
@interface YGLayout : NSObject
|
||||
|
||||
/**
|
||||
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 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 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
|
444
YogaKit/Source/YGLayout.m
Normal file
@@ -0,0 +1,444 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#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 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_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 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;
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
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 (YGNodeGetMeasureFunc(node) == NULL) {
|
||||
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, flexGrow, FlexGrow)
|
||||
YG_PROPERTY(CGFloat, flexShrink, FlexShrink)
|
||||
YG_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_VALUE_PROPERTY(width, Width)
|
||||
YG_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 & YGDimensionFlexibilityFlexibleHeigth) {
|
||||
size.height = YGUndefined;
|
||||
}
|
||||
[self calculateLayoutWithSize:size];
|
||||
YGApplyLayoutToViewHierarchy(self.view, preserveOrigin);
|
||||
}
|
||||
|
||||
|
||||
- (CGSize)intrinsicSize
|
||||
{
|
||||
const CGSize constrainedSize = {
|
||||
.width = YGUndefined,
|
||||
.height = YGUndefined,
|
||||
};
|
||||
return [self calculateLayoutWithSize:constrainedSize];
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
- (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),
|
||||
};
|
||||
}
|
||||
|
||||
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);
|
||||
const CGSize 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.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;
|
||||
}
|
||||
|
||||
while (YGNodeGetChildCount(node) > 0) {
|
||||
YGNodeRemoveChild(node, YGNodeGetChild(node, YGNodeGetChildCount(node) - 1));
|
||||
}
|
||||
}
|
||||
|
||||
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
|
46
YogaKit/Source/YGLayoutExtensions.swift
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
742
YogaKit/Tests/YogaKitTests.m
Normal file
@@ -0,0 +1,742 @@
|
||||
/**
|
||||
* Copyright (c) 2014-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
#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)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:YGDimensionFlexibilityFlexibleHeigth];
|
||||
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 | YGDimensionFlexibilityFlexibleHeigth];
|
||||
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
|
6
YogaKit/YogaKitSample/Podfile
Normal file
@@ -0,0 +1,6 @@
|
||||
use_frameworks!
|
||||
|
||||
target 'YogaKitSample' do
|
||||
pod 'YogaKit', :path => '../../YogaKit.podspec'
|
||||
pod 'IGListKit', '~> 2.1.0'
|
||||
end
|
26
YogaKit/YogaKitSample/Podfile.lock
Normal 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.3.0)
|
||||
- YogaKit (1.3.0):
|
||||
- Yoga (~> 1.3)
|
||||
|
||||
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
|
522
YogaKit/YogaKitSample/YogaKitSample.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,522 @@
|
||||
// !$*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 */;
|
||||
}
|
7
YogaKit/YogaKitSample/YogaKitSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:YogaKitSample.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
@@ -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>
|
10
YogaKit/YogaKitSample/YogaKitSample.xcworkspace/contents.xcworkspacedata
generated
Normal 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>
|
27
YogaKit/YogaKitSample/YogaKitSample/AppDelegate.swift
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
@@ -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"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 868 B |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 2.7 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 8.5 KiB |
After Width: | Height: | Size: 4.5 KiB |
After Width: | Height: | Size: 7.4 KiB |
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
100
YogaKit/YogaKitSample/YogaKitSample/ExamplesViewController.swift
Normal 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)
|
||||
}
|
||||
}
|
36
YogaKit/YogaKitSample/YogaKitSample/Info.plist
Normal 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>
|
@@ -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
|
||||
}
|
||||
}
|
56
YogaKit/YogaKitSample/YogaKitSample/ViewController.m
Normal 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
|
@@ -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)
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
@@ -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
|
||||
}
|
||||
}
|
32
android/BUCK
Normal file
@@ -0,0 +1,32 @@
|
||||
# Copyright (c) 2014-present, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the BSD-style license found in the
|
||||
# LICENSE file in the root directory of this source tree. An additional grant
|
||||
# of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
include_defs("//YOGA_DEFS")
|
||||
|
||||
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,
|
||||
],
|
||||
)
|
||||
|
||||
android_resource(
|
||||
name = "res",
|
||||
package = "com.facebook.yoga.android",
|
||||
res = "src/main/res",
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
)
|
21
android/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# YogaLayout [](https://facebook.github.io/yoga/docs/api/android/) [](https://facebook.github.io/yoga/docs/api/android/) [](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.
|
45
android/build.gradle
Normal file
@@ -0,0 +1,45 @@
|
||||
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 {
|
||||
compile 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')
|
5
android/gradle.properties
Normal file
@@ -0,0 +1,5 @@
|
||||
GROUP=com.facebook.yoga.android
|
||||
POM_NAME=YogaLayout
|
||||
POM_DESCRIPTION=YogaLayout
|
||||
POM_ARTIFACT_ID=yoga-layout
|
||||
POM_PACKAGING=aar
|
54
android/sample/AndroidManifest.xml
Normal 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>
|
35
android/sample/BUCK
Normal file
@@ -0,0 +1,35 @@
|
||||
# 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.
|
||||
|
||||
include_defs("//YOGA_DEFS")
|
||||
|
||||
android_binary(
|
||||
name = "sample",
|
||||
keystore = ":debug_keystore",
|
||||
manifest = "AndroidManifest.xml",
|
||||
deps = [
|
||||
ANDROID_SAMPLE_JAVA_TARGET,
|
||||
ANDROID_SAMPLE_RES_TARGET,
|
||||
],
|
||||
)
|
||||
|
||||
android_resource(
|
||||
name = "res",
|
||||
package = "com.facebook.samples.yoga",
|
||||
res = "res",
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
deps = [
|
||||
ANDROID_RES_TARGET,
|
||||
],
|
||||
)
|
||||
|
||||
keystore(
|
||||
name = "debug_keystore",
|
||||
properties = "debug.keystore.properties",
|
||||
store = "debug.keystore",
|
||||
)
|
BIN
android/sample/debug.keystore
Normal file
3
android/sample/debug.keystore.properties
Normal file
@@ -0,0 +1,3 @@
|
||||
key.alias=androiddebugkey
|
||||
key.store.password=android
|
||||
key.alias.password=android
|
23
android/sample/java/com/facebook/samples/yoga/BUCK
Normal file
@@ -0,0 +1,23 @@
|
||||
# Copyright (c) 2014-present, Facebook, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This source code is licensed under the BSD-style license found in the
|
||||
# LICENSE file in the root directory of this source tree. An additional grant
|
||||
# of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
include_defs("//YOGA_DEFS")
|
||||
|
||||
android_library(
|
||||
name = "yoga",
|
||||
srcs = glob(["**/*.java"]),
|
||||
visibility = [
|
||||
"PUBLIC",
|
||||
],
|
||||
deps = [
|
||||
ANDROID_JAVA_TARGET,
|
||||
ANDROID_SAMPLE_RES_TARGET,
|
||||
ANDROID_SUPPORT_TARGET,
|
||||
APPCOMPAT_TARGET,
|
||||
SOLOADER_TARGET,
|
||||
],
|
||||
)
|
@@ -0,0 +1,113 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,193 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,110 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
@@ -0,0 +1,74 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
@@ -0,0 +1,75 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
@@ -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.
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
17
android/sample/res/drawable/action_bar_background.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle"
|
||||
>
|
||||
<solid
|
||||
android:color="@color/yoga_grey"
|
||||
/>
|
||||
</shape>
|
BIN
android/sample/res/drawable/ic_launcher.png
Normal file
After Width: | Height: | Size: 28 KiB |
34
android/sample/res/drawable/sample_children_background.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle"
|
||||
>
|
||||
|
||||
<corners
|
||||
android:radius="4dp"
|
||||
/>
|
||||
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/children_stroke"
|
||||
/>
|
||||
|
||||
<padding
|
||||
android:top="6dp"
|
||||
android:bottom="6dp"
|
||||
android:left="8dp"
|
||||
android:right="8dp"
|
||||
/>
|
||||
|
||||
<solid
|
||||
android:color="@color/children_background"
|
||||
/>
|
||||
</shape>
|
50
android/sample/res/layout/benchmark_fragment.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<YogaLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:yoga="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/rt"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="column"
|
||||
>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_height="50dp"
|
||||
>
|
||||
<Button
|
||||
android:id="@+id/btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="Run benchmark"
|
||||
yoga:yg_flex="1"
|
||||
/>
|
||||
<Spinner
|
||||
android:id="@+id/benchmarkSelect"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:spinnerMode="dropdown"
|
||||
/>
|
||||
</VirtualYogaLayout>
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:textSize="10sp"
|
||||
android:fontFamily="monospace"
|
||||
yoga:yg_flex="1"
|
||||
/>
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="2dp"
|
||||
android:background="@color/yoga_grey"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:id="@+id/preview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:orientation="horizontal"
|
||||
/>
|
||||
</YogaLayout>
|
30
android/sample/res/layout/benchmark_layout_1.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<YogaLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:yoga="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_alignItems="center"
|
||||
>
|
||||
<View
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:background="@color/yoga_blue"
|
||||
yoga:yg_flex="0"
|
||||
yoga:yg_marginAll="5dp"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/child_1_text"
|
||||
yoga:yg_flex="0"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/child_2_text"
|
||||
yoga:yg_flex="1"
|
||||
yoga:yg_marginHorizontal="5dp"
|
||||
/>
|
||||
</YogaLayout>
|
28
android/sample/res/layout/benchmark_layout_1_linear.xml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
>
|
||||
<ImageView
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_margin="5dp"
|
||||
android:src="@drawable/ic_launcher"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/child_1_text"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:text="@string/child_2_text"
|
||||
/>
|
||||
</LinearLayout>
|
104
android/sample/res/layout/benchmark_layout_2.xml
Normal file
@@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<YogaLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:yoga="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
yoga:yg_flexDirection="column"
|
||||
yoga:yg_alignItems="stretch"
|
||||
>
|
||||
<View
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_blue"
|
||||
yoga:yg_flex="1"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:height="40dp"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_alignItems="stretch"
|
||||
>
|
||||
<View
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_blue"
|
||||
yoga:yg_marginAll="10dp"
|
||||
yoga:yg_aspectRatio="1"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:height="40dp"
|
||||
yoga:yg_flexDirection="column"
|
||||
yoga:yg_alignItems="stretch"
|
||||
yoga:yg_flex="1"
|
||||
yoga:yg_justifyContent="space_around"
|
||||
>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:height="8dp"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_alignItems="stretch"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/child_1_text"
|
||||
android:textSize="5sp"
|
||||
yoga:yg_flex="1"
|
||||
/>
|
||||
<View
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_blue"
|
||||
yoga:yg_aspectRatio="1"
|
||||
/>
|
||||
</VirtualYogaLayout>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:height="8dp"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_alignItems="stretch"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/child_1_text"
|
||||
android:textSize="5sp"
|
||||
yoga:yg_flex="1"
|
||||
/>
|
||||
<View
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_blue"
|
||||
yoga:yg_aspectRatio="1"
|
||||
/>
|
||||
</VirtualYogaLayout>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:height="8dp"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_alignItems="stretch"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/child_1_text"
|
||||
android:textSize="5sp"
|
||||
yoga:yg_flex="1"
|
||||
/>
|
||||
<View
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_blue"
|
||||
yoga:yg_aspectRatio="1"
|
||||
/>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</YogaLayout>
|
96
android/sample/res/layout/benchmark_layout_2_linear.xml
Normal file
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:yoga="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_launcher"
|
||||
android:background="@color/yoga_blue"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<View
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:src="@drawable/ic_launcher"
|
||||
android:background="@color/yoga_blue"
|
||||
android:layout_margin="10dp"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="40dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="8dp"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="4dp"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/child_1_text"
|
||||
android:textSize="5sp"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
<View
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
android:src="@drawable/ic_launcher"
|
||||
android:background="@color/yoga_blue"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="8dp"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="4dp"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/child_1_text"
|
||||
android:textSize="5sp"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
<View
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
android:src="@drawable/ic_launcher"
|
||||
android:background="@color/yoga_blue"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="8dp"
|
||||
android:orientation="horizontal"
|
||||
android:layout_marginTop="4dp"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/child_1_text"
|
||||
android:textSize="5sp"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
<View
|
||||
android:layout_width="8dp"
|
||||
android:layout_height="8dp"
|
||||
android:src="@drawable/ic_launcher"
|
||||
android:background="@color/yoga_blue"
|
||||
/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
206
android/sample/res/layout/benchmark_layout_3.xml
Normal file
@@ -0,0 +1,206 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<YogaLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:yoga="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_alignItems="center"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_justifyContent="center"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_blue"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="column"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_grey"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_grey"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_blue"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_grey"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_grey"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="column"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_blue"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_grey"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_grey"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_blue"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_grey"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="column"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_grey"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_blue"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_grey"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/yoga_grey"
|
||||
yoga:yg_marginLeft="10dp"
|
||||
/>
|
||||
<VirtualYogaLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_flex="1"
|
||||
>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</VirtualYogaLayout>
|
||||
</YogaLayout>
|
204
android/sample/res/layout/benchmark_layout_3_linear.xml
Normal file
@@ -0,0 +1,204 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_blue"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_grey"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_grey"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_blue"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_grey"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_grey"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_blue"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_grey"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_grey"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_blue"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_grey"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_grey"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_blue"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_grey"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:background="@color/yoga_grey"
|
||||
/>
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal"
|
||||
>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
7
android/sample/res/layout/benchmark_select_layout.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<android.support.v4.view.ViewPager
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/viewpager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
137
android/sample/res/layout/main_layout.xml
Normal file
@@ -0,0 +1,137 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<YogaLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:yoga="http://schemas.android.com/apk/res/com.facebook.samples.yoga"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
>
|
||||
<YogaLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/sample_children_background"
|
||||
yoga:yg_marginHorizontal="10dp"
|
||||
yoga:yg_marginTop="5dp"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_alignItems="center"
|
||||
>
|
||||
<ImageView
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:src="@drawable/ic_launcher"
|
||||
yoga:yg_flex="0"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/child_1_text"
|
||||
android:textColor="@color/children_text"
|
||||
yoga:yg_flex="1"
|
||||
yoga:yg_marginStart="8dp"
|
||||
/>
|
||||
</YogaLayout>
|
||||
<YogaLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/sample_children_background"
|
||||
yoga:yg_marginHorizontal="10dp"
|
||||
yoga:yg_marginTop="5dp"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_alignItems="center"
|
||||
>
|
||||
<ImageView
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:src="@drawable/ic_launcher"
|
||||
yoga:yg_flex="0"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/child_2_text"
|
||||
android:textColor="@color/children_text"
|
||||
yoga:yg_flex="1"
|
||||
yoga:yg_marginStart="8dp"
|
||||
/>
|
||||
</YogaLayout>
|
||||
<YogaLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/sample_children_background"
|
||||
yoga:yg_marginHorizontal="10dp"
|
||||
yoga:yg_marginTop="5dp"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_alignItems="center"
|
||||
>
|
||||
<ImageView
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:src="@drawable/ic_launcher"
|
||||
yoga:yg_flex="0"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/child_3_text"
|
||||
android:textColor="@color/children_text"
|
||||
yoga:yg_flex="1"
|
||||
yoga:yg_marginStart="8dp"
|
||||
/>
|
||||
</YogaLayout>
|
||||
<YogaLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/sample_children_background"
|
||||
yoga:yg_marginHorizontal="10dp"
|
||||
yoga:yg_marginTop="5dp"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_alignItems="center"
|
||||
>
|
||||
<ImageView
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:src="@drawable/ic_launcher"
|
||||
yoga:yg_flex="0"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/child_4_text"
|
||||
android:textColor="@color/children_text"
|
||||
yoga:yg_flex="1"
|
||||
yoga:yg_marginStart="8dp"
|
||||
/>
|
||||
</YogaLayout>
|
||||
<YogaLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/sample_children_background"
|
||||
yoga:yg_marginHorizontal="10dp"
|
||||
yoga:yg_marginTop="5dp"
|
||||
yoga:yg_flexDirection="row"
|
||||
yoga:yg_alignItems="center"
|
||||
>
|
||||
<ImageView
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:src="@drawable/ic_launcher"
|
||||
yoga:yg_flex="0"
|
||||
/>
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/child_5_text"
|
||||
android:textColor="@color/children_text"
|
||||
yoga:yg_flex="1"
|
||||
yoga:yg_marginStart="10dp"
|
||||
/>
|
||||
</YogaLayout>
|
||||
</YogaLayout>
|
19
android/sample/res/menu/action_bar_benchmark.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
>
|
||||
<item
|
||||
android:id="@+id/action_home"
|
||||
android:title="Home"
|
||||
android:showAsAction="always"
|
||||
/>
|
||||
</menu>
|
19
android/sample/res/menu/action_bar_home.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
>
|
||||
<item
|
||||
android:id="@+id/action_benchmark"
|
||||
android:title="Benchmark"
|
||||
android:showAsAction="always"
|
||||
/>
|
||||
</menu>
|
20
android/sample/res/values/colors.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<color name="yoga_grey">#FF303846</color>
|
||||
<color name="yoga_blue">#FF97DCCF</color>
|
||||
|
||||
<color name="children_background">#FFFFFFFF</color>
|
||||
<color name="children_stroke">#665890ff</color>
|
||||
<color name="children_text">#FF23355b</color>
|
||||
|
||||
</resources>
|
33
android/sample/res/values/strings.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="app_name">Yoga</string>
|
||||
<string
|
||||
name="child_1_text"
|
||||
description="Placeholder text for the first element in the layout"
|
||||
>Hello. I am Yoga!</string>
|
||||
<string
|
||||
name="child_2_text"
|
||||
description="Placeholder text for the second element in the layout"
|
||||
>I am a layout engine!</string>
|
||||
<string
|
||||
name="child_3_text"
|
||||
description="Placeholder text for the third element in the layout"
|
||||
>I run natively.</string>
|
||||
<string
|
||||
name="child_4_text"
|
||||
description="Placeholder text for the fourth element in the layout"
|
||||
>So I\'m fast.</string>
|
||||
<string
|
||||
name="child_5_text"
|
||||
description="Placeholder text for the fifth element in the layout"
|
||||
>Who are you?</string>
|
||||
</resources>
|
23
android/sample/res/values/styles.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<style name="NoTitleBarWhiteBG" parent="Theme.AppCompat.Light">
|
||||
<item name="android:actionBarStyle">@style/MyActionBar</item>
|
||||
<item name="android:textDirection">locale</item>
|
||||
</style>
|
||||
<style name="MyActionBar" parent="Widget.AppCompat.Light.ActionBar">
|
||||
<item name="android:titleTextStyle">@style/MyTitleText</item>
|
||||
<item name="android:background">@drawable/action_bar_background</item>
|
||||
</style>
|
||||
<style name="MyTitleText" parent="TextAppearance.AppCompat.Widget.ActionBar.Title">
|
||||
<item name="android:textColor">@color/yoga_blue</item>
|
||||
</style>
|
||||
</resources>
|
25
android/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (c) 2014-present, Facebook, Inc.
|
||||
All rights reserved.
|
||||
|
||||
This source code is licensed under the BSD-style license found in the
|
||||
LICENSE file in the root directory of this source tree. An additional grant
|
||||
of patent rights can be found in the PATENTS file in the same directory.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.facebook.yoga.android"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0"
|
||||
>
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="15"
|
||||
android:targetSdkVersion="21"
|
||||
/>
|
||||
|
||||
<application/>
|
||||
|
||||
</manifest>
|