Last active
September 28, 2015 07:16
-
-
Save talenguyen/3a33a6a01c8ae218e7c2 to your computer and use it in GitHub Desktop.
Android ContentLayout. The utility class to switch showing content/loading/error/empty efficient way
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<resources> | |
<declare-styleable name="ContentLayout"> | |
<attr name="content_layout" | |
format="reference"/> | |
<attr name="error_layout" | |
format="reference"/> | |
<attr name="empty_layout" | |
format="reference"/> | |
<attr name="loading_layout" | |
format="reference"/> | |
</declare-styleable> | |
</resources> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Umbala | |
* | |
* Created by Giang Nguyen on 9/26/15. | |
* Copyright (c) 2015 Umbala. All rights reserved. | |
*/ | |
package co.umbala.umbala.ui.widget; | |
import android.animation.Animator; | |
import android.animation.AnimatorListenerAdapter; | |
import android.animation.AnimatorSet; | |
import android.animation.ObjectAnimator; | |
import android.content.Context; | |
import android.content.res.TypedArray; | |
import android.support.annotation.LayoutRes; | |
import android.support.v7.internal.widget.ViewStubCompat; | |
import android.util.AttributeSet; | |
import android.view.View; | |
import android.widget.FrameLayout; | |
import co.umbala.umbala.R; | |
public class ContentLayout extends FrameLayout { | |
private static final int DURATION = 200; | |
private View vContent; | |
private View vLoading; | |
private View vError; | |
private View vEmpty; | |
private View showingView; | |
private ViewStubCompat vsError; | |
private ViewStubCompat vsEmpty; | |
private ViewStubCompat vsLoading; | |
private ViewStubCompat vsContent; | |
public ContentLayout(Context context) { | |
this(context, null, 0); | |
} | |
public ContentLayout(Context context, AttributeSet attrs) { | |
this(context, attrs, 0); | |
} | |
public ContentLayout(Context context, AttributeSet attrs, int defStyleAttr) { | |
super(context, attrs, defStyleAttr); | |
final TypedArray a = context.getTheme() | |
.obtainStyledAttributes(attrs, R.styleable.ContentLayout, defStyleAttr, 0); | |
try { | |
int layoutId; | |
layoutId = a.getResourceId(R.styleable.ContentLayout_content_layout, 0); | |
if (layoutId != 0) { | |
vsContent = new ViewStubCompat(context, null); | |
vsContent.setLayoutResource(layoutId); | |
addView(vsContent); | |
} | |
layoutId = a.getResourceId(R.styleable.ContentLayout_error_layout, 0); | |
if (layoutId != 0) { | |
setErrorLayout(layoutId); | |
} | |
layoutId = a.getResourceId(R.styleable.ContentLayout_loading_layout, 0); | |
if (layoutId != 0) { | |
setLoadingLayout(layoutId); | |
} | |
layoutId = a.getResourceId(R.styleable.ContentLayout_empty_layout, 0); | |
if (layoutId != 0) { | |
setEmptyLayout(layoutId); | |
} | |
} finally { | |
a.recycle(); | |
} | |
} | |
private void setLoadingLayout(int layoutId) { | |
if (vsLoading != null) { | |
// Remove the old View | |
removeView(vsLoading); | |
} | |
vsLoading = new ViewStubCompat(getContext(), null); | |
vsLoading.setLayoutResource(layoutId); | |
addView(vsLoading); | |
} | |
public void setErrorLayout(@LayoutRes int layoutId) { | |
if (vsError != null) { | |
removeView(vsError); | |
} | |
vsError = new ViewStubCompat(getContext(), null); | |
vsError.setLayoutResource(layoutId); | |
addView(vsError); | |
} | |
public void setEmptyLayout(@LayoutRes int layoutId) { | |
if (vsEmpty != null) { | |
removeView(vsEmpty); | |
} | |
vsEmpty = new ViewStubCompat(getContext(), null); | |
vsEmpty.setLayoutResource(layoutId); | |
addView(vsEmpty); | |
} | |
public View getContentView() { | |
if (vContent == null) { | |
vContent = inflateEmptyView(vsContent); | |
} | |
return vContent; | |
} | |
public View getErrorView() { | |
if (vError == null) { | |
vError = inflateEmptyView(vsError); | |
} | |
return vError; | |
} | |
public void showContent() { | |
if (vContent == null) { | |
vContent = inflateEmptyView(vsContent); | |
} | |
if (showingView == vContent) { | |
return; | |
} | |
crossFade(vContent, showingView); | |
showingView = vContent; | |
} | |
public void showError() { | |
if (vError == null) { | |
vError = inflateEmptyView(vsError); | |
} | |
if (showingView == vError) { | |
return; | |
} | |
crossFade(vError, showingView); | |
showingView = vError; | |
} | |
public void showLoading() { | |
if (vLoading == null) { | |
vLoading = inflateEmptyView(vsLoading); | |
} | |
if (showingView == vLoading) { | |
return; | |
} | |
crossFade(vLoading, showingView); | |
showingView = vLoading; | |
} | |
public void showEmpty() { | |
if (vEmpty == null) { | |
vEmpty = inflateEmptyView(vsEmpty); | |
} | |
if (showingView == vEmpty) { | |
return; | |
} | |
// Show empty | |
crossFade(vEmpty, showingView); | |
showingView = vEmpty; | |
} | |
private View inflateEmptyView(ViewStubCompat viewStub) { | |
if (viewStub == null) { | |
throw new NullPointerException("Must specify the layout in xml"); | |
} | |
return viewStub.inflate(); | |
} | |
private void crossFade(View showView, final View hideView) { | |
if (showView == null && hideView == null) { | |
return; | |
} | |
if (showView == null) { | |
hide(hideView); | |
} else if (hideView == null) { | |
show(showView); | |
} else { | |
final Animator hideAnimator = hideAnimator(hideView); | |
final Animator showAnimator = showAnimator(showView); | |
final AnimatorSet animatorSet = new AnimatorSet().setDuration(200); | |
animatorSet.addListener(new AnimatorListenerAdapter() { | |
@Override public void onAnimationEnd(Animator animation) { | |
super.onAnimationEnd(animation); | |
hideView.setVisibility(GONE); | |
} | |
}); | |
showView.setVisibility(VISIBLE); | |
animatorSet.playTogether(showAnimator, hideAnimator); | |
animatorSet.start(); | |
} | |
} | |
private void hide(final View view) { | |
final Animator animator = hideAnimator(view); | |
animator.setDuration(DURATION).addListener(new AnimatorListenerAdapter() { | |
@Override public void onAnimationEnd(Animator animation) { | |
super.onAnimationEnd(animation); | |
// Clear side-effect by this callback | |
animator.removeListener(this); | |
view.setVisibility(GONE); | |
} | |
}); | |
animator.start(); | |
} | |
private void show(final View view) { | |
view.setVisibility(VISIBLE); | |
showAnimator(view).setDuration(DURATION).start(); | |
} | |
private Animator hideAnimator(View target) { | |
return ObjectAnimator.ofFloat(target, "alpha", 0f); | |
} | |
private Animator showAnimator(View target) { | |
return ObjectAnimator.ofFloat(target, "alpha", 1f); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment