StateLayout Documentation

repository·master·Indexed 20 days ago

https://github.com/liangjingkanji/statelayout

An Android library for managing and displaying default or empty states such as loading, error, and empty data. It supports global and local configurations via StateConfig, XML or programmatic layout definitions, and custom state transition animations through StateChangedHandler. StateLayout can be integrated with BRV and Net for automated state switching and provides built-in support for 'click to retry' actions and skeleton screens.

Tokens
5.5K
Snippets
20
Records
23
Agent score
72%

What's inside StateLayout

  1. Overview of StateLayout features

    master

    StateLayout is a library designed to manage default/empty states (e.g., loading, error, empty data) across an entire application or within specific local layouts.

    Key Features:

    • Global or Local States: Manage empty states for the whole app or specific UI components.
    • Flexible Declaration: Define layouts via XML or programmatically via code.
    • Built-in Functionality: Quick configuration for 'click to retry' actions, custom animations, and skeleton screens.
    • Callbacks: Listen to state change events.
    • Automation Support: Can be integrated with BRV for list states and Net for network request states to automate state switching without manual intervention.
  2. Handle error states using tags in showXX() and onXX() callbacks

    master
    When using showXX() functions to display default/error pages, you can pass a tag parameter. This tag is then received in the corresponding onXX() callback, allowing you to differentiate between different error scenarios (e.g., distinguishing between a 400 Bad Request and a 500 Server Error) and display appropriate UI text.
  3. Handle additional states using tags

    master

    StateLayout natively supports four states: Error, Empty, Loading, and Content (the wrapped view).

    If you need to distinguish between different types of a single state (for example, differentiating between a Network Error and a Business Logic Error), you can use a tag to identify the specific condition. You can pass an exception object or any other object as a tag when triggering the error state.

    // Pass an exception object as a tag to distinguish error types
    showError(NetNetworkingException())
  4. Implement state transition animations with StateChangedHandler

    master

    To handle the simultaneous hiding of the previous state and the showing of the new state, implement the StateChangedHandler interface. This allows you to orchestrate complex transitions between different Status types.

    Built-in Handler: FadeStateChangedHandler

    The framework provides a FadeStateChangedHandler which implements a cross-fade transition. It uses onRemove to fade out the old view and onAdd to fade in the new view.

    Configuration

    You can set a custom or global handler via StateConfig.stateChangedHandler.

    // Configure a global handler
    StateConfig.stateChangedHandler = FadeStateChangedHandler(duration = 400)
  5. Completely customize state transitions with StateChangedHandler

    master

    To achieve maximum customization, implement the StateChangedHandler interface. This allows you to replace the default empty state switching logic, including defining custom animations for showing/hiding states and customizing layout parameters (width/height).

    By default, StateChangedHandler uses removeView/addView. If you prefer using visibility (e.g., View.GONE vs View.VISIBLE), you must implement this logic yourself within your custom handler.

    // Set for a specific instance (Singleton approach)
    state.stateChangedHandler = StateChangedHandler()
    
    // Set globally for all instances
    StateConfig.stateChangedHandler = StateChangedHandler()
  6. Configure StateLayout layouts

    master

    You can specify the layouts for different states (Empty, Error, and Loading) using either XML attributes or programmatic configuration.

    XML Configuration

    Use the following app: attributes within your StateLayout declaration:

    • app:empty_layout
    • app:error_layout
    • app:loading_layout

    Programmatic Configuration

    Access the StateLayout instance and assign layout resource IDs to the corresponding properties:

    // Programmatic configuration
    state.apply {
        emptyLayout = R.layout.layout_empty
        errorLayout = R.layout.layout_error
        loadingLayout = R.layout.layout_loading
    }
  7. Configure quick retry via View IDs

    master

    You can enable automatic retry functionality by providing the ID of a View (such as an image or a button) that users can click when the system is in an error or empty state. When the specified View is clicked, StateLayout will automatically call showLoading() to attempt a retry.

    There are two ways to configure this:

    1. Instance-based (Singleton/Local): Set retry IDs for a specific StateLayout instance.
    2. Global configuration: Set retry IDs globally for all StateLayout instances using StateConfig.
    // Instance-based configuration
    state.setRetryIds(R.id.msg)
    
    // Global configuration
    StateConfig.setRetryIds(R.id.msg)
  8. Add entry animations to default states

    master

    You can add custom animations to views when they are added to the layout by using the lifecycle callbacks in StateConfig.

    Warning: Overusing animations can slow down response speeds and negatively impact user experience.

    To implement this, create an extension function for View to handle the animation logic, and then call it within the appropriate StateConfig lifecycle blocks (onError, onEmpty, onContent, or onLoading).

    // 1. Create a unified animation function
    private fun View.startAnimation() {
        // Hide the view first, then fade it in over 800ms
        animate().setDuration(0).alpha(0F).withEndAction {
            animate().setDuration(800).alpha(1F)
        }
    }
    
    // 2. Apply the animation to specific default states
    StateConfig.apply {
        onError { startAnimation() }
        onEmpty { startAnimation() }
        onContent { startAnimation() }
        onLoading { startAnimation() }
    }
  9. Create a StateLayout

    master

    You can create a StateLayout using either XML layout declaration or programmatically via code.

    Note: Programmatic creation using stateCreate() is not recommended for performance reasons, as repeated calls can cause issues. Using XML is the preferred method.

    In a StateLayout, the views wrapped inside the StateLayout tag are considered the Content View, while the different states (empty, error, loading) are referred to as State Pages.

    <com.drake.statelayout.StateLayout
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/state"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.example.statelayout.MainActivity">
    
        <TextView
            android:id="@+id/tv_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="加载成功" />
    
    </com.drake.statelayout.StateLayout>
  10. Configure global error view callbacks

    master

    You can define a global callback for error states using StateConfig.onError. This allows you to intercept the error tag (the object passed to showError) and perform specific UI updates, such as changing an error image or adding a specific view, based on the type of error encountered.

    StateConfig.onError {
        if (it is NetNetworkingException) {
            // For network exceptions, show a specific error image
            findViewById<View>(R.id.iv_error).setImageResource(R.drawable.ic_networking_error)
        }
    }
  11. Implement skeleton animation using LeastAnimationStateChangedHandler

    master

    In StateLayout, skeleton animation is treated as a specific type of loading state animation. To prevent the animation from flickering (flashing) when network requests are too fast, you should implement a custom LeastAnimationStateChangedHandler.

    This handler ensures that the animation has a minimum execution time, providing a smoother user experience by preventing the loading state from being interrupted immediately by a success or error state.

    // Note: The implementation logic is demonstrated in the project's SkeletonAnimationActivity.kt
    // You should implement LeastAnimationStateChangedHandler to control the minimum duration of the animation state.
  12. Initialize StateLayout with StateConfig in Application

    master

    You can perform global configuration for StateLayout within your Application class using StateConfig. This allows you to define default layouts for empty, error, and loading states, set a global retry ID, and provide global callbacks for state transitions.

    StateConfig.apply {
        // Set default layouts for different states
        emptyLayout = R.layout.layout_empty
        errorLayout = R.layout.layout_error
        loadingLayout = R.layout.layout_loading
    
        // Set the global ID used for retry actions
        setRetryIds(R.id.msg)
    
        // Global callbacks for state changes
        onLoading {
            // Handle loading state globally
        }
    
        onEmpty {
            // Handle empty state globally
        }
    
        onError {
            // Handle error state globally
        }
    }