Project introduction

Play the Android demo. With Jetpack MVVM development architecture, single Activity multi-fragment project design, the project structure is clear, the code is concise and elegant, the pursuit of the most official way of implementation. Use the following knowledge: LiveData, ViewModel, DataBinding (including two-way binding, use of BindingAdapter), ViewBinding, coroutines (including Flow, suspend, LiveData coroutine constructor, flow coroutine constructor) Use), Hilt, Paging3 (including RemoteMediator, loading state), Room, Navigation (using ViewModel to share data), Banner (kotlin simple implementation), TabLayout, BottomNavigationVi Ew, RecycleView (including ListAdapter, ConcatAdapter, PagingDataAdapter use), ViewPager2, Glide, Cookie, Retrofit2, start page, dark theme, immersive mode, Kotli N higher order functions.

Project screenshot (default theme, dark theme)

Project Reference Demo

  • Sunflower
  • architecture-components-samples
  • views-widgets-samples
  • user-interface-samples
  • architecture-samples
  • Compose -samples: The compose function is not covered in this demo for the time being

Project Knowledge

LiveData

  • LiveData document
  • LiveDataSample:
  • Holding observable classes is similar to EventBus or RxJava. LiveData is a lifecycle aware component
  • LiveData differs from MutableLiveData
  • LiveData use
  • Understand coroutines, LiveData, and Flow
  • Google recommends using Kotlin Flow in the MVVM architecture
  • Demo: GithubBrowserSample[]

ViewModel

  • The ViewModel document
  • ViewModel four integration methods, that is:
    • Saved State in ViewModel — The data of the ViewModel is restored when the background process restarts;
    • Using ViewModel in NavGraph — Integration of ViewModel with Navigation component library
    • ViewModel with data-binding — simplify data binding with ViewModel and LiveData;
    • ViewModelScope — Integration of Kotlin coroutines and ViewModel.
  • In an Activity or FragmentHow to handle the three ways of the ViewModel(Not quite understand)

ViewBinding

  • ViewBinding document

DataBinding

  • DataBinding document
    • Replaces findviewbyId, similar to Butterknife.

coroutines

  • Understand coroutines, LiveData, and Flow
    • The liveData coroutine constructor provides a coroutine code block. This block is the scope of the liveData, which is executed when the liveData is observed, and cancelled when the liveData is no longer in use. Moreover, the coroutine constructor produces an immutable LiveData that can be directly exposed to the corresponding view. The emit() method is used to update the LiveData.
    • A common use case is when the user selects elements in the UI and then displays those selected elements. A common practice is to save the ID of the selected project in a MutableLiveData and then run switchMap. Now in switchMap, you can also use the coroutine constructor:
        private val itemId = MutableLiveData<String>()
        val result = itemId.switchMap {
            liveData { emit(fetchItem(it)) }
        }
    Copy the code
  • Google recommends using Kotlin Flow in the MVVM architecture
  • Schematic coroutine principle

Hilt

  • The hilt and Koin

Paging

  • Paging library 3.0.0 official version has been released. Celebrate! The Paging library helps you load and display data pages from local storage or larger data sets in your network. This approach enables your application to use network bandwidth and system resources more efficiently. The components of the Paging library are designed to fit into the recommended Android application architecture, seamlessly integrate with other Jetpack components, and provide first-class Kotlin support.

  • The official documentation

  • Official demo:

    • PagingSample: demo of the local database
    • PagingWithNetworkSample: Demo of network data
  • The Paging library contains the following functions:

    • Paged data is cached in memory. This feature ensures that your application uses system resources efficiently when processing paging data.
    • Built-in request de-duplication ensures that your application makes efficient use of network bandwidth and system resources.
    • The configurable RecyclerView adapter automatically requests data when the user scrolls to the end of the loaded data.
    • First-class support for Kotlin coroutines and Flow as well as LiveData and RxJava.
    • Built-in support for error handling, including refresh and retry.
  • The Paging component and its integration into the application architecture:

  • Define a data source: The definition of a data source depends on where you load the data from. You simply implement PagingSource or a combination of PagingSource and RemoteMediator:

    • If you load data from a single source, such as network, local data, files, memory cache, etc. (not just network and database, other such as files can also use Paging), implement PagingSource. If you use Room, start with 2.3.0-alpha. It will implement PagingSource for you by default.
    • If you load data from a multi-tiered data source, just like a network data source with a local database cache. Then you need to implement RemoteMediator to merge the two data sources into a PagingSource in the local database cache.
  • PagingSource:

    • PagingSource defines a data source for paging data and how to get the data from that source.
    • LoadParams: Sealed class of PagingSource that contains information about the load operation to be performed, including the key to be loaded and the number of items to be loaded. Used as an argument to the load() function
    • LoadResult: Sealed class of PagingSource that contains the result of the load operation. LoadResult is a sealed class based on whether the load() call was successful. As the return value of the load() function
    • GetRefreshKey () : This method accepts a PagingState object as an argument and returns the key to pass to the load() method when the data is refreshed or invalid after the initial load. The Paging library automatically invokes this method on subsequent data refreshes.
    • Load () : The following figure illustrates how the load() function receives the key for each load and provides the key for subsequent loads:
    • Example code:
          // Customize the PagingSource class
          private const val ARTICLE_STARTING_PAGE_INDEX = 0
      
          class HomeArticlePagingSource(
              private val api: WanJetpackApi
          ) : PagingSource<Int, ApiArticle>() {
      
              override suspend fun load(params: LoadParams<Int>): LoadResult<Int, ApiArticle> {
                  valpage = params.key ? : ARTICLE_STARTING_PAGE_INDEXreturn try {
                      val response = api.getHomeArticle(page)
                      val datas = response.data.datas
                      LoadResult.Page(
                          data = datas,
                          prevKey = if (page == ARTICLE_STARTING_PAGE_INDEX) null else page - 1,
                          nextKey = if (page == response.data.pageCount) null else page + 1)},catch (exception: Exception) {
                      LoadResult.Error(exception)
                  }
              }
      
              override fun getRefreshKey(state: PagingState<Int, ApiArticle>): Int? {
                  return null}}Copy the code
  • PagingData:

    • The container for PagingData is called PagingData, and each time the data is refreshed, an instance of PagingData is created. To create a PagingData data stream, you need to create an instance of Pager and provide a PagingConfig configuration object and a function that tells the Pager how to get an instance of the PagerSource you implement for the Pager to use.
    • The Pager class provides methods to display a responsive stream of the PagingData object from the PagingSource. The Paging library supports the use of multiple Flow types, including Flow, LiveData, and the Flowable and Observable types in RxJava.
    • Pager().flow returns flow . Then in the ViewModel. CachedIn (viewModelScope), the cachedIn() operator makes the data stream shareable and caches the loaded data using the provided CoroutineScope
    • Example code for this rule: (Note: Pager’s remoteMediator parameter is optional.
          //Repository:
          fun getHomeArticle(a): Flow<PagingData<ApiArticle>> {
              return Pager(
                  config = PagingConfig(enablePlaceholders = false, pageSize = HOME_ARTICLE_PAGE_SIZE),
                  pagingSourceFactory = { HomeArticlePagingSource(api) }
              ).flow
          }
      Copy the code
          //ViewModel:
          fun getHomeArticle(a): Flow<PagingData<ApiArticle>> {
              val newResult: Flow<PagingData<ApiArticle>> =
                  repository.getHomeArticle().cachedIn(viewModelScope)
              currentArticleResult = newResult
              return newResult
          }
      Copy the code
  • PagingDataAdapter:

    • You must define onCreateViewHolder() and onBindViewHolder() methods; Specify a ViewHoler and a Diffutil.ItemCallback
    • The related code in Adapter and UI (Activity and Fragment) is omitted.
  • LoadType: an enum class, which contains three states: REFRESH, PREPEND, and APPEND. Used in the LoadParams class of PagingSource.

    • Type of load a [PagingData] can trigger a [PagingSource] to perform.
    • REFRESH: [PagingData] content being refreshed, which can be a result of [PagingSource] invalidation, refresh that may contain content updates, or the initial load.
    • PREPEND: Load at the start of a [PagingData].
    • APPEND: Load at the end of a [PagingData].
  • LoadState: a sealed class.

    • LoadState of a PagedList load-associated with a [LoadType].
    • [LoadState] of any [LoadType] may be observed for UI purposes by registering a listener via [androidx.paging.PagingDataAdapter.addLoadStateListener] or [androidx.paging.AsyncPagingDataDiffer.addLoadStateListener]
    • The Paging library uses the LoadState object to expose the LoadState that can be used on the interface. LoadState takes one of three forms based on the current LoadState:
      • If no loading operation is being performed and there are no errors, LoadState is a LoadState.NotLoading object.
      • If a Loading operation is being performed, LoadState is a loadstate.loading object.
      • If an Error occurs, LoadState is a LoadState.Error object.
  • Three scenarios of loading state: pulldown refresh, pullup load more, first entry to the scroll bar in the middle of the page (and a load failure alert)

  • Display LoadState: you can use LoadState in the interface in two ways: using a listener, and using a special list adapter to display the LoadState directly in the RecyclerView list.

    • Method one, useListener fetchLoad state: To get load state for general use in the interface, the PagingDataAdapter provides addLoadStateListener() and loadStateFlow. Updates from loadStateFlow or addLoadStateListener() ensure synchronization with updates to the interface. This means that if you receive a LoadState notloading.Incomplete, you can be sure that the loading is complete and that the interface has been updated accordingly.
          // The addLoadStateListener mode.
          articleAdapter.addLoadStateListener {
              when (it.refresh) {
                  is LoadState.NotLoading -> {
                      progressBar.visibility = View.INVISIBLE
                      recyclerView.visibility = View.VISIBLE
                  }
                  is LoadState.Loading -> {
                      progressBar.visibility = View.VISIBLE
                      recyclerView.visibility = View.INVISIBLE
                  }
                  is LoadState.Error -> {
                      val state = it.refresh as LoadState.Error
                      progressBar.visibility = View.INVISIBLE
                      Toast.makeText(this."Load Error: ${state.error.message}", Toast.LENGTH_SHORT).show()
                  }
              }
          }
      Copy the code
          / / loadStateFlow way
          // collectLatest is a suspend function, so it is called in a coroutine or another suspend
          lifecycleScope.launch {
            pagingAdapter.loadStateFlow.collectLatest {
              progressBar.isVisible = it.refresh is LoadState.Loading
              retry.isVisible = it.refresh !is LoadState.Loading
              errorMsg.isVisible = it.refresh is LoadState.Error
            }
          }
      Copy the code
    • Method two, useAdapter renderingLoad state: The Paging library provides another list adapter called LoadStateAdapter for rendering load state directly in the list of Paging data displayed.And the way to do that is toAddLoadStateListener () and ConcatAdapter are encapsulated in PagingDataAdapter
      • First, create a class that implements LoadStateAdapter and define the onCreateViewHolder() and onBindViewHolder() methods:
            class LoadStateViewHolder(
              parent: ViewGroup,
              retry: () -> Unit
            ) : RecyclerView.ViewHolder(
              LayoutInflater.from(parent.context)
                .inflate(R.layout.load_state_item, parent, false)) {private val binding = LoadStateItemBinding.bind(itemView)
              private val progressBar: ProgressBar = binding.progressBar
              private val errorMsg: TextView = binding.errorMsg
              private val retry: Button = binding.retryButton
                .also {
                  it.setOnClickListener { retry() }
                }
        
              fun bind(loadState: LoadState) {
                if (loadState is LoadState.Error) {
                  errorMsg.text = loadState.error.localizedMessage
                }
        
                progressBar.isVisible = loadState is LoadState.Loading
                retry.isVisible = loadState is LoadState.Error
                errorMsg.isVisible = loadState is LoadState.Error
              }
            }
        
            // Adapter that displays a loading spinner when
            // state = LoadState.Loading, and an error message and retry
            // button when state is LoadState.Error.
            class ExampleLoadStateAdapter(
              private val retry: () -> Unit
            ) : LoadStateAdapter<LoadStateViewHolder>() {
        
              override fun onCreateViewHolder(
                parent: ViewGroup,
                loadState: LoadState
              ) = LoadStateViewHolder(parent, retry)
        
              override fun onBindViewHolder(
                holder: LoadStateViewHolder,
                loadState: LoadState
              ) = holder.bind(loadState)
            }
        Copy the code
      • Then, from PagingDataAdapter object call withLoadStateHeaderAndFooter () method:
            pagingAdapter
              .withLoadStateHeaderAndFooter(
                header = ExampleLoadStateAdapter(adapter::retry),
                footer = ExampleLoadStateAdapter(adapter::retry)
              )
        Copy the code
      • If you just want RecyclerView to show the load state in the header or footer, you can call withLoadStateHeader() or withLoadStateFooter(). About withLoadStateHeaderAndFooter (), withLoadStateHeader () and withLoadStateFooter () implementation, through the source code, Actually is to use PagingDataAdapter. AddLoadStateListener () solution, just by ConcatAdapter encapsulation. AddLoadStateListener () and ConcatAdapter are encapsulated in PagingDataAdapter, and the return value is ConcatAdapter
      • Note: Because withLoadStateHeaderAndFooter (), withLoadStateHeader () and withLoadStateFooter ConcatAdapter () returns, So if the constructor ConcatAdapter(firstAdapter, articleAdapter) has been used, then adding headers and footers with withLoadState will fail. Since withLoadState is also a ConcatAdapter, there are two ConcatAdapter. AddAdapter (0,firstAdapter); addAdapter(0,firstAdapter); And call concatAdapter. AddAdapter position is in the binding. ArticleList) before and after the adapter = concatAdapter is ok.
  • Pager: Pager().flow Converts the PagingSource to PagingData. Used in Repository

  • RemoteMediator: used in Pager().

    • When you load data from a multi-tiered data source, you should implement a RemoteMediator.
    • The common usage is to request data from the network and store it in a database. The load() method is triggered whenever there is no data in the database to display. Based on PagingState and LoadType, we can construct the data request for the next page.
  • PagingConfig: used in Pager()

  • PagingState: used in the custom PagingSource getRefreshKey() method, and in the custom RemoteMediator load() method.

    • Official Introduction: Snapshot state of Paging system including the loaded [pages], the last accessed [anchorPosition], and the [config] used.
  • Paging blog: Paging 3.0 has been released. The following blog is an alpha version, but can be used as a reference:

    • Paging load is implemented using Paging 3
    • Jetpack series Paging3, this is enough

Room

  • Room library
  • The official guide
  • The official demo

DataStore

  • DataStore
  • Use Jetpack DataStore for data storage

App Startup

  • App Startup

WorkManager

  • WorkManager

compose

  • compose

Navigation

  • Navigation documents
  • NavigationAdvancedSample
  • ARouter is a framework for Activity routing. It uses APT technology and can be used for componentization. Navigation is primarily a framework for Fragment route Navigation.
  • A comprehensive analysis of Jetpack Navigation
  • Bottom navigation bar 1
  • Bottom navigation bar 2
  • User Login Scenario
    • Conditions for navigation
    • Share data between fragments with activityViewModels()
    • Use ViewModel to share data in NavGraph
  • Safe navigation of the Args
  • Interfragment animation: Android Material component 1.2.0 is now available

Preference

  • Preference library
  • The official guide
  • Official demo: PreferencesKotlin

RecyclerView

  • RecyclerView library
  • The official documentation
  • The official demo
    • RecyclerView: Common Demo of the Java version
    • RecyclerViewAnimations: Add, delete, and update items
    • RecyclerViewKotlin: Demo of ConcatAdapter
      • ConcatAdapter is implemented to avoid nested sliding
      • Use Kotlin high – order functions to deal with the RecyclerView click events
      • The implementation of new, delete item program and update item animation
    • RecyclerViewSimple: Kotlin common demo
  • Default adapter: RecyclerView.Adapter: know RecyclerView
  • ListAdapter: Inherits the RecyclerView.Adapter: Uses ListAdapter in the RecyclerView
  • ConcatAdapter:
    • Use ConcatAdapter to connect other adapters in sequence, use the header in RecyclerView to get one step faster, new technology series: ConcatAdapter as the new partner of RecyclerView
    • RecyclerView new partner ConcatAdapter, to be studied.
  • PagingDataAdapter: Inherits recyclerView. Adapter

Slide the refresh

  • Slide refresh: General slide refresh for RecyclerView in the drop-down refresh and pull up load more.
  • The official documentation
  • Official demo:
    • SwipeRefreshLayoutBasic
    • SwipeRefreshMultipleViews
  • Slide the refreshinterfaceImplementation scheme:
    • Tripartite framework: SmartRefreshLayout
    • There are three options for self-implementation:
      • Scheme 1: You can customize a layout in the RecyclerView outer layer, put three controls inside: HeaderView, RecyclerView, FooterView. With SwipeRefreshLayout, just write a FooterView. Android simple and easy to start the drop-down refresh control, Android RecyclerView drop-down refresh & drop-down load more
      • Scheme 2: It can be used as two items of RecyclerView and distinguished by different types
      • Solution 3: You can use ConcatAdapter to connect other adapters in sequence
      • Plan 4: can directly use PagingDataAdapter withLoadStateFooter () to load the footer, but drop-down refresh also take their own implementation. Query the PagingDataAdapter implementation method found, in fact, this method is also scheme three, only in the PagingDataAdapter has been encapsulated.
      • About the pull-down refresh, can also use the idea of left slide delete, but the experience is not particularly ideal, temporarily pass this scheme
  • Slide the refreshfunctionImplementation scheme:
    • If ConcatAdapter, PagingDataAdapter: Use Paging3, refer to the Paging library description above.
    • If it is ListAdapter, recyclerView.adapter:
    • Refresh by pulling down and delete by sliding left refer to Demo:
      • AndroidSwipeLayout
      • SwipeRecyclerView
      • Android easy to use the drop-down refresh control

Loading status

  • Several scenarios of loading state: pull-down refresh, pull-up load more, all content loaded at the bottom, loading state of the first page entered (and loading failure alerts)
  • Pull-down refresh, pull-up load more: omitted
  • When the page is loaded for the first time:
  • The bottom has been loaded with all the content: there are more schemes, I prefer the following two schemes
    • Solution 1: Use the withLoadStateFooter. The same layout and adapter are used for pull-up loading. [Refer to this Demo]
    • Solution 2: Through concatAdapter.addAdapter implementation, specially display loading more

animation

  • Animation: The pull-down refreshes the scene through property Animation
  • The official documentation
  • Attribute animation:
    • ValueAnimator: The main timing engine for property animation, which also calculates the value of the property to be animated. It has all the core functionality needed to compute the values of the animations, along with timing details for each animation, information about whether the animations are repeated, a listener to receive update events, and the ability to set custom types to be evaluated. Animating properties is a two-step process: calculating the values after the effect is animated, and setting those values on the objects and properties to which the effect is to be animated. ValueAnimator does not perform the second step, so you must listen for updates to the values computed by ValueAnimator and use your own logic to modify the objects to animate. For more details, see adding Animation Effects with ValueAnimator section.
    • ObjectAnimator: Subclass of ValueAnimator that sets the target object and object properties to add animation effects. This class updates the properties after calculating a new value for the animation. In most cases, you might as well use ObjectAnimator because it greatly simplifies the process of animating the values of the target object. Sometimes, however, you need to use ValueAnimator directly because ObjectAnimator has some other limitations, such as requiring the target object to have specific accessor methods.
    • AnimationSet: This class provides a mechanism for grouping animations together so that they run relative to each other. You can set the animations to play together, in order, or after a specified delay. For more details, see Orchestrating Multiple Animation sections with AnimatorSet.
    • LayoutTransition:
    • LayoutAnimations:

ViewPager2

  • ViewPager2 library
  • The official documentation
  • The official demo
    • ViewPager2 with a Preview of Next/Prev Page in the official demo corresponds to a similar scenario in the Banner
    • ViewPager2 with a Nested RecyclerViews scenario is very good, provides a solution to Nested sliding scheme
  • ViewPager2 bottom use RecycleView implementation, so here no longer use PagerAdapter but use recyclerView. Adapter
  • Corresponding fragments using FragmentStateAdapter, not FragmentStatePagerAdapter, FragmentPagerAdapter and so on

Banner

  • Banner: The ViewPager app
  • The three parties library:
    • banner
    • Develop a commercial level Banner control
    • Create a flexible and easy to use Banner component
    • ViewPager2: Create the Banner control
  • Own implementation:
    • Keep the Banner and RecyclerView separate: Through NestedScrollView package ViewPager2 and RecyclerView, there will be a sliding caton problem, even with android: nestedScrollingEnabled = “false” attribute, Unless you add setHasFixedSize(true), there is another problem: with setHasFixedSize(true), only one page of data is displayed. So this scheme is temporarily unworkable. Code related to this scheme
          binding.articleList.setHasFixedSize(true)
          binding.articleList.isNestedScrollingEnabled = false
      Copy the code
    • Make banners part of RecyclerView:
      • If the Banner is at the top: if the Banner is at the top, do the header
      • If the Banner is in the middle: If it is in the middle, make a type, or an extension to the Adapter, and make something like a header that can be inserted in the middle. After all, “type” is hard to write
    • ConcatAdapter:
      • This demo is to use the scheme, the demo through the HomeFirstAdapter add RecyclerView ConcatAdapter, through the HomeBannerAdapter to achieve ViewPager2 adapter.
      • Through the above way plus ViewPager2, ViewPager2 does not affect the function of RecyclerView, RecyclerView sliding up and down smooth; But ViewPager2 can’t slide because events are intercepted by RecyclerView. So you need to add a custom layout NestedFrameLayout nested on top of ViewPager2, and handle the event distribution of the parent class in NestedFrameLayout, that is, when you swipe NestedFrameLayout left and right, Perform NestedFrameLayout parent. RequestDisallowInterceptTouchEvent (true) method, let ViewPager2 consumer events.
    • Implementation via MultiTypeAdapter: no validation yet
    • Icbc ronge purchase implementation scheme: in addition to the viewPager function on the home page are placed in AppBarLayout, but this TabLayout may be the same as Ronge purchase on the following, not what you want. ConcatAdapter can also be used to achieve the first page effect of ICBC ronge purchase.
    • Jingdong home page implementation scheme: custom control implementation. ConcatAdapter can also achieve the effect of jingdong home page

NestedScrollView

  • Directly in NestedScrollView into ViewPager2 and RecyclerView, there will be a slide card. Solution Reference
  • NestedScrollView
  • Cause of event conflicts: In Android’s event distribution mechanism, once one control consumes an event, no other control can receive the event. Therefore, when there are nested sliding scenarios, we all need to manually resolve event conflicts ourselves. With Android 5.0 Lollipop, Google officially solved the problem of not being able to share events with traditional Android event distribution by using nested sliders.
  • Nested sliding mechanism: The basic principle of nested sliding mechanism can be considered as event sharing, that is, when the child control receives the sliding event and is ready to slide, it will first notify the parent control (startNestedScroll); The parent control is then asked if it wants to slide (dispatchNestedPreScroll) before sliding; If the parent control slides in response to the event, the child control is notified of exactly how much sliding distance it has consumed; Then the remaining sliding distance is handled by the child control; Finally, after the child control finishes sliding, if the slider distance is left, it will ask the parent control again if it needs to continue sliding the remaining distance (dispatchNestedScroll)…

TabLayout

  • TabLayout
  • And ViewPager2 and Fragment applications

BottomNavigationView

  • BottomNavigationView
  • And Navigation, Fragment, ViewPager2

Constraint Layout

  • Constraint Layout

  • Constraint Layout 2.0

  • CoordinatorLayout, NestedScrollView, Collapse ToolbarLayout, AppBarLayout, and MaterialToolbart

  • Scenario to be optimized, search scenario: Search Delivers search queries using the search dialog or search widget with the assistance of the Android system

    • Search dialog
    • Search widgets

Glide

  • Compared with Coil, it is recommended to use Coil to load the image

Cookie

  • CookieManager
  • In this Demo, you need to log in to the favorites. You are advised to persist the returned cookies (including the account and password) to the local computer.

WebView

  • The WebView library
  • The official documentation
  • The official demo
  • In this demo, skip to the WebFragment by passing parameters through the Bundle instead of using Safe Args Navigation
  • The WebView in this demo is adapted to a dark theme.

Start the interface

  • Solution: by windowSplashscreenContent properties or SplashActivity interface
    • Note windowSplashscreenContent attribute is in Android8.0 (v26), if the adapter start-up interface on the previous version, should be a new Activity, namely SplashActivity.
  • Cold start, hot start
  • Splash Screen: displays the brand Logo or Slogan
    • If you want to display only one interface, just set @color/jetpack_green_500 in the Themes.
  • Advertisement Screen: displays holiday events or daily advertisements
  • Guide Screen: Shows key features, usually only once
  • Check out the blog: The new app launch API for Android 12.

Style system, immersive (It has been adapted to Android6.0, 8.1, 10 and 11. See demo for details)

  • This demo sink invasion scheme. Key properties: windowTranslucentStatus, statusBarColor, fitsSystemWindows, mSemiTransparentBarColor, clipToPadding
    1. Set true in Themes (or through code). Debugging found not set @ android: color/transparent.
    2. In the layout setting (or by code sets) AppBarLayout attribute android: fitsSystemWindows = “true”, is to prevent AppBarLayout display on the statusbar.
    3. Use reflection to set the mSemiTransparentBarColor of the decorView to transparent. The code is as follows:
        try {
            val decorView = window.decorView::class.java
            val field = decorView.getDeclaredField("mSemiTransparentBarColor")
            field.isAccessible = true
            field.setInt(window.decorView, Color.TRANSPARENT)
        } catch (e: Exception) {
        }
    Copy the code
  • Note: StatusBar works the same way as NavigationBar
  • Reference article:
    • Android style system | topic background and style
    • Android | style systemCommon theme background properties
    • Android style system | theme background attributes
    • Gestures navigation (a) | open full screen experience
    • Gestures navigation (2) | processing visual conflict
    • Gesture navigation (3) | how to deal with conflict
    • Gestures navigation (4) |Immersion mode
    • Android immersive status bar, just read this!

Touch gestures

  • Gesture navigation document
  • Drag and scale documents
  • Swipe left to delete:
    • See demo: PagingSample
    • Official solution: Use ItemTouchHelper for drag and slide deletion
    • RecycleView Android RecycleView

Project Address:Github.com/lelelongwan…