Разделы презентаций


Навигация в Android_ от UX до реализации

Содержание

Устанавливайте приложение а ЦифроАрбатможно нажать и получать напоминание о мероприятииобсуждать мероприятиеделиться мероприятием с друзьями

Слайды и текст этой презентации

Слайд 1


Слайд 4Устанавливайте приложение
а ЦифроАрбат
можно нажать

и
получать напоминание о мероприятии
обсуждать мероприятие
делиться мероприятием с друзьями
Устанавливайте приложение а   ЦифроАрбатможно нажать

Слайд 5Навигация в Android
от UX до реализации

Навигация в Androidот UX до реализации

Слайд 6Севастьян Жуков
Android Developer
@seva_zhukov

Севастьян ЖуковAndroid Developer   @seva_zhukov

Слайд 7Новые фичи
Усложнение навигации
Удобный UX

Новые фичиУсложнение навигацииУдобный UX

Слайд 8Навигация — процесс управления некоторым объектом
Навигация в Android — перемещение

между фичами

Навигация — процесс управления некоторым объектомНавигация в Android — перемещение между фичами

Слайд 9Панель навигации
Программная реализация
Навигация
+
=

Панель навигацииПрограммная реализацияНавигация+=

Слайд 10от UX

от UX

Слайд 11Drawer Layout
Tab Navigation
Circle Menu
Classic Menu
Гибридные решения

Drawer LayoutTab NavigationCircle MenuClassic MenuГибридные решения

Слайд 12Drawer Layout
— выдвигающаяся панель сбоку

Доступ к фиче за 2 действия

В

приложении предполагается большое количество важных фич (более 5) и доступ

к ним хотелось бы иметь за минимальное количество шагов




Drawer Layout— выдвигающаяся панель сбокуДоступ к фиче за 2 действияВ приложении предполагается большое количество важных фич (более

Слайд 13+ Много фич на панели
+ Привычно для пользователя
- Сложная настройка
- Сложности доступа на большом

экране (тяжело тянуться пальцем в противоположную сторону экрана)
Drawer Layout

+	Много фич на панели+	Привычно для пользователя-	Сложная настройка-	Сложности доступа на большом экране (тяжело тянуться пальцем в противоположную сторону

Слайд 14Tab Navigation
— панель внизу экрана

Доступ к фиче за 1 действие

Небольшое

количество главных фич (менее 5)

Tab Navigation— панель внизу экранаДоступ к фиче за 1 действиеНебольшое количество главных фич (менее 5)

Слайд 15Tab Navigation
+ Доступ к фиче в один клик

- Возможность разместить на панели

малое количество фич

Tab Navigation+	Доступ к фиче в один клик-	Возможность разместить на панели малое количество фич

Слайд 16Circle Menu
— круглая кнопка в углу для отображения панели

Доступ к

фиче за 2 тапа

Приложение развлекательного портала + большое количество важных

фич (до 9)


Circle Menu— круглая кнопка в углу для отображения панелиДоступ к фиче за 2 тапаПриложение развлекательного портала +

Слайд 17Circle Menu
+ Ярко, оригинально и динамично
+ Большое количество фич (до 9)

- Нагрузка приложения

анимацией
- Кнопка занимает часть контента
- Непривычно пользователю

Circle Menu+	Ярко, оригинально и динамично+	Большое количество фич (до 9)-	Нагрузка приложения анимацией-	Кнопка занимает часть контента-	Непривычно пользователю

Слайд 18Classic Menu
— панель занимает весь экран и содержит в себе

все фичи приложения

Доступ к фиче за 1 тап

Небольшое приложение,
просто для

новичков

Classic Menu— панель занимает весь экран и содержит в себе все фичи приложенияДоступ к фиче за 1

Слайд 19Classic Menu
+ Простота реализации
+ Очевидность использования

- Невозможность перейти к другой фиче, не вернувшись

на главную панель навигации

Classic Menu+	Простота реализации+	Очевидность использования-	Невозможность перейти к другой фиче, не вернувшись на главную панель навигации

Слайд 20Гибридные решения
Невозможно использовать только один вид панели
ВК: много важных фич


Tab + Classic
Lingualeo: 2 логических раздела в одной из фич
Drawer

+ Tab
Гибридные решенияНевозможно использовать только один вид панелиВК: много важных фич Tab + ClassicLingualeo: 2 логических раздела в

Слайд 21Выбираем решение

Выбираем решение

Слайд 22до реализации

до реализации

Слайд 24Set Root
Push
Replace
Clear stack + Add New Screen
Back / BackTo
Change container

транзакции

Set RootPushReplaceClear stack + Add New ScreenBack / BackToChange containerтранзакции

Слайд 25решения
Cicerone
Conductor
Jetpack
MultiStack Navigation Library

решенияCiceroneConductorJetpackMultiStack Navigation Library

Слайд 26FragmentManager
Set Root
fragmentManager.beginTransaction()
.add(R.id.container,

IntroFragment())
.commit()
Replace
fragmentManager.beginTransaction()

.replace(R.id.container, SignInFragment())
.commit()


FragmentManagerSet RootfragmentManager.beginTransaction()        .add(R.id.container, IntroFragment())

Слайд 27FragmentManager
Push = Replace + AddToBackStack
fragmentManager.beginTransaction()

.replace(R.id.container, SignUpFragment())

.addToBackStack(Screen.SIGN_UP)
.commit()
BackTo
supportFragmentManager.popBackStack(Screen.FIRST.name, FragmentManager.POP_BACK_STACK_INCLUSIVE)

Back
supportFragmentManager.popBackStack()


FragmentManagerPush = Replace + AddToBackStackfragmentManager.beginTransaction()          .replace(R.id.container, SignUpFragment())

Слайд 28Clear stack + Set New Screen
for (i in 0 until

fragmentManager.backStackEntryCount) {
fragmentManager.popBackStackImmediate()

}
fragmentManager
.beginTransaction()
.replace(R.id.container, fragment)
.commit()

FragmentManager

Clear stack + Set New Screenfor (i in 0 until fragmentManager.backStackEntryCount) {

Слайд 29FragmentManager
Переход между контейнерами (активити)
startActivity(Intent(this, MainActivity::class.java))

Передача данных между фрагментами
val bundle =

Bundle()
bundle.putString("id", "1")
val postFragment = PostFragment()
postFragment.arguments = bundle

FragmentManagerПереход между контейнерами (активити)startActivity(Intent(this, MainActivity::class.java))Передача данных между фрагментамиval bundle = Bundle()bundle.putString(

Слайд 30FragmentManager.Проблемы
Много кода
Нет сохранения состояния навигатора
Нужно учитывать жизненный цикл контейнера java.lang.IllegalStateException:

Can not perform this action after onSaveInstanceState

FragmentManager.ПроблемыМного кодаНет сохранения состояния навигатораНужно учитывать жизненный цикл контейнера java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

Слайд 31FragmentManager.Решение проблем
Extensions
fun Fragment.setClearScreen(containerId: Int, fragment: Fragment, ) {
for

(i in 0 until fragmentManager!!.backStackEntryCount) {
fragmentManager!!.popBackStackImmediate()

}
fragmentManager!!
.beginTransaction()
.replace(containerId, fragment)
.commit()
}
FragmentManager.Решение проблемExtensionsfun Fragment.setClearScreen(containerId: Int, fragment: Fragment, ) {  for (i in 0 until fragmentManager!!.backStackEntryCount) {

Слайд 32Cicerone

Cicerone

Слайд 33cicerone = Cicerone.create()

fun getNavigatorHolder(): NavigatorHolder {
return cicerone.navigatorHolder
}

fun getRouter():

Router {
return cicerone.router
}
Cicerone

cicerone = Cicerone.create()fun getNavigatorHolder(): NavigatorHolder {  return cicerone.navigatorHolder}fun getRouter(): Router {  return cicerone.router}Cicerone

Слайд 34var navigator = object : SupportFragmentNavigator(supportFragmentManager, R.id.main_container) {
override

fun createFragment(screenKey: String?, data: Any?): Fragment {

return when (screenKey) {
Screen.FIRST.name -> FirstScreen() ...
} ...
}
override fun onResume() {
super.onResume()
App.instance.getNavigatorHolder().setNavigator(navigator)
}
var navigator = object : SupportFragmentNavigator(supportFragmentManager, R.id.main_container) {  override fun createFragment(screenKey: String?, data: Any?): Fragment {

Слайд 35Cicerone
Set Root
getRouter().newRootScreen(Screen.FIRST.name)
Replace
getRouter().replaceScreen(Screen.SECOND.name)
Push
getRouter().navigateTo(Screen.SECOND.name)

CiceroneSet RootgetRouter().newRootScreen(Screen.FIRST.name)ReplacegetRouter().replaceScreen(Screen.SECOND.name)PushgetRouter().navigateTo(Screen.SECOND.name)

Слайд 36Clear stack + Set New Screen
getRouter().newRootScreen(Screen.FIRST.name)
Передача данных между экранами
getRouter().navigateTo(Screen.SECOND.name, data)
BackTo
App.instance.getRouter().backTo(Screen.FIRST.name)


Cicerone

Clear stack + Set New ScreengetRouter().newRootScreen(Screen.FIRST.name)Передача данных между экранамиgetRouter().navigateTo(Screen.SECOND.name, data)BackToApp.instance.getRouter().backTo(Screen.FIRST.name)Cicerone

Слайд 37Cicerone
Back
App.instance.getRouter().exit()
Переход между контейнерами (активити)
getGlobalRouter().navigateTo(Screen.MAIN.name)

CiceroneBackApp.instance.getRouter().exit()Переход между контейнерами (активити)getGlobalRouter().navigateTo(Screen.MAIN.name)

Слайд 38Cicerone
Сохранение состояния навигатора
Транзакции в одну строку
Экраны - не обязательно фрагменты
Дополнительный

код реализации навигации

CiceroneСохранение состояния навигатораТранзакции в одну строкуЭкраны - не обязательно фрагментыДополнительный код реализации навигации

Слайд 39Conductor

Conductor

Слайд 40Router
val router = Conductor.attachRouter(this, auth_container, savedInstanceState)

Set Root
router.setRoot(RouterTransaction.with(IntroController()))

Replace
router.replaceTopController(RouterTransaction.with(SignInController()))
Conductor

Routerval router = Conductor.attachRouter(this, auth_container, savedInstanceState)Set Rootrouter.setRoot(RouterTransaction.with(IntroController()))Replacerouter.replaceTopController(RouterTransaction.with(SignInController()))Conductor

Слайд 41Push
router.pushController(RouterTransaction.with(SignUpController()))

Clear stack + Set New Screen
router.setRoot(RouterTransaction.with(IntroController()))

Back
router.handleBack()


Conductor

Pushrouter.pushController(RouterTransaction.with(SignUpController()))Clear stack + Set New Screenrouter.setRoot(RouterTransaction.with(IntroController()))Backrouter.handleBack()Conductor

Слайд 42Передача данных между экранами
router.pushController(RouterTransaction.with(SignUpController(data)))

BackTo
router.popToTag(TAG)
Переход между контейнерами
startActivity(Intent(this, MainActivity::class.java))



Conductor

Передача данных между экранамиrouter.pushController(RouterTransaction.with(SignUpController(data)))BackTorouter.popToTag(TAG)Переход между контейнерамиstartActivity(Intent(this, MainActivity::class.java))Conductor

Слайд 43Mosby (MVP)
Controller - MvpController
Presenter создается после onCreateView и до onAttach

override

fun onAttach(view: View) {
super.onAttach(view)

presenter.doSomething()
}

Conductor.Интеграция с архитектурой

Mosby (MVP)Controller - MvpControllerPresenter создается после onCreateView и до onAttachoverride fun onAttach(view: View) {

Слайд 44Conductor
Сохранение состояния навигатора
Транзакции в одну строку
Быстрые транзакции
Легко интегрируемая анимация
Не нужна

“ручная” реализация навигации
Ограниченный выбор готовых архитектурных решений

ConductorСохранение состояния навигатораТранзакции в одну строкуБыстрые транзакцииЛегко интегрируемая анимацияНе нужна “ручная” реализация навигацииОграниченный выбор готовых архитектурных решений

Слайд 45Navigation Architecture Component
Fragment1
Fragment2
Fragment3
Navigation Graph
Navigation
NavController

Navigation Architecture ComponentFragment1Fragment2Fragment3Navigation GraphNavigationNavController

Слайд 46Navigation Architecture Component

Navigation Architecture Component

Слайд 47

android:id="@+id/authFragment" android:name="com.memebattle.flexible_control.feature.auth.presentation.AuthFragment"
android:label="fragment_auth"

tools:layout="@layout/fragment_auth" >
android:id="@+id/action_authFragment_to_mainFragment"
app:clearTask="true"
app:destination="@id/mainFragment" />

...

...

Слайд 48class MainActivity : AppCompatActivity() {

lateinit var navController: NavController

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setContentView(R.layout.activity_main)
App.component.inject(this)
navController = Navigation.findNavController(this, R.id.nav_host_global)
navController.navigate(R.id.action_authFragment_to_mainFragment)
}
}

Navigation Architecture Component

class MainActivity : AppCompatActivity() {  lateinit var navController: NavController  override fun onCreate(savedInstanceState: Bundle?) {

Слайд 49Set Root
in Navigation Graph: app:startDestination="@id/authFragment"

Clear stack + Set New Screen
in

action: app:clearTask="true"

Передача данных между экранами
navController.navigate(R.id.mapFragment, args)
Navigation Architecture Component

Set Rootin Navigation Graph: app:startDestination=

Слайд 50Push
navController.navigate(R.id.action_authFragment_to_mainFragment)

Back
navController.popBackStack()
BackTo
navController.popBackStack(R.id.mapFragment, true)



Navigation Architecture Component

Push navController.navigate(R.id.action_authFragment_to_mainFragment)BacknavController.popBackStack()BackTonavController.popBackStack(R.id.mapFragment, true)Navigation Architecture Component

Слайд 51Deep Link
Запуск приложения сразу на нужном экране

Установка Deep Link в

destination


Deep LinkЗапуск приложения сразу на нужном экранеУстановка Deep Link в destination

Слайд 52AndroidManifest.xml





Авто-настройка Intent Filter
Deep Link

AndroidManifest.xml  Авто-настройка Intent FilterDeep Link

Слайд 53Navigation Architecture Components Navigation UI
Автоматическое переключение по стекам
NavigationUI.setupWithNavController(bottomNavigationView, navController)

Стеки экранов

не сохраняются!

Navigation Architecture Components Navigation UIАвтоматическое переключение по стекамNavigationUI.setupWithNavController(bottomNavigationView, navController)Стеки экранов не сохраняются!

Слайд 54Navigation Architecture Component
Наглядный граф навигации
Deep Link
Nested Graph
На графе нельзя описать

переходы назад
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

Navigation Architecture ComponentНаглядный граф навигацииDeep LinkNested GraphНа графе нельзя описать переходы назадjava.lang.IllegalStateException: Can not perform this action

Слайд 55Заряжаем колоды фрагментов
с MultiStack Navigation Library

Заряжаем колоды фрагментовс MultiStack Navigation Library

Слайд 561
2
3
Стэки

123Стэки

Слайд 57tap profile item [profile]
tap news item [profile, news]
tap messages item

[profile, news, messages]
tap news item [profile, messages, news]
Порядок стеков

tap profile item [profile]tap news item [profile, news]tap messages item [profile, news, messages]tap news item [profile, messages,

Слайд 58Спуск по стеку item а
Если стек item а заканчивается, то

происходит спуск по порядку стеков
[profile, news]
[profile]
Pop Screen

Спуск по стеку item аЕсли стек item а заканчивается, то происходит спуск по порядку стеков[profile, news][profile]Pop Screen

Слайд 59Глобальный Push Screen
Есть возможность сделать Push Screen в глобальный контейнер,

оставаясь в локальном бэкстеке
local
global
global
screen
push

Глобальный Push ScreenЕсть возможность сделать Push Screen в глобальный контейнер, оставаясь в локальном бэкстекеlocalglobalglobalscreenpush

Слайд 60class MainActivity : AppCompatActivity() { private lateinit var msFragmentManager:

MSFragmentManager override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) msFragmentManager = MSFragmentManager(supportFragmentManager) msFragmentManager.globalContainerId = R.id.global_container msFragmentManager.addGlobal(MainFragment()) } }

Настройка MSNL.Activity

class MainActivity : AppCompatActivity() {   private lateinit var msFragmentManager: MSFragmentManager   override fun onCreate(savedInstanceState:

Слайд 61class MainActivity : AppCompatActivity() { private lateinit var msFragmentManager:

MSFragmentManager override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) msFragmentManager = MSFragmentManager(supportFragmentManager) msFragmentManager.globalContainerId = R.id.global_container msFragmentManager.addGlobal(MainFragment()) } }

Настройка MSNL.Activity

class MainActivity : AppCompatActivity() {   private lateinit var msFragmentManager: MSFragmentManager   override fun onCreate(savedInstanceState:

Слайд 62class MainActivity : AppCompatActivity() { private lateinit var msFragmentManager:

MSFragmentManager override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) msFragmentManager = MSFragmentManager(supportFragmentManager) msFragmentManager.globalContainerId = R.id.global_container msFragmentManager.addGlobal(MainFragment()) } }

Настройка MSNL.Activity

class MainActivity : AppCompatActivity() {   private lateinit var msFragmentManager: MSFragmentManager   override fun onCreate(savedInstanceState:

Слайд 63class MainActivity : AppCompatActivity() { private lateinit var msFragmentManager:

MSFragmentManager override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) msFragmentManager = MSFragmentManager(supportFragmentManager) msFragmentManager.globalContainerId = R.id.global_container msFragmentManager.addGlobal(MainFragment()) } }

Настройка MSNL.Activity

class MainActivity : AppCompatActivity() {   private lateinit var msFragmentManager: MSFragmentManager   override fun onCreate(savedInstanceState:

Слайд 64class MainActivity : AppCompatActivity() { private lateinit var msFragmentManager:

MSFragmentManager override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) msFragmentManager = MSFragmentManager(supportFragmentManager) msFragmentManager.globalContainerId = R.id.global_container msFragmentManager.addGlobal(MainFragment()) } }

Настройка MSNL.Activity

class MainActivity : AppCompatActivity() {   private lateinit var msFragmentManager: MSFragmentManager   override fun onCreate(savedInstanceState:

Слайд 65override fun onBackPressed() { val fragment =

this.supportFragmentManager
.findFragmentById(R.id.global_container) (fragment as? IOnBackPressed)?.onBackPressed() }

Настройка MSNL.Activity

override fun onBackPressed() {     val fragment = this.supportFragmentManager.findFragmentById(R.id.global_container)     (fragment

Слайд 66class MainFragment : Fragment(), IOnBackPressed { override fun onCreateView(inflater:

LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

val v = inflater.inflate(R.layout.fragment_main, container, false) msFragmentManager.localContainerId = R.id.local_container val fragments = arrayListOf(NewsFragment(), MessagesFragment(), FriendsFragment(), ProfileFragment()) MSNavigation.setupNavigation(msFragmentManager, v.bottomNavigationView, fragments) return v } }

Настройка MSNL.FlowFragment

class MainFragment : Fragment(), IOnBackPressed {   override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?

Слайд 67class MainFragment : Fragment(), IOnBackPressed { override fun onCreateView(inflater:

LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

val v = inflater.inflate(R.layout.fragment_main, container, false) msFragmentManager.localContainerId = R.id.local_container val fragments = arrayListOf(NewsFragment(), MessagesFragment(), FriendsFragment(), ProfileFragment()) MSNavigation.setupNavigation(msFragmentManager, v.bottomNavigationView, fragments) return v } }

Настройка MSNL.FlowFragment

class MainFragment : Fragment(), IOnBackPressed {   override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?

Слайд 68class MainFragment : Fragment(), IOnBackPressed { override fun onCreateView(inflater:

LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

val v = inflater.inflate(R.layout.fragment_main, container, false) msFragmentManager.localContainerId = R.id.local_container val fragments = arrayListOf(NewsFragment(), MessagesFragment(), FriendsFragment(), ProfileFragment()) MSNavigation.setupNavigation(msFragmentManager, v.bottomNavigationView, fragments) return v } }

Настройка MSNL.FlowFragment

class MainFragment : Fragment(), IOnBackPressed {   override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?

Слайд 69class MainFragment : Fragment(), IOnBackPressed { override fun onCreateView(inflater:

LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

val v = inflater.inflate(R.layout.fragment_main, container, false) msFragmentManager.localContainerId = R.id.local_container val fragments = arrayListOf(NewsFragment(), MessagesFragment(), FriendsFragment(), ProfileFragment()) MSNavigation.setupNavigation(msFragmentManager, v.bottomNavigationView, fragments) return v } }

Настройка MSNL.FlowFragment

class MainFragment : Fragment(), IOnBackPressed {   override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View?

Слайд 70Настройка MSNL.FlowFragment
override fun onBackPressed(): Boolean { MSNavigation.onBackPressed()

return true }

Настройка MSNL.FlowFragmentoverride fun onBackPressed(): Boolean {     MSNavigation.onBackPressed()     return true

Слайд 71fun navigate(fragment: Fragment, args: Bundle?)
fun replace(fragment: Fragment, args: Bundle?)
fun navigateGlobal(fragment:

Fragment, args: Bundle?)
fun replaceGlobal(fragment: Fragment, args: Bundle?)
fun add(containerId: Int, fragment:

Fragment)
fun addGlobal(containerId: Int, fragment: Fragment)
fun back()
fun backTo(fragmentTag: String)

MSNL.Методы

fun navigate(fragment: Fragment, args: Bundle?)fun replace(fragment: Fragment, args: Bundle?)fun navigateGlobal(fragment: Fragment, args: Bundle?)fun replaceGlobal(fragment: Fragment, args: Bundle?)fun

Слайд 72Вопросы?
Севастьян Жуков
@seva_zhukov

MSNL

Вопросы?Севастьян Жуков   @seva_zhukovMSNL

Обратная связь

Если не удалось найти и скачать доклад-презентацию, Вы можете заказать его на нашем сайте. Мы постараемся найти нужный Вам материал и отправим по электронной почте. Не стесняйтесь обращаться к нам, если у вас возникли вопросы или пожелания:

Email: Нажмите что бы посмотреть 

Что такое TheSlide.ru?

Это сайт презентации, докладов, проектов в PowerPoint. Здесь удобно  хранить и делиться своими презентациями с другими пользователями.


Для правообладателей

Яндекс.Метрика