Android state third-party library

Android state third-party library

1.StatefulLayout 2

githup

This is a layout library that supports multiple states, including empty layout, error layout and loading layout. Additionally, the library provides options for customizing states.

Dependency import
implementation 'cz.kinst.jakub:android-stateful-layout-base:2.0.7'
use

use in xml

<cz.kinst.jakub.view.StatefulLayout
    android:id="@+id/stateful_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <!--Your Content Here-->
        
</cz.kinst.jakub.view.StatefulLayout>

Set the layout corresponding to the corresponding state in onCreate

// in onCreate()
statefulLayout.setStateView(STATE_NO_PERSMISSION, LayoutInflater.from(this).inflate(R.layout.state_no_permission, null));
statefulLayout.setStateView(STATE_PROGRESS, LayoutInflater.from(this).inflate(R.layout.state_progress, null));
API
  • setStateView(String state, View view)Add new state and corresponding view

  • setState(String state)change current status

  • getState()Returns the current view state (string id)

  • setOnStateChangeListener(OnStateChangeListener listener)Set up a listener for state change events

  • setStateController(StateController stateController)Sets the state controller object. See below.

StateController

If you don't want to manipulate directly with views (MVVM/MPV scenario), you can create an instance of StateController and bind it to StatefulLayout (using databinding for example). StateController allows you to set different states as well as control the current state itself. See the example below or the DataBindingControllerActivity in the example project.

<cz.kinst.jakub.view.StatefulLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:stateController="@{viewModel.stateController}">
</cz.kinst.jakub.view.StatefulLayout>
stateController = StatefulLayout.StateController.create()
                .withState(STATE_NO_PERSMISSION, LayoutInflater.from(this).inflate(R.layout.state_no_permission, null))
                .withState(STATE_PROGRESS, LayoutInflater.from(this).inflate(R.layout.state_progress, null))
                .build();
​
//...
​
stateController.setState(STATE_PROGRESS);

Extensible (SimpleStatefulLayout)

This base class should be used if you want to have a completely custom set of states/views. You can inherit and add custom states in the constructor (see SimpleStatefulLayout for example), or use Stateful layout directly and add states dynamically in code via setStateView(). The original StatefulLayout contains only one state - StatefulLayout.state.CONTENT, no matter what children are in the markup's XML content.

implementation 'cz.kinst.jakub:android-stateful-layout-simple:2.0.7'

SimpleStatefulLayout extends Stateful layout and adds several useful states for most applications - State.OFFLINE, State.PROGRESS, State.EMPTY. It provides customizable layout placeholders for these states and a way to provide fully custom layouts for states.

You can also customize it by extending the class or adding states with setStateView().

use
<cz.kinst.jakub.view.SimpleStatefulLayout
    android:id="@+id/stateful_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <!--Your Content Here-->
        
</cz.kinst.jakub.view.SimpleStatefulLayout>
// in onCreate()
statefulLayout.showProgress();
// load data
statefulLayout.showContent();
optional attributes
  • app:offlineTextCustom text to display when offline

  • app:offlineRetryTextThe text of the retry button when offline

  • app:emptyTextCustom text to display when offline

  • app:offlineImageDrawableA custom image displayed above the offline status text (if not using a custom layout)

  • app:emptyImageDrawableCustom image displayed above empty status text (if not using custom layout)

  • app:offlineLayoutCustom layout displayed when offline

  • app:emptyLayoutCustom layout shown when in EMPTY state

  • app:progressLayoutCustom layout shown when in PROGRESS state

  • app:stateThe initial state of the view ( 内容, 进度, 离线, 空布局)

  • app:stateTextAppearanceWhen not using a custom layout, here's how to style a TextView in an offline and empty layout state.

API
  • showContent()

  • showProgress()

  • showEmpty()

  • showOffline()

  • setEmptyText(String text)If using the default layout, this will set the text displayed in the EMPTY state

  • setOfflineText(String text)This will set the text displayed offline if using the default layout

  • setOfflineRetryText(String text)If using the default layout, this will set the text of the retry button displayed while offline

  • setOfflineRetryOnClickListener(OnClickListener listener)If using the default layout, this will set the click listener to the retry button displayed offline

  • setEmptyImageDrawable(Drawable drawable)Set custom image displayed above empty text when not using custom layout

  • setEmptyImageResource(int resourceId)Set custom image displayed above empty text when not using custom layout

  • setOfflineImageDrawable(Drawable drawable)Set custom image displayed above offline text when not using custom layout

  • setOfflineImageResource(int resourceId)Set custom image displayed above offline text when not using custom layout

  • setTransitionsEnabled(boolean enabled)Transition between enabled/disabled states

Use of Transition and TransitionManager for Android animation

2.StateView

StateView is a lightweight control that inherits from Viewand absorbs ViewStubsome features of . It is invisible in the initial state, does not occupy the layout position, and occupies less memory. The view will not be added to the layout until the action displays an empty/retry/load view.

githup

introduce

allprojects {
    repositories {
        ...
        maven { url 'https://jitpack.io' }
    }
}
dependencies {
    implementation 'com.github.nukc:StateView:v3.0.2'
}
Instructions

Use directly in code:

  • Inject into Activity

    mStateView = StateView.inject(Activity activity);
  • Inject into View

    mStateView = StateView.inject(View view);
  • Inject into ViewGroup

    mStateView = StateView.inject(ViewGroup parent);

or add to layout (this way can be more flexible):

    <com.github.nukc.stateview.StateView
        android:id="@+id/stateView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
  • Show an empty view:mStateView.showEmpty();

  • Show loading view:mStateView.showLoading();

  • Show retry view:mStateView.showRetry();

  • Display content:mStateView.showContent();

Set retry click event:

    mStateView.setOnRetryClickListener(new StateView.OnRetryClickListener() { 
        @Override 
        public void onRetryClick() { 
            //do something, no need to call showLoading() 
            //No need to call showLoading() method, StateView will call it automatically 
        } 
    });

Set up a custom view:

  • Global setting method: Create a new one under the layout of your own project, and the name can be the same as the default layout of StateView (no code setting is required). The name of the default layout: base_empty// .base_retrybase_loading

  • Single page setting: the layout name is different, and then the code is set.

    setEmptyResource(@LayoutRes int emptyResource)
​
    setRetryResource(@LayoutRes int retryResource)
​
    setLoadingResource(@LayoutRes int loadingResource)
​
    // v2.1
    setEmptyView(View view)
    setRetryView(View view)
    setLoadingView(View view)
​
    // v3.0.0
    setView(viewType: Int, view: View)
    // eg: set empty view
    setView(mStateView.getEmptyResource(), emptyView)
    // set any view
    setView(1, view)
    // show view
    show(viewType: Int)

Use to OnInflateListenerset the text image or other operations: callback when the view is successfully added to the parent (only one callback per viewType)

    mStateView.setOnInflateListener(new StateView.OnInflateListener() {
        @Override
        public void onInflate(@StateView.ViewType int viewType, View view) {
            if (viewType == StateView.EMPTY) {
                // set text or other
                ViewGroup emptyView = (ViewGroup) view;
                TextView tvMessage = (TextView) emptyView.findViewById(R.id.tv_message);
                ImageView ivState = (ImageView) emptyView.findViewById(R.id.iv_state);
                tvMessage.setText("custom message");
                ivState.setImageResource(R.drawable.retry);
            } else if (viewType == StateView.RETRY) {
                // ...
            }
        }
    });
Custom Attribute
<resources>
    <declare-styleable name="StateView">
        <attr name="emptyResource" format="reference" />
        <attr name="retryResource" format="reference" />
        <attr name="loadingResource" format="reference" />
    </declare-styleable>
</resources>
animation switch

Set view switching animation:

    // The default provider is null, that is, animation switching is not provided by default. 
    // If necessary, set one. 
    setAnimatorProvider(AnimatorProvider provider)

The animation effect can be customized, or you can directly use the animations library, which is separated from the main library, so that you can only rely on the library if you don't need it.

    compile 'com.github.nukc.stateview:animations:1.0.1'

The following animation effects are currently provided:

  • Gradient scaling:FadeScaleAnimatorProvider

  • Card Flip:FlipAnimatorProvider

  • Swipe left and right:SlideAnimatorProvider

If you customize it, you can directly implement AnimatorProviderthe interface and provide it .Animator

public class FadeScaleAnimatorProvider implements AnimatorProvider {
​
    @Override
    public Animator showAnimation(View view) {
        AnimatorSet set = new AnimatorSet();
        set.playTogether(
                ObjectAnimator.ofFloat(view, "alpha", 0f, 1f),
                ObjectAnimator.ofFloat(view, "scaleX", 0.1f, 1f),
                ObjectAnimator.ofFloat(view, "scaleY", 0.1f, 1f)
        );
        return set;
    }
​
    @Override
    public Animator hideAnimation(View view) {
        AnimatorSet set = new AnimatorSet();
        set.playTogether(
                ObjectAnimator.ofFloat(view, "alpha", 1f, 0f),
                ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.1f),
                ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.1f)
        );
        return set;
    }
}
Compatible with immersive fullscreen mode

For immersive full-screen mode, you can use this method to make up the height of the statusBar, so as not to cover the toolbar

/**
 * @return statusBarHeight
 */
private int getStatusBarHeight() {
    int height = 0;
    int resId = getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resId > 0) {
        height = getResources().getDimensionPixelSize(resId);
    }
    return height;
}
​
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) mStateView.getLayoutParams();
layoutParams.topMargin += getStatusBarHeight()

3.LoadSir

githup

LoadSirIt is an efficient, easy-to-use, low-carbon, environmentally friendly, and scalable loading feedback page management framework. When loading network or other data, switch the status page according to your needs. You can add custom status pages, such as loading, loading failure, and no data , network timeout, such as placeholder images, login failure and other commonly used pages. It can cooperate with the network loading framework, combine the return status code, error code, and data to automatically switch the status page, and the packaging effect is better.

Functions and features of LoadSir

  • ⭐Support Activity, Fragment, Fragment (v4), View state callback

  • ⭐ Adapt to multiple Fragment switching, and Fragment+ViewPager switching, without layout overlap or layout disorder

  • ⭐Use generics to convert input signals and output states, and automatically adapt the status page according to the status code or data returned by the network to achieve global automatic state switching

  • ⭐ No need to modify layout files

  • ⭐ Only one state view is loaded, not all views are preloaded

  • ⭐No need to set enumeration or constant status value, directly use status page class type (xxx.class) as status code

  • ⭐Click events can be set separately for a single status page, overwritten according to the returned boolean value or used in conjunction with OnReloadListener, such as a network error can jump to the settings page

  • ⭐No preset pages, low coupling, developers can configure as they like

  • ⭐You can keep the title bar (Toolbar, title view, etc.)

  • Can set reload click event (OnReloadListener)

  • Customizable status page (inherited from Callback class)

  • The state can be switched directly in the child thread

  • The initial status page can be set (the progress page is commonly used as the initial status)

  • Extensible status page, add custom status page in configuration

  • It can be configured globally as a single instance or individually

Get started with LoadSir

The use of LoadSir only needs three simple steps

add dependencies
compile 'com.kingja.loadsir:loadsir:1.3.8'
Step 1: Configuration
global configuration

The global configuration method uses the singleton mode, that is, the obtained configurations are all the same. Can be configured in Application, add status page, set default status page

public class App extends Application { 
    @Override 
    public void onCreate() { 
        super.onCreate(); 
        LoadSir.beginBuilder() 
                .addCallback(new ErrorCallback())//Add various status pages.addCallback 
                (new EmptyCallback()) 
                .addCallback (new LoadingCallback()) 
                .addCallback(new TimeoutCallback()) 
                .addCallback(new CustomCallback()) 
                .setDefaultCallback(LoadingCallback.class)//Set default status page.commit 
                (); 
    } 
}
Separate configuration

This method can be used if you want to keep the global configuration and add some different configurations to a special page.

LoadSir loadSir = new LoadSir.Builder()
                .addCallback(new LoadingCallback())
                .addCallback(new EmptyCallback())
                .addCallback(new ErrorCallback())
                .build();
        loadService = loadSir.register(this, new Callback.OnReloadListener() {
            @Override
            public void onReload(View v) {
                // 重新加载逻辑
            }
        });
Step 2: Register
Use in Activity
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_content);
    // Your can change the callback on sub thread directly.
    LoadService loadService = LoadSir.getDefault().register(this, new Callback.OnReloadListener() {
        @Override
        public void onReload(View v) {
            // 重新加载逻辑
        }
    });
}}
Use in View
ImageView imageView = (ImageView) findViewById(R.id.iv_img); 
LoadSir loadSir = new LoadSir.Builder() 
        .addCallback(new TimeoutCallback()) 
        .setDefaultCallback(LoadingCallback.class) 
        .build(); 
loadService = loadSir.register( imageView, new Callback.OnReloadListener() { 
    @Override 
    public void onReload(View v) { 
        loadService.showCallback(LoadingCallback.class); 
        // reload logic 
    } 
}); 
Ps: 
[1] To register a child View of RelativeLayout or ConstraintLayout , if the sub-View is constrained by other sub-Views, it is recommended to wrap another layer of layout outside the sub-View, refer to 
acitivy_view.xm and activity_constraintlayout.xml
Use in Fragment

Since Fragment is added to Activitiy in various ways, it is quite special, so the registration method in Fragment is different from the above two, let’s look at the template code first:

@Nullable 
@Override 
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle 
        savedInstanceState) { 
    //Step 1: Get layout View 
    rootView = View.inflate(getActivity(), R.layout.fragment_a_content, null); 
    //Step 2: Register layout View 
    LoadService loadService = LoadSir.getDefault().register(rootView, new Callback.OnReloadListener() { 
        @Override 
        public void onReload(View v) { 
            // Reload logic 
        } 
    }); 
    // Step 3: Return the LoadLayout generated by LoadSir 
    return loadService.getLoadLayout(); 
}
Step 3: callback
direct callback
protected void loadNet() { 
        // Network access... 
        // Callback 
        loadService.showSuccess();//Successful callback 
        loadService.showCallback(EmptyCallback.class);//Other callbacks 
    }
Converter callback (recommended)

If you don't want to manually perform each callback, you can choose to add a converter when registering, and adapt the corresponding status page according to the returned data.

LoadService loadService = LoadSir.getDefault().register(this, new Callback.OnReloadListener() {
    @Override
    public void onReload(View v) {
            // 重新加载逻辑
    }}, new Convertor<HttpResult>() {
    @Override
    public Class<? extends Callback> map(HttpResult httpResult) {
        Class<? extends Callback> resultCode = SuccessCallback.class;
        switch (httpResult.getResultCode()) {
            case SUCCESS_CODE://成功回调
                if (httpResult.getData().size() == 0) {
                    resultCode = EmptyCallback.class;
                }else{
                    resultCode = SuccessCallback.class;
                }
                break;
            case ERROR_CODE:
                resultCode = ErrorCallback.class;
                break;
        }
        return resultCode;
    }
});

When calling back, directly pass in the data type specified by the converter.

loadService.showWithConvertor(httpResult);
Custom callback page

In order to be completely decoupled, LoadSir does not preset any status pages and needs to be implemented by itself. Developers can customize their own callback pages, such as loading, no data, error, timeout and other common pages, set the layout and customize the click logic

public class CustomCallback extends Callback { 
​//
    Fill the layout 
    @Override 
    protected int onCreateView() { 
        return R.layout.layout_custom; 
    } 
    //Click event of the current Callback, if it returns true, it will overwrite the registration onReloa(), if it returns false Then execute both, first execute onReloadEvent(). 
    @Override 
    protected boolean onReloadEvent(final Context context, View view) { 
        Toast.makeText(context.getApplicationContext(), "Hello buddy! :p", Toast.LENGTH_SHORT).show(); 
        (view.findViewById(R.id. iv_gift)).setOnClickListener(new View.OnClickListener() { 
            @Override 
            public void onClick(View v) {
                Toast.makeText(context.getApplicationContext(), "It's your gift! :p", Toast.LENGTH_SHORT).show(); }  
            }
        ); 
        return true; 
    } 
​//
    Whether to display the original image when displaying the Callback view (SuccessView ), return true to display, false to hide 
    @Override 
    public boolean getSuccessVisible() { 
        return super.getSuccessVisible(); 
    } 
​//
    Callback when adding Callback to the current view, View is the layout View of the current Callback 
    @Override 
    public void onAttach( Context context, View view) { 
        super.onAttach(context, view); 
    } 
​//
    The callback when the Callback is removed from the current view, and the View is the layout View of the current Callback 
    @Override 
    public void onDetach() { 
        super.onDetach(context, view); 
    } 
​}
Dynamically modify Callback
loadService = LoadSir.getDefault().register(...);
loadService.setCallBack(EmptyCallback.class, new Transport() {
   @Override
   public void order(Context context, View view) {
       TextView mTvEmpty = (TextView) view.findViewById(R.id.tv_empty);
       mTvEmpty.setText("fine, no data. You must fill it!");
   }
});
LoadSir comes with a portable Callback
ProgressCallback loadingCallback = new ProgressCallback.Builder()
        .setTitle("Loading", R.style.Hint_Title)
        .build();
​
HintCallback hintCallback = new HintCallback.Builder()
        .setTitle("Error", R.style.Hint_Title)
        .setSubTitle("Sorry, buddy, I will try it again.")
        .setHintImg(R.drawable.error)
        .build();
​
LoadSir loadSir = new LoadSir.Builder()
        .addCallback(loadingCallback)
        .addCallback(hintCallback)
        .setDefaultCallback(ProgressCallback.class)
        .build();

4.empty-view

githup

5.EasyRecyclerView

recommend using this

Guess you like

Origin blog.csdn.net/fromVillageCoolBoy/article/details/131478870