Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ウィンドウサイズの変更に強い堅牢な画面の構築 / DroidKaigi 2018

nakamuuu
February 09, 2018

ウィンドウサイズの変更に強い堅牢な画面の構築 / DroidKaigi 2018

DroidKaigi 2018 での発表資料です。 https://droidkaigi.jp/2018/
Room 3 - 2018/02/09 16:50-17:20

【参考資料 / リンク】
<< 前半 : ウィンドウサイズの変更に強いレイアウトの構築 >>
・android:fitsSystemWindows - View | Android Developers
https://developer.android.com/reference/android/view/View.html#attr_android:fitsSystemWindows
・OnApplyWindowInsetsListener (v4 compat library) | Android Developers
https://developer.android.com/reference/android/support/v4/view/OnApplyWindowInsetsListener.html
・View#dispatchApplyWindowInsets | Android Developers
https://developer.android.com/reference/android/view/View.html#dispatchApplyWindowInsets(android.view.WindowInsets)
・ViewGroup#dispatchApplyWindowInsets | Android Developers
https://developer.android.com/reference/android/view/ViewGroup.html#dispatchApplyWindowInsets(android.view.WindowInsets)
・View#onApplyWindowInsets | Android Developers
https://developer.android.com/reference/android/view/View.html#onApplyWindowInsets(android.view.WindowInsets)

<< 後半 : 構成の変更時の画面の状態保持について >>
・Handling Configuration Changes | Android Developers
https://developer.android.com/guide/topics/resources/runtime-changes.html
・guardian/toolargetool | GitHub
https://github.com/guardian/toolargetool
・frankiesardo/Icepick | GitHub
https://github.com/frankiesardo/icepick
・nakamuuu/Retainer | GitHub
https://github.com/nakamuuu/retainer
・StateAwareViewModel - nakamuuu | GitHug Gist
https://gist.github.com/nakamuuu/29d7e358735ab867fb145c210d49f8af
・Of Bundles and ViewModels | ProAndroidDev
https://proandroiddev.com/customizing-the-new-viewmodel-cf28b8a7c5fc

nakamuuu

February 09, 2018
Tweet

More Decks by nakamuuu

Other Decks in Technology

Transcript

  1. 17 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங 04όʔδϣϯ͝ͱʹఆٛʜʁ <dimen name=“status_bar_height”>0dp</dimen> WBMVFTEJNFOTYNM <dimen name=“status_bar_height”>25dp</dimen> WBMVFTWEJNFOTYNM <dimen

    name=“status_bar_height”>24dp</dimen> WBMVFTWEJNFOTYNM val resId = res.getIdentifier(“status_bar_height”, “dimen”, “android”) val statusBarHeight = res.getDimensionPixelSize(resId) γεςϜϦιʔεΛऔಘʜʁ
  2. 31 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங ͋Δ͍͸ʜ PO"QQMZ8JOEPX*OTFUTͰDPOTVNF͠ͳ͍ ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets -> //

    View#onApplyWindowInsets ͷσϑΥϧτͷॲཧΛߦΘͤΔ ViewCompat.onApplyWindowInsets(v, insets) // ௨ৗ͸insets.consumeSystemWindowInsets()Λฦ͕͢ɺ // ࣗ਎Ҏ߱ͷViewʹ΋ΠϯηοτΛ෇༩͍ͨ͠ͷͰinsetsΛͦͷ··ฦ͢ return insets } GJUT4ZTUFN8JOEPXTUSVFͳΒDPOTVNF͞ΕΔ લఏ่͕ΕΔͷͰཚ༻͢Δͱࠞಱͱͦ͠͏ʜ
  3. 32 ΢Οϯυ΢αΠζͷมߋʹڧ͍ϨΠΞ΢τͷߏங εςʔλεόʔͷߴ͞Λऔಘ͢Δ ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets -> statuBarSize =

    insets.systemWindowInsetTop return ViewCompat.onApplyWindowInsets(v, insets) } ͦΕͰ΋GJUT4ZTUFN8JOEPXTͰ͸Ͳ͏ʹ΋Ͱ͖ͳ͍ PS εςʔλεόʔͷྖҬʹESBX͍ͨ͠ ˞/BWJHBUJPO7JFXͷܧঝݩͰ͋Δ4DSJN*OTFUT'SBNF-BZPVU͕޷ྫ
  4. 39 ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ ᶃPO4BWF*OTUBODF4UBUF Ͱอ࣋ class ExampleActivity: AppCompatActivity() { private var

    foo: Foo? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) foo = savedInstanceState?.getParcelable("foo") } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putParcelable("foo", foo) } }
  5. 44 ᶄ'SBHNFOUTFU3FUBJO*OTUBODF USVF Λ༻͍ͯอ࣋ class ExampleActivity: AppCompatActivity() { private var

    retainedFragment: RetainedFragment? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) retainedFragment = getSupportFragmentManager() .findFragmentByTag(“tag") as? RetainedFragment if (retainedFragment == null) { // লུ: RetainedFragmentͷΠϯελϯεΛੜ੒ˍcommit } } } class RetainedFragment: Fragment() { var foo: Foo? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setRetainInstance(true) } } ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ
  6. 46 ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ ඇਪ঑ʜʁ PO3FUBJO$VTUPN/PO$POGJHVSBUJPO*OTUBODF Ͱอ࣋ class ExampleActivity: AppCompatActivity() { private

    var foo: Foo? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) foo = getLastCustomNonConfigurationInstance() as? Foo } override fun onRetainCustomNonConfigurationInstance(): Any? { return foo } }
  7. ᶃ PO4BWF*OTUBODF4UBUF Ͱ#VOEMFʹ֨ೲ͠ɺ PO$SFBUF PO3FTUPSF*OTUBODF4UBUF Ͱ෮ݩ ᶄ TFU3FUBJO*OTUBODF USVF Λݺͼग़ͨ͠'SBHNFOU

    ʹσʔλΛ֨ೲ 48 ࢖͍෼͚Λߟ͑Δ্Ͱ஫ҙ͢΂͖ͳͷ͸ อ࣋ͨ͠σʔλͷʮण໋ʯ ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ
  8. 50 ߏ੒ͷมߋ࣌ͷը໘ͷঢ়ଶอ࣋ʹ͍ͭͯ ᶃ PO4BWF*OTUBODF4UBUF Ͱ#VOEMFʹ֨ೲ͠ɺ PO$SFBUF PO3FTUPSF*OTUBODF4UBUF Ͱ෮ݩ ᶄ TFU3FUBJO*OTUBODF

    USVF Λݺͼग़ͨ͠'SBHNFOU ʹσʔλΛ֨ೲ "DUJWJUZͷഁغͱͱ΋ʹফࣦ͢Δ͕ɺ ଟྔͰεςʔτϑϧͳσʔλΛอ࣋Ͱ͖Δ "DUJWJUZͷελοΫ͕ଘࡏ͢ΔݶΓ࢒Γଓ͚Δ͕ɺ γϦΞϧԽՄೳͳগྔͷσʔλͷΈอ࣋Ͱ͖Δ
  9. 56 ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ ෮ݩՄೳ ෮ݩෆೳ PO4BWF*OTUBODF4UBUF Ͱ อ࣋ TFU3FUBJO*OTUBODF USVF Λ

    ݺͼग़ͨ͠'SBHNFOUͰอ࣋ w՝୊ᶃ௿͍ίετͰޮ཰తʹ'SBHNFOUΛ࢖༻͢Δ ঢ়ଶอ࣋ͷํ๏ʹҠߦ͍ͨ͠ w՝୊ᶄͭͷը໘Ͱण໋͕ҟͳΔͭͷঢ়ଶอ࣋ͷ ख๏Λ༻͍ͨ࣌ͷ੔߹ੑΛ୲อ͍ͨ͠
  10. 57 ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ ՝୊ᶃ௿͍ίετͰޮ཰తʹ'SBHNFOUΛ࢖༻͢Δ ঢ়ଶอ࣋ͷํ๏ʹҠߦ͍ͨ͠ ͜Ε·Ͱ͸΄΅શͯͷը໘ͰGSBOLJFTBSEP*DFQJDLΛ࢖༻ IUUQTHJUIVCDPNGSBOLJFTBSEPJDFQJDL class ExampleActivity: AppCompatActivity() {

    @JvmField @State var foo: Foo? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Icepick.restoreInstanceState(this, savedInstanceState) } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) Icepick.saveInstanceState(this, outState) } }
  11. 59 ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ ՝୊ᶃ௿͍ίετͰޮ཰తʹ'SBHNFOUΛ࢖༻͢Δ ঢ়ଶอ࣋ͷํ๏ʹҠߦ͍ͨ͠ class ExampleActivity: AppCompatActivity() { @JvmField @Retain

    var foo: Foo? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Retainer.bind(this) } } "OOPUBUJPO1SPDFTTPSͰ*DFQJDLͷΑ͏ʹ ϑΟʔϧυͷอ࣋Λߦ͑ΔϥΠϒϥϦΛ࡞੒
  12. ը໘ͷঢ়ଶอ࣋ͷख๏ΛͲ͏ޮՌతʹ࢖͍෼͚Δ͔ 61 TBWFE*OTUBODF4UBUFΛੜ੒࣌ʹ౉ͤΔ 7JFX.PEFM'BDUPSZΛ࡞੒ ˞IUUQTQSPBOESPJEEFWDPNDVTUPNJ[JOHUIFOFXWJFXNPEFMDGCBDGDࢀߟ abstract class StateAwareViewModel(app: Application) :

    AndroidViewModel(app) { abstract fun saveInstanceState(outState: Bundle) abstract fun restoreInstanceState(state: Bundle?) } class StateAwareViewModelFactory( private val application: Application, private val savedInstanceState: Bundle? ) : ViewModelProvider.NewInstanceFactory() { override fun <T : ViewModel> create(modelClass: Class<T>): T { return if (StateAwareViewModel::class.java.isAssignableFrom(modelClass)) { return modelClass.getConstructor(Application::class.java) .newInstance(application) .also { (it as StateAwareViewModel) .restoreInstanceState(savedInstanceState) } } else super.create(modelClass) } }