рдХреИрд╕реЗ рдШреЛрд╖рд┐рдд рддреМрд░ рдкрд░ рдПрдХ рдврд╣рдиреЗ рд╡рд╛рд▓реЗ рдЯреВрд▓рдмрд╛рд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВ



рдореИрдВ рдПрдХ рд╕рдорд╛рдзрд╛рди рдкреНрд░рд╕реНрддреБрдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдХреЛрдб рдкрдардиреАрдпрддрд╛ рдкрд░ рдЬреЛрд░ рджреЗрдиреЗ рдХреЗ рд╕рд╛рде CollapsingToolbar рдХрд╛ рд╡рд░реНрдгрди рдХреИрд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рд▓реЗрдЦ рдпрд╣ рдирд╣реАрдВ рдмрддрд╛рдПрдЧрд╛ рдХрд┐ рдЖрдкрдХрд╛ рд╕рдордиреНрд╡рдпрдХ рдХреНрдпрд╛ рд╣реИ рдФрд░ рдХреИрд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реИред рд╡реНрдпрд╡рд╣рд╛рд░ред рдЕрдЧрд░ рдкрд╛рдардХ рдЗрд╕реЗ рд╕рдордЭрдиреЗ рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВ, рддреЛ рдХрдИ рд▓реЗрдЦ рд╣реИрдВ, рдЬрд┐рдирдореЗрдВ рд╣реНрд░реЛрдм рднреА рд╢рд╛рдорд┐рд▓ рд╣реИрдВ ред рдпрджрд┐ рдЖрдк рд╕рдордЭрдирд╛ рдирд╣реАрдВ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдареАрдХ рд╣реИ: рдореИрдВрдиреЗ CollapsingToolbar рдХреА рд╕реНрдкреЗрд▓рд┐рдВрдЧ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА рддрд╛рдХрд┐ рдореИрдВ CoordinatorLayout.Behavior рдФрд░ OnOffsetChangedListener рд╕реЗ рдЕрдореВрд░реНрдд рдХрд░ рд╕рдХреВрдВред

рдорд╛рдорд▓реЗ


  • рдЯреВрд▓рдмрд╛рд░ - рджреГрд╢реНрдпреЛрдВ рдХрд╛ рдПрдХ рд╕реЗрдЯ рдЬрд┐рд╕реЗ рд╣рдо рд╕реНрдХреНрд░реАрди рдХреЗ рд╢реАрд░реНрд╖ рдкрд░ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ (android.widget.Toolbar рдирд╣реАрдВ)ред
  • NestedScroll - рдХреЛрдИ рднреА рд╕реНрдХреНрд░реЙрд▓ рдпреЛрдЧреНрдп рджреГрд╢реНрдп рдЬреЛ AppBarLayout (RecyclerView, NestedScrollView) рд╕реЗ рдЬреБрдбрд╝рд╛ рд╣реЛ рд╕рдХрддрд╛ рд╣реИред

рдЖрдкрдХреЛ рдЕрдкрдирд╛ рдирд┐рд░реНрдгрдп рд▓рд┐рдЦрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рдкрдбрд╝реА


рдореИрдВрдиреЗ "рдЗрдВрдЯрд░рдиреЗрдЯ" рдкрд░ рдХрдИ рджреГрд╖реНрдЯрд┐рдХреЛрдгреЛрдВ рдХреЛ рджреЗрдЦрд╛, рдФрд░ рд▓рдЧрднрдЧ рд╕рднреА рдирд┐рдореНрдирд╛рдиреБрд╕рд╛рд░ рдмрдирд╛рдП рдЧрдП рдереЗ:

  1. AppBarLayout рдХреЗ рд▓рд┐рдП рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдКрдВрдЪрд╛рдИ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рддрд╛ рд╣реИред
  2. CoordinatorLayout.Behavior рд▓рд┐рдЦрд╛ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ, рдХреБрдЫ рдЧрдгрдирд╛рдУрдВ рдХреЗ рд╕рд╛рде (рдХреИрд╢реНрдб рд╡реНрдпреВ рд╣рд╛рдЗрдЯ рдХреЛ рдПрдХ рдЕрдиреНрдп рджреГрд╢реНрдп рдХреЗ рдиреАрдЪреЗ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдорд╛рдЗрдирд╕ рдорд╛рд░реНрдЬрд┐рди рдХреЛ рд╕реНрдХреНрд░реЙрд▓ рд╕реЗ рдЧреБрдгрд╛ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдпрд╣рд╛рдВ рдЧрдгрдирд╛ рдХреА рдЬрд╛рддреА рд╣реИ) рд╡реЗ рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рдХрд╛ рджреГрд╢реНрдп рдмрджрд▓рддреЗ рд╣реИрдВред
  3. рдЕрдиреНрдп рд╡рд┐рдЪрд╛рд░ AppBarLayout рдХреЗ OnOffsetChangedListener рдореЗрдВ рдмрджрд▓рддреЗ рд╣реИрдВред

рдпрд╣рд╛рдБ рд╡рд░реНрдгрд┐рдд рджреГрд╖реНрдЯрд┐рдХреЛрдг рдХреЗ рд╕рд╛рде рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИ , рдЬреАрдердм рдкрд░ 2.5k рд╕рд┐рддрд╛рд░реЗред

рдЙрдореНрдореАрдж

рд╡рд╛рд╕реНрддрд╡рд┐рдХрддрд╛: рдЕрдкрдиреЗ рд╡рдирдкреНрд▓рд╕ рдкрд░ рдбрд╛рд▓реЗрдВ

рдЖрдк рдЗрд╕ рд╕рдорд╛рдзрд╛рди рдХреЗ рд▓рд┐рдП рд▓реЗрдЖрдЙрдЯ рдХреЛ рд╕рд╣реА рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдХреБрдЫ рдФрд░ рдореБрдЭреЗ рднреНрд░рдорд┐рдд рдХрд░рддрд╛ рд╣реИред рдХреБрдЫ рд╡рд┐рдЪрд╛рд░реЛрдВ рдХрд╛ рдкреНрд░рдмрдВрдзрди рдСрдирдСрдлрд╕реЗрдЯрдЪреИрдВрдЬрд▓рд┐рд╕реНрдЯрдирд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рдХреБрдЫ рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ, рдХреБрдЫ рдмреЙрдХреНрд╕ рд╕реЗ рдмрд╛рд╣рд░ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдкреВрд░реА рддрд╕реНрд╡реАрд░ рдХреЛ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП, рдбреЗрд╡рд▓рдкрд░ рдХреЛ рдХрдИ рд╡рд░реНрдЧреЛрдВ рдореЗрдВ рдЬрд╛рдирд╛ рд╣реЛрдЧрд╛, рдФрд░ рдЕрдЧрд░ рдПрдХ рдирдП рджреГрд╢реНрдп рдХреЗ рд▓рд┐рдП рд╡реНрдпрд╡рд╣рд╛рд░ рдХреЛ рдЬреЛрдбрд╝рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдЬреЛ рдЕрдиреНрдп рд╡реНрдпрд╡рд╣рд╛рд░ рдкрд░ рдирд┐рд░реНрднрд░ рдХрд░рддрд╛ рд╣реИ рдФрд░ рдСрдирдСрдлрд╝рд╕реЗрдЯрдЪреИрдирд▓рд┐рд╕реНрдЯрд▓рд┐рд╕реНрдЯ рдореЗрдВ рдмрджрд▓рд╛рд╡ рдкрд░, рдмреИрд╕рд╛рдЦреА рдФрд░ рдХреАрдбрд╝реЗ рдиреАрд▓реЗ рд░рдВрдЧ рд╕реЗ рдмрдврд╝ рд╕рдХрддреЗ рд╣реИрдВ

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдпрд╣ рдЙрджрд╛рд╣рд░рдг рдпрд╣ рдирд╣реАрдВ рджрд┐рдЦрд╛рддрд╛ рд╣реИ рдХрд┐ рдпрджрд┐ рдЯреВрд▓рдмрд╛рд░ рдореЗрдВ рдЗрд╕ рдЯреВрд▓рдмрд╛рд░ рдХреА рдКрдВрдЪрд╛рдИ рдХреЛ рдкреНрд░рднрд╛рд╡рд┐рдд рдХрд░рдиреЗ рд╡рд╛рд▓реЗ рдЕрддрд┐рд░рд┐рдХреНрдд рддрддреНрд╡ рдЬреЛрдбрд╝реЗ рдЬрд╛рддреЗ рд╣реИрдВ рддреЛ рдХреНрдпрд╛ рдХрд░рдирд╛ рд╣реИред

рд▓реЗрдЦ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ gif рдореЗрдВ, рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ TextView рдмрдЯрди рдкрд░ рдХреНрд▓рд┐рдХ рдХрд░рдХреЗ рдХреИрд╕реЗ рдЫрд┐рдкрд╛ рд╣реБрдЖ рд╣реИ - рдФрд░ NestedScroll рдХреЛ рдЕрдзрд┐рдХ рдЦреАрдВрдЪрд╛ рдЬрд╛рддрд╛ рд╣реИ рддрд╛рдХрд┐ рдХреЛрдИ рдЦрд╛рд▓реА рдЬрдЧрд╣ рди рд╣реЛ)ред

рдлрд┐рд░ рд╕реЗ рдЬреАрдЖрдИрдПрдл

рдпрд╣ рдХреИрд╕реЗ рдХрд░рдирд╛ рд╣реИ? рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рджрд┐рдорд╛рдЧ рдореЗрдВ рдЖрдиреЗ рд╡рд╛рд▓реЗ рд╕рдорд╛рдзрд╛рдиреЛрдВ рдореЗрдВ рдПрдХ рдФрд░ рдХреЛрдСрд░реНрдбрд┐рдиреЗрдЯрд░ рд▓рдпрдЖрдЙрдЯ.рдмреЗрд╣рд╡рд┐рдпрд░ рдлреЙрд░ рдиреЗрд╕реНрдЯреНрд╕рдХреНрд░реЛрд▓ (рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд AppBarLayout.Behavior рдХрд╛ рддрд░реНрдХ рд░рдЦрддреЗ рд╣реБрдП) рд▓рд┐рдЦрдирд╛ рдпрд╛ рдЯреВрд▓рдмрд╛рд░ рдХреЛ AppBarLayout рдореЗрдВ рд▓рд┐рдЦрдирд╛ рдФрд░ рдЗрд╕реЗ OnOffsetChangedListener рдореЗрдВ рдмрджрд▓рдирд╛ рд╣реИред рдореИрдВрдиреЗ рджреЛрдиреЛрдВ рд╕рдорд╛рдзрд╛рдиреЛрдВ рдХреА рдХреЛрд╢рд┐рд╢ рдХреА, рдФрд░ рдЗрд╕рдиреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╡рд┐рд╡рд░рдгреЛрдВ рд╕реЗ рдЬреБрдбрд╝рд╛ рдПрдХ рдХреЛрдб рдирд┐рдХрд▓рд╛, рдЬрд┐рд╕реЗ рд╕рдордЭрдирд╛ рдХрд┐рд╕реА рдФрд░ рдХреЗ рд▓рд┐рдП рдХрд╛рдлреА рдореБрд╢реНрдХрд┐рд▓ рд╣реЛрдЧрд╛ рдФрд░ рдЗрд╕рдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдореБрдЭреЗ рдЦреБрд╢реА рд╣реЛрдЧреА рдЕрдЧрд░ рдХреЛрдИ рдРрд╕рд╛ рдЙрджрд╛рд╣рд░рдг рд╕рд╛рдЭрд╛ рдХрд░рддрд╛ рд╣реИ рдЬрд╣рд╛рдВ рдЗрд╕ рддрд░рд╣ рдХреЗ рддрд░реНрдХ рдХреЛ "рд╕рдлрд╛рдИ рд╕реЗ" рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдЕрдм рдореИрдВ рдЕрдкрдирд╛ рд╕рдорд╛рдзрд╛рди рджрд┐рдЦрд╛рдКрдВрдЧрд╛ред рдпрд╣ рд╡рд┐рдЪрд╛рд░ рдПрдХ рдЬрдЧрд╣ рдкрд░ рдШреЛрд╖рд┐рдд рд░реВрдк рд╕реЗ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реИ рдХрд┐ рдХреМрди рд╕реЗ рджреГрд╢реНрдп рдФрд░ рдЙрдиреНрд╣реЗрдВ рдХреИрд╕реЗ рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред

рдЖрдкреА рдХреИрд╕рд╛ рджрд┐рдЦрддрд╛ рд╣реИ?


рддреЛ, рд╕рдордиреНрд╡рдпрдХрд▓реЗрдпрдЖрдЙрдЯ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдПред рд╡реНрдпрд╡рд╣рд╛рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

  • рдЗрдирд╣реЗрд░рд┐рдЯ рдмрд┐рд╣реЗрд╡рд┐рдпрд░рдмрд╛рдпреНрдпреВрд▓реНрд╕;
  • AppBarLayout, CollapsingToolbarLayout рдФрд░ рд╕реНрдХреНрд░реЙрд▓ рд▓рдВрдмрд╛рдИ (AppBarLayout рдКрдВрдЪрд╛рдИ) рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рд╡рд╛рд▓реА рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдУрд╡рд░рд░рд╛рдЗрдб рдХрд░реЗрдВред
  • setUpViews рд╡рд┐рдзрд┐ рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░реЗрдВ - рдирд┐рдпрдореЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВ рдХрд┐ рдРрдкрдмрд╛рд░ рдХреЗ рд╕реНрдХреНрд░реЙрд▓рдмрд╛рд░ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрди рдХреИрд╕реЗ рджрд┐рдЦрд╛рдИ рджреЗрдЧрд╛ред

TopInfoBehavior рдЯреВрд▓рдмрд╛рд░ рдХреЗ рд▓рд┐рдП gif рд╕реЗ рдЖрд▓реЗрдЦ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛ (рдмрд╛рдж рдореЗрдВ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рд╕рдордЭрд╛рдКрдВрдЧрд╛ рдХрд┐ рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ):

рдЦрд╝рд╛рдХрд╛

TopInfoBehavior.kt
class TopInfoBehavior( context: Context?, attrs: AttributeSet? ) : BehaviorByRules(context, attrs) { override fun calcAppbarHeight(child: View): Int = with(child) { return (height + pixels(R.dimen.toolbar_height)).toInt() } override fun View.provideAppbar(): AppBarLayout = ablAppbar override fun View.provideCollapsingToolbar(): CollapsingToolbarLayout = ctlToolbar override fun View.setUpViews(): List<RuledView> = listOf( RuledView( viewGroupTopDetails, BRuleYOffset( min = pixels(R.dimen.zero), max = pixels(R.dimen.toolbar_height) ) ), RuledView( textViewTopDetails, BRuleAlpha(min = 0.6f, max = 1f) .workInRange(from = appearedUntil, to = 1f), BRuleXOffset( min = 0f, max = pixels(R.dimen.big_margin), interpolator = ReverseInterpolator(AccelerateInterpolator()) ), BRuleYOffset( min = pixels(R.dimen.zero), max = pixels(R.dimen.pad), interpolator = ReverseInterpolator(LinearInterpolator()) ), BRuleAppear(0.1f), BRuleScale(min = 0.8f, max = 1f) ), RuledView( textViewPainIsTheArse, BRuleAppear(isAppearedUntil = GONE_VIEW_THRESHOLD) ), RuledView( textViewCollapsedTop, BRuleAppear(0.1f, true) ), RuledView( textViewTop, BRuleAppear(isAppearedUntil = GONE_VIEW_THRESHOLD) ), buildRuleForIcon(ivTop, LinearInterpolator()), buildRuleForIcon(ivTop2, AccelerateInterpolator(0.7f)), buildRuleForIcon(ivTop3, AccelerateInterpolator()) ) private fun View.buildRuleForIcon( view: ImageView, interpolator: Interpolator ) = RuledView( view, BRuleYOffset( min = -(ivTop3.y - tvCollapsedTop.y), max = 0f, interpolator = DecelerateInterpolator(1.5f) ), BRuleXOffset( min = 0f, max = tvCollapsedTop.width.toFloat() + pixels(R.dimen.huge_margin), interpolator = ReverseInterpolator(interpolator) ) ) companion object { const val GONE_VIEW_THRESHOLD = 0.8f } } 


Xml рд▓реЗрдЖрдЙрдЯ (рдкрдардиреАрдпрддрд╛ рдХреЗ рд▓рд┐рдП рд╕реНрдкрд╖реНрдЯ рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдБ рд╣рдЯрд╛ рджреА рдЧрдИ)
 <android.support.design.widget.CoordinatorLayout> <android.support.design.widget.AppBarLayout android:layout_height="wrap_content"> <android.support.design.widget.CollapsingToolbarLayout app:layout_scrollFlags="scroll|exitUntilCollapsed"> <android.support.v7.widget.Toolbar android:layout_height="@dimen/toolbar_height" app:layout_collapseMode="pin"/> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <!--  --> <RelativeLayout android:translationZ="5dp" app:layout_behavior="TopInfoBehavior"/> <android.support.v4.widget.NestedScrollView app:layout_behavior="@string/appbar_scrolling_view_behavior"> </android.support.v4.widget.NestedScrollView> <android.support.design.widget.FloatingActionButton app:layout_anchor="@id/nesteScroll" app:layout_anchorGravity="right"/> </android.support.design.widget.CoordinatorLayout> 


рдпрд╣ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ


рдХрд╛рд░реНрдп рдирд┐рдпрдо рд▓рд┐рдЦрдирд╛ рд╣реИ:

 interface BehaviorRule { /** * @param view to be changed * @param details view's data when first attached * @param ratio in range [0, 1]; 0 when toolbar is collapsed */ fun manage(ratio: Float, details: InitialViewDetails, view: View) } 

рдпрд╣рд╛рдВ рд╕рдм рдХреБрдЫ рд╕реНрдкрд╖реНрдЯ рд╣реИ - 0 рд╕реЗ 1 рддрдХ рдПрдХ рдлреНрд▓реЛрдЯ рдореВрд▓реНрдп рдореЗрдВ рдЖрддрд╛ рд╣реИ, рдПрдХреНрд╢рдирдмрд╛рд░ рд╕реНрдХреНрд░реЙрд▓рд┐рдВрдЧ рдХрд╛ рдкреНрд░рддрд┐рд╢рдд рджрд░реНрд╢рд╛рддрд╛ рд╣реИ, рдПрдХ рджреГрд╢реНрдп рдЖрддрд╛ рд╣реИ рдФрд░ рдЗрд╕рдХреА рдкреНрд░рд╛рд░рдВрднрд┐рдХ рд╕реНрдерд┐рддрд┐ред рдпрд╣ рдЕрдзрд┐рдХ рджрд┐рд▓рдЪрд╕реНрдк рд▓рдЧрддрд╛ рд╣реИ BaseBehaviorRule - рдПрдХ рдирд┐рдпрдо рдЬрд┐рд╕рдореЗрдВ рд╕реЗ рдЕрдиреНрдп рдмреБрдирд┐рдпрд╛рджреА рдирд┐рдпрдо рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓реЗ рд╣реИрдВред

 abstract class BaseBehaviorRule : BehaviorRule { abstract val interpolator: Interpolator abstract val min: Float abstract val max: Float final override fun manage( ratio: Float, details: InitialViewDetails, view: View ) { val interpolation = interpolator.getInterpolation(ratio) val offset = normalize( oldValue = interpolation, newMin = min, newMax = max ) perform(offset, details, view) } /** * @param offset normalized with range from [min] to [max] with [interpolator] */ abstract fun perform(offset: Float, details: InitialViewDetails, view: View) } /** * Affine transform value form one range into another */ fun normalize( oldValue: Float, newMin: Float, newMax: Float, oldMin: Float = 0f, oldMax: Float = 1f ): Float = newMin + ((oldValue - oldMin) * (newMax - newMin)) / (oldMax - oldMin) 

рдмреБрдирд┐рдпрд╛рджреА рдирд┐рдпрдореЛрдВ рдХреЗ рд▓рд┐рдП, рдореВрд▓реНрдпреЛрдВ (рдиреНрдпреВрдирддрдо, рдЕрдзрд┐рдХрддрдо) рдФрд░ рдЗрдВрдЯрд░рдкреЛрд▓рд░ рдХреА рд╕реАрдорд╛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХреА рдЬрд╛рддреА рд╣реИред рдпрд╣ рд▓рдЧрднрдЧ рдХрд┐рд╕реА рднреА рд╡реНрдпрд╡рд╣рд╛рд░ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИред

рдорд╛рди рд▓реЗрдВ рдХрд┐ рд╣рдо рдЕрдкрдиреЗ рджреГрд╢реНрдп рдХреЗ рд▓рд┐рдП рдЕрд▓реНрдлрд╛ рдХреЛ 0.5 рд╕реЗ 0.9 рдХреА рд╕реАрдорд╛ рдореЗрдВ рд╕реЗрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВред рд╣рдо рдпрд╣ рднреА рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдХрд┐ рд╕реНрдХреНрд░реЙрд▓ рджреГрд╢реНрдп рдЬрд▓реНрджреА рд╕реЗ рдкрд╛рд░рджрд░реНрд╢реА рд╣реЛ рдЬрд╛рдП, рдФрд░ рдлрд┐рд░ рдкрд░рд┐рд╡рд░реНрддрди рдХреА рджрд░ рдЧрд┐рд░ рдЬрд╛рдПрдЧреАред
рдирд┐рдпрдо рдЗрд╕ рддрд░рд╣ рджрд┐рдЦреЗрдЧрд╛:

 BRuleAlpha(min = 0.5f, max = 0.9f, interpolator = DecelerateInterpolator()) 

рдФрд░ рдпрд╣рд╛рдБ BRuleAlpha рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╣реИ:

BRuleAlpha.kt
 /** * [min], [max] тАФ values in range [0, 1] */ class BRuleAlpha( override val min: Float, override val max: Float, override val interpolator: Interpolator = LinearInterpolator() ) : BaseBehaviorRule() { override fun perform(offset: Float, details: InitialViewDetails, view: View) { view.alpha = offset } } 


рдФрд░ рдЕрдВрдд рдореЗрдВ, BehaviorByRules рдХреЛрдбред рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЬрд┐рдиреНрд╣реЛрдВрдиреЗ рдЕрдкрдирд╛ рд╡реНрдпрд╡рд╣рд╛рд░ рд▓рд┐рдЦрд╛ рд╣реИ, рд╕рдм рдХреБрдЫ рд╕реНрдкрд╖реНрдЯ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП (рд╕рд┐рд╡рд╛рдп рдЗрд╕рдХреЗ рдХрд┐ рдЕрдВрджрд░ рдХреНрдпрд╛ рд╣реИ)

BehaviorByRules.kt
 abstract class BehaviorByRules( context: Context?, attrs: AttributeSet? ) : CoordinatorLayout.Behavior<View>(context, attrs) { private var views: List<RuledView> = emptyList() private var lastChildHeight = -1 private var needToUpdateHeight: Boolean = true override fun layoutDependsOn( parent: CoordinatorLayout, child: View, dependency: View ): Boolean { return dependency is AppBarLayout } override fun onDependentViewChanged( parent: CoordinatorLayout, child: View, dependency: View ): Boolean { if (views.isEmpty()) views = child.setUpViews() val progress = calcProgress(parent) views.forEach { performRules(offsetView = it, percent = progress) } tryToInitHeight(child, dependency, progress) return true } override fun onMeasureChild( parent: CoordinatorLayout, child: View, parentWidthMeasureSpec: Int, widthUsed: Int, parentHeightMeasureSpec: Int, heightUsed: Int ): Boolean { val canUpdateHeight = canUpdateHeight(calcProgress(parent)) if (canUpdateHeight) { parent.post { val newChildHeight = child.height if (newChildHeight != lastChildHeight) { lastChildHeight = newChildHeight setUpAppbarHeight(child, parent) } } } else { needToUpdateHeight = true } return super.onMeasureChild( parent, child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed ) } /** * If you use fitsSystemWindows=true in your coordinator layout, * you will have to include statusBar height in the appbarHeight */ protected abstract fun calcAppbarHeight(child: View): Int protected abstract fun View.setUpViews(): List<RuledView> protected abstract fun View.provideAppbar(): AppBarLayout protected abstract fun View.provideCollapsingToolbar(): CollapsingToolbarLayout /** * You man not want to update height, if height depends on views, that are currently invisible */ protected open fun canUpdateHeight(progress: Float): Boolean = true private fun calcProgress(parent: CoordinatorLayout): Float { val appBar = parent.provideAppbar() val scrollRange = appBar.totalScrollRange.toFloat() val scrollY = Math.abs(appBar.y) val scroll = 1 - scrollY / scrollRange return when { scroll.isNaN() -> 1f else -> scroll } } private fun setUpAppbarHeight(child: View, parent: ViewGroup) { parent.provideCollapsingToolbar().setHeight(calcAppbarHeight(child)) } private fun tryToInitHeight(child: View, dependency: View, scrollPercent: Float) { if (needToUpdateHeight && canUpdateHeight(scrollPercent)) { setUpAppbarHeight(child, dependency as ViewGroup) needToUpdateHeight = false } } private fun performRules(offsetView: RuledView, percent: Float) { val view = offsetView.view val details = offsetView.details offsetView.rules.forEach { rule -> rule.manage(percent, details, view) } } } 


рддреЛ OnMeasureChild рдХреЗ рд╕рд╛рде рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИ?

рдпрд╣ рдЙрд╕ рд╕рдорд╕реНрдпрд╛ рдХреЛ рд╣рд▓ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИ рдЬреЛ рдореИрдВрдиреЗ рдКрдкрд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд▓рд┐рдЦрд╛ рдерд╛: рдпрджрд┐ рдЯреВрд▓рдмрд╛рд░ рдХрд╛ рдХреБрдЫ рд╣рд┐рд╕реНрд╕рд╛ рдЧрд╛рдпрдм рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ рдиреЗрд╕реНрдЯреНрд╕рдХреНрд░реЛрд▓ рдХреЛ рдЕрдзрд┐рдХ рдЪрд▓рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЗрд╕реЗ рдЙрдЪреНрдЪ рд╕рд╡рд╛рд░реА рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ CollapsingToolbarLayout рдХреА рдКрдВрдЪрд╛рдИ рдХрдо рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

рдПрдХ рдФрд░ рдЧреИрд░-рд╕реНрдкрд╖реНрдЯ рддрд░реАрдХрд╛ рд╣реИ - canUpdateHeightред рдпрд╣ рдЖрд╡рд╢реНрдпрдХ рд╣реИ рддрд╛рдХрд┐ рдЖрдк рдЙрддреНрддрд░рд╛рдзрд┐рдХрд╛рд░реА рдХреЛ рдПрдХ рдирд┐рдпрдо рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗ рд╕рдХреЗрдВ рдЬрдм рдЖрдк рдКрдБрдЪрд╛рдИ рдирд╣реАрдВ рдмрджрд▓ рд╕рдХрддреЗред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рд╡рд╣ рджреГрд╢реНрдп рдЬрд┐рд╕ рдкрд░ рдКрдВрдЪрд╛рдИ рдирд┐рд░реНрднрд░ рдХрд░рддреА рд╣реИ, рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдЫрд┐рдкреА рд╣реБрдИ рд╣реИред рдореБрдЭреЗ рдпрдХреАрди рдирд╣реАрдВ рд╣реИ рдХрд┐ рдпрд╣ рд╕рднреА рдорд╛рдорд▓реЛрдВ рдХреЛ рдХрд╡рд░ рдХрд░реЗрдЧрд╛, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдХрд┐рд╕реА рдХреЗ рдкрд╛рд╕ рдмреЗрд╣рддрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдИ рд╡рд┐рдЪрд╛рд░ рд╣реИ, рддреЛ рдХреГрдкрдпрд╛ рдЯрд┐рдкреНрдкрдгреА рдореЗрдВ рдпрд╛ рд╡реНрдпрдХреНрддрд┐рдЧрдд рд╕рдВрджреЗрд╢ рдореЗрдВ рд▓рд┐рдЦреЗрдВред

рд░реЗрдХ рдХрд┐ рдЖрдк CollapsingToolbarLayout рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рддреЗ рд╕рдордп рдХрджрдо рд░рдЦ рд╕рдХрддреЗ рд╣реИрдВ


  • рдЬрдм рджреГрд╢реНрдп рдмрджрд▓рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ onLayout рд╕реЗ рдмрдЪрдирд╛ рдЪрд╛рд╣рд┐рдПред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рд▓реЗрдЖрдЙрдЯ рдмрджрд▓рдиреЗ рдирд╣реАрдВ рдЪрд╛рд╣рд┐рдП рдпрд╛ рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ рдХреЛрдИ рдкрд╛рда рдмрджрд▓реЗрдВ, рдЕрдиреНрдпрдерд╛ рдкреНрд░рджрд░реНрд╢рди рдореЗрдВ рднрд╛рд░реА рдЧрд┐рд░рд╛рд╡рдЯ рдЖрдПрдЧреАред
  • рдпрджрд┐ рдЖрдк OnOffsetChangedListener рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЯреВрд▓рдмрд╛рд░ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ OnLayout рдФрд░ рднреА рдЦрддрд░рдирд╛рдХ рд╣реИ - OnOffsetChanged рд╡рд┐рдзрд┐ рдЕрдирд┐рд╢реНрдЪрд┐рдд рдХрд╛рд▓ рддрдХ рдЯреНрд░рд┐рдЧрд░ рд╣реЛ рдЬрд╛рдПрдЧреАред
  • CoordinatorLayout.Behavior рдХреЛ рджреГрд╢реНрдп (рд▓реЗрдЖрдЙрдЯрдбреЗрдкреЗрдВрдбреНрд╕рдСрди) рдкрд░ рдирд┐рд░реНрднрд░ рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП, рдЬреЛ рджреГрд╢реНрдпрддрд╛ GONE рдореЗрдВ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЬрдм рдпрд╣ рджреГрд╢реНрдп View.VISIBLE рдкрд░ рд▓реМрдЯрддрд╛ рд╣реИ, рддреЛ рд╡реНрдпрд╡рд╣рд╛рд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдирд╣реАрдВ рдХрд░реЗрдЧрд╛ред
  • рдпрджрд┐ рдЯреВрд▓рдмрд╛рд░ AppBarLayout рдХреЗ рдмрд╛рд╣рд░ рд╣реЛрдЧрд╛, рддреЛ рдЯреВрд▓рдмрд╛рд░ рдХреЛ рдЕрд╡рд░реБрджреНрдз рдХрд░рдиреЗ рд╕реЗ рд░реЛрдХрдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдЯреВрд▓рдмрд╛рд░ рдХреЗ рдореВрд▓ рджреГрд╢реНрдп рд╕рдореВрд╣ рдореЗрдВ Android рд╡рд┐рд╢реЗрд╖рддрд╛: translationZ = "5dp" рдХреЛ рдЬреЛрдбрд╝рдирд╛ рд╣реЛрдЧрд╛ред

рдирд┐рд╖реНрдХрд░реНрд╖ рдореЗрдВ


рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рд╕рдорд╛рдзрд╛рди рд╣реИ рдЬреЛ рдЖрдкрдХреЛ рддрд░реНрдХ рдХреЗ рд╕рд╛рде рдЕрдкрдиреЗ CollapsingToolbarLayout рдХреЛ рдЬрд▓реНрджреА рд╕реЗ рд╕реНрдХреЗрдЪ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ рдЬреЛ рдкрдврд╝рдирд╛ рдФрд░ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдирд╛ рдЕрдкреЗрдХреНрд╖рд╛рдХреГрдд рдЖрд╕рд╛рди рд╣реИред рд╕рднреА рдирд┐рдпрдо рдФрд░ рдирд┐рд░реНрднрд░рддрд╛рдПрдВ рдПрдХ рд╣реА рд╡рд░реНрдЧ рдХреЗ рдврд╛рдВрдЪреЗ рдХреЗ рднреАрддрд░ рдмрдирддреА рд╣реИрдВ - рдХреЛрдСрд░реНрдбрд┐рдиреЗрдЯрд░ рд▓рдпрдЖрдЙрдЯ.рдмреЗрд╣рд╡рд┐рдпрд░ред рдХреЛрдб рдХреЛ рдЬреАрдердм рдкрд░ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

Source: https://habr.com/ru/post/hi426369/


All Articles