package org.qii.weiciyuan.support.lib; import org.qii.weiciyuan.R; import org.qii.weiciyuan.bean.ItemBean; import org.qii.weiciyuan.bean.ListBean; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; import android.view.View; import android.widget.TextView; import java.io.Serializable; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; /** * User: qii * Date: 13-4-20 */ public class TopTipBar extends TextView { //always show toptipbar, or hide itself when handling out of date data (for example user scroll down listview) public enum Type { ALWAYS, AUTO } private TreeSet<Long> ids = null; private boolean disappear = false; private Runnable lastRunnable; private boolean error; private OnChangeListener onChangeListener; private Type type; private static class TopTipBarComparator implements Comparator<Long>, Serializable { @Override public int compare(Long a, Long b) { Long aL = a; Long bL = b; Long resultL = aL - bL; int result = 0; if (resultL > 0L) { result = 1; } else if (resultL < 0L) { result = -1; } return result; } } public static interface OnChangeListener { public void onChange(int count); } public void setOnChangeListener(OnChangeListener l) { this.onChangeListener = l; this.onChangeListener.onChange(ids.size()); } public TopTipBar(Context context) { this(context, null); } public TopTipBar(Context context, AttributeSet attrs) { this(context, attrs, -1); } public TopTipBar(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); type = Type.AUTO; ids = new TreeSet<Long>(new TopTipBarComparator()); } public void setType(Type type) { this.type = type; setCount(); } public TreeSet<Long> getValues() { TreeSet<Long> copy = new TreeSet<Long>(); copy.addAll(this.ids); return copy; } /** * the json library gson has a bug, may convert database value to Double type, * so I have to force cast to Long type; * todo use other json library */ public void setValue(Set<Long> values) { this.ids.clear(); Iterator iterator = values.iterator(); while (iterator.hasNext()) { Object object = iterator.next(); if (object instanceof Double) { Double value = (Double) object; this.ids.add(value.longValue()); } else { this.ids.add((Long) object); } } this.disappear = false; setCount(); } public void setValue(ListBean<?, ?> listData, boolean disappear) { this.disappear = disappear; List<? extends ItemBean> values = listData.getItemList(); for (ItemBean b : values) { if (b != null) { ids.add(b.getIdLong()); } } setCount(); if (disappear) { disappear(3000); ids.clear(); } if (this.onChangeListener != null) { this.onChangeListener.onChange(ids.size()); } } private void disappear(int duration) { if (getVisibility() == View.INVISIBLE || getVisibility() == View.GONE) { return; } if (lastRunnable != null) { Handler handler = getHandler(); if (handler != null) { handler.removeCallbacks(lastRunnable); } } lastRunnable = new Runnable() { @Override public void run() { animate().alpha(0).setDuration(300).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); setVisibility(View.INVISIBLE); animate().alpha(1.0f).setListener(null); if (ids.size() > 0) { setCount(); } } }); } }; Handler handler = getHandler(); if (handler != null) { handler.postDelayed(lastRunnable, duration); } } private void setCount() { this.error = false; int count = ids.size(); if (count > 0) { setVisibility(View.VISIBLE); setText(String.format(getContext().getString(R.string.new_messages_count), String.valueOf(ids.size()))); setBackgroundResource(R.color.top_tip_bar_tip); } else { disappear(0); } } public void hideCount() { if (!error) { setVisibility(View.INVISIBLE); } } //helperId can be used to keep TopTipBar stay Visible status public void handle(long id, long helperId) { if (disappear || id == 0L) { return; } SortedSet tmp = ids.headSet(id, true); if (tmp.size() > 0) { tmp.clear(); setCount(); if (this.onChangeListener != null) { this.onChangeListener.onChange(ids.size()); } } if (type == Type.ALWAYS) { return; } if (helperId == 0L) { return; } if (ids.contains(helperId)) { setCount(); } else { setVisibility(View.INVISIBLE); } } public void clearAndReset() { if (disappear) { return; } ids.clear(); disappear(0); if (this.onChangeListener != null) { this.onChangeListener.onChange(ids.size()); } } public void setError(String error) { this.disappear = true; this.error = true; setVisibility(View.VISIBLE); animate().alpha(1.0f); setText(error); disappear(3000); setBackgroundResource(R.color.top_tip_bar_error); } @Override public Parcelable onSaveInstanceState() { //begin boilerplate code that allows parent classes to save state Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); //end ss.ids = this.ids; ss.disappear = this.disappear; ss.visible = this.isShown(); ss.type = this.type; return ss; } @Override public void onRestoreInstanceState(Parcelable state) { if (!(state instanceof SavedState)) { super.onRestoreInstanceState(state); return; } SavedState ss = (SavedState) state; super.onRestoreInstanceState(ss.getSuperState()); this.ids = ss.ids; this.disappear = ss.disappear; this.type = ss.type; if (ss.visible) { setVisibility(View.VISIBLE); } } static class SavedState extends BaseSavedState { TreeSet<Long> ids; boolean disappear; boolean visible; Type type; SavedState(Parcelable superState) { super(superState); } private SavedState(Parcel in) { super(in); Bundle bundle = in.readBundle(); this.ids = (TreeSet<Long>) bundle.getSerializable("ids"); this.type = (Type) bundle.getSerializable("type"); boolean[] disappearArray = new boolean[2]; in.readBooleanArray(disappearArray); this.disappear = disappearArray[0]; this.visible = disappearArray[1]; } @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); Bundle bundle = new Bundle(); bundle.putSerializable("ids", ids); bundle.putSerializable("type", type); out.writeBundle(bundle); out.writeBooleanArray(new boolean[]{this.disappear, this.visible}); } //required field that makes Parcelables from a Parcel public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() { public SavedState createFromParcel(Parcel in) { return new SavedState(in); } public SavedState[] newArray(int size) { return new SavedState[size]; } }; } }