package pl.droidsonroids.gif;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Parcelable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.widget.TextView;
import java.io.IOException;
/**
* A {@link TextView} which handles GIFs as compound drawables. NOTE:
* {@code android:drawableStart} and {@code android:drawableEnd} from XML are
* not supported but can be set using
* {@link #setCompoundDrawablesRelativeWithIntrinsicBounds(int, int, int, int)}
*
* @author koral--
*/
public class GifTextView extends TextView {
private boolean mFreezesAnimation;
/**
* A corresponding superclass constructor wrapper.
*
* @param context
*/
public GifTextView(Context context) {
super(context);
}
/**
* Like equivalent from superclass but also try to interpret compound drawables defined in XML
* attributes as GIFs.
*
* @param context
* @param attrs
* @see TextView#TextView(Context, AttributeSet)
*/
public GifTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs, 0, 0);
}
/**
* Like equivalent from superclass but also try to interpret compound drawables defined in XML
* attributes as GIFs.
*
* @param context
* @param attrs
* @param defStyle
* @see TextView#TextView(Context, AttributeSet, int)
*/
public GifTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(attrs, defStyle, 0);
}
/**
* Like equivalent from superclass but also try to interpret compound drawables defined in XML
* attributes as GIFs.
*
* @param context
* @param attrs
* @param defStyle
* @param defStyleRes
* @see TextView#TextView(Context, AttributeSet, int, int)
*/
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
public GifTextView(Context context, AttributeSet attrs, int defStyle, int defStyleRes) {
super(context, attrs, defStyle, defStyleRes);
init(attrs, defStyle, defStyleRes);
}
private void init(AttributeSet attrs, int defStyle, int defStyleRes) {
if (attrs != null) {
Drawable left = getGifOrDefaultDrawable(attrs.getAttributeResourceValue(GifViewUtils.ANDROID_NS, "drawableLeft", 0));
Drawable top = getGifOrDefaultDrawable(attrs.getAttributeResourceValue(GifViewUtils.ANDROID_NS, "drawableTop", 0));
Drawable right = getGifOrDefaultDrawable(attrs.getAttributeResourceValue(GifViewUtils.ANDROID_NS, "drawableRight", 0));
Drawable bottom = getGifOrDefaultDrawable(attrs.getAttributeResourceValue(GifViewUtils.ANDROID_NS, "drawableBottom", 0));
Drawable start = getGifOrDefaultDrawable(attrs.getAttributeResourceValue(GifViewUtils.ANDROID_NS, "drawableStart", 0));
Drawable end = getGifOrDefaultDrawable(attrs.getAttributeResourceValue(GifViewUtils.ANDROID_NS, "drawableEnd", 0));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) {
if (start == null) {
start = left;
}
if (end == null) {
end = right;
}
} else {
if (start == null) {
start = right;
}
if (end == null) {
end = left;
}
}
setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
} else {
setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
}
setBackgroundInternal(getGifOrDefaultDrawable(attrs.getAttributeResourceValue(GifViewUtils.ANDROID_NS, "background", 0)));
}
mFreezesAnimation = GifViewUtils.isFreezingAnimation(this, attrs, defStyle, defStyleRes);
}
@SuppressWarnings("deprecation") // setBackgroundDrawable
private void setBackgroundInternal(Drawable bg) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
setBackground(bg);
} else {
setBackgroundDrawable(bg);
}
}
@Override
public void setBackgroundResource(int resId) {
setBackgroundInternal(getGifOrDefaultDrawable(resId));
}
@SuppressWarnings("deprecation") //Resources#getDrawable(int)
private Drawable getGifOrDefaultDrawable(int resId) {
if (resId == 0) {
return null;
}
final Resources resources = getResources();
if (!isInEditMode() && "drawable".equals(resources.getResourceTypeName(resId))) {
try {
return new GifDrawable(resources, resId);
} catch (IOException | NotFoundException ignored) {
// ignored
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return resources.getDrawable(resId, getContext().getTheme());
} else {
return resources.getDrawable(resId);
}
}
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void setCompoundDrawablesRelativeWithIntrinsicBounds(int start, int top, int end, int bottom) {
setCompoundDrawablesRelativeWithIntrinsicBounds(getGifOrDefaultDrawable(start), getGifOrDefaultDrawable(top), getGifOrDefaultDrawable(end), getGifOrDefaultDrawable(bottom));
}
@Override
public void setCompoundDrawablesWithIntrinsicBounds(int left, int top, int right, int bottom) {
setCompoundDrawablesWithIntrinsicBounds(getGifOrDefaultDrawable(left), getGifOrDefaultDrawable(top), getGifOrDefaultDrawable(right), getGifOrDefaultDrawable(bottom));
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
hideCompoundDrawables(getCompoundDrawables());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
hideCompoundDrawables(getCompoundDrawablesRelative());
}
}
private void hideCompoundDrawables(Drawable[] drawables) {
for (Drawable d : drawables) {
if (d != null) {
d.setVisible(false, false);
}
}
}
@Override
public Parcelable onSaveInstanceState() {
Drawable[] savedDrawables = new Drawable[7];
if (mFreezesAnimation) {
Drawable[] compoundDrawables = getCompoundDrawables();
System.arraycopy(compoundDrawables, 0, savedDrawables, 0, compoundDrawables.length);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Drawable[] compoundDrawablesRelative = getCompoundDrawablesRelative();
savedDrawables[4] = compoundDrawablesRelative[0]; //start
savedDrawables[5] = compoundDrawablesRelative[2]; //end
}
savedDrawables[6] = getBackground();
}
return new GifViewSavedState(super.onSaveInstanceState(), savedDrawables);
}
@Override
public void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof GifViewSavedState)) {
super.onRestoreInstanceState(state);
return;
}
GifViewSavedState ss = (GifViewSavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
Drawable[] compoundDrawables = getCompoundDrawables();
ss.restoreState(compoundDrawables[0], 0);
ss.restoreState(compoundDrawables[1], 1);
ss.restoreState(compoundDrawables[2], 2);
ss.restoreState(compoundDrawables[3], 3);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
Drawable[] compoundDrawablesRelative = getCompoundDrawablesRelative();
ss.restoreState(compoundDrawablesRelative[0], 4);
ss.restoreState(compoundDrawablesRelative[2], 5);
}
ss.restoreState(getBackground(), 6);
}
/**
* Sets whether animation position is saved in {@link #onSaveInstanceState()} and restored
* in {@link #onRestoreInstanceState(Parcelable)}. This is applicable to all compound drawables.
*
* @param freezesAnimation whether animation position is saved
*/
public void setFreezesAnimation(boolean freezesAnimation) {
mFreezesAnimation = freezesAnimation;
}
}