package com.android.yzd.memo.widget.spinner;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.animation.LinearOutSlowInInterpolator;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;
import com.android.yzd.memo.R;
import java.util.List;
/**
* @author angelo.marchesin
*/
@SuppressWarnings("unused")
public class NiceSpinner extends TextView {
private static final int MAX_LEVEL = 10000;
private static final int DEFAULT_ELEVATION = 16;
private static final String INSTANCE_STATE = "instance_state";
private static final String SELECTED_INDEX = "selected_index";
private static final String IS_POPUP_SHOWING = "is_popup_showing";
private int mSelectedIndex;
private Drawable mDrawable;
private PopupWindow mPopup;
private ListView mListView;
private NiceSpinnerBaseAdapter mAdapter;
private AdapterView.OnItemClickListener mOnItemClickListener;
private AdapterView.OnItemSelectedListener mOnItemSelectedListener;
private boolean mHideArrow;
@SuppressWarnings("ConstantConditions")
public NiceSpinner(Context context) {
super(context);
init(context, null);
}
public NiceSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public NiceSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@Override
public Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putParcelable(INSTANCE_STATE, super.onSaveInstanceState());
bundle.putInt(SELECTED_INDEX, mSelectedIndex);
if (mPopup != null) {
bundle.putBoolean(IS_POPUP_SHOWING, mPopup.isShowing());
dismissDropDown();
}
return bundle;
}
@Override
public void onRestoreInstanceState(Parcelable savedState) {
if (savedState instanceof Bundle) {
Bundle bundle = (Bundle) savedState;
mSelectedIndex = bundle.getInt(SELECTED_INDEX);
if (mAdapter != null) {
setText(mAdapter.getItemInDataset(mSelectedIndex).toString());
mAdapter.notifyItemSelected(mSelectedIndex);
}
if (bundle.getBoolean(IS_POPUP_SHOWING)) {
if (mPopup != null) {
// Post the show request into the looper to avoid bad token exception
post(new Runnable() {
@Override
public void run() {
showDropDown();
}
});
}
}
savedState = bundle.getParcelable(INSTANCE_STATE);
}
super.onRestoreInstanceState(savedState);
}
private void init(Context context, AttributeSet attrs) {
Resources resources = getResources();
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.NiceSpinner);
int defaultPadding = resources.getDimensionPixelSize(R.dimen.one_and_a_half_grid_unit);
setGravity(Gravity.CENTER_VERTICAL | Gravity.CENTER);
setPadding(resources.getDimensionPixelSize(R.dimen.three_grid_unit), defaultPadding, defaultPadding,
defaultPadding);
setClickable(true);
// setBackgroundResource(R.drawable.selector);
mListView = new ListView(context);
// Set the spinner's id into the listview to make it pretend to be the right parent in
// onItemClick
mListView.setId(getId());
mListView.setDivider(null);
mListView.setItemsCanFocus(true);
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position >= mSelectedIndex && position < mAdapter.getCount()) {
position++;
}
// Need to set selected index before calling listeners or getSelectedIndex() can be
// reported incorrectly due to race conditions.
mSelectedIndex = position;
if (mOnItemClickListener != null) {
mOnItemClickListener.onItemClick(parent, view, position, id);
}
if (mOnItemSelectedListener != null) {
mOnItemSelectedListener.onItemSelected(parent, view, position, id);
}
mAdapter.notifyItemSelected(position);
setText(mAdapter.getItemInDataset(position).toString());
dismissDropDown();
}
});
mPopup = new PopupWindow(context);
mPopup.setContentView(mListView);
mPopup.setOutsideTouchable(true);
mPopup.setFocusable(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mPopup.setElevation(DEFAULT_ELEVATION);
mPopup.setBackgroundDrawable(ContextCompat.getDrawable(context, R.drawable.spinner_drawable));
} else {
mPopup.setBackgroundDrawable(ContextCompat.getDrawable(context, R.drawable.drop_down_shadow));
}
mPopup.setOnDismissListener(new PopupWindow.OnDismissListener() {
@Override
public void onDismiss() {
if (!mHideArrow) {
animateArrow(false);
}
}
});
mHideArrow = typedArray.getBoolean(R.styleable.NiceSpinner_hideArrow, false);
if (!mHideArrow) {
Drawable basicDrawable = ContextCompat.getDrawable(context, R.drawable.arrow);
int resId = typedArray.getColor(R.styleable.NiceSpinner_arrowTint, -1);
if (basicDrawable != null) {
mDrawable = DrawableCompat.wrap(basicDrawable);
if (resId != -1) {
DrawableCompat.setTint(mDrawable, resId);
}
}
setCompoundDrawablesWithIntrinsicBounds(null, null, mDrawable, null);
}
typedArray.recycle();
}
public int getSelectedIndex() {
return mSelectedIndex;
}
/**
* Set the default spinner item using its index
*
* @param position the item's position
*/
public void setSelectedIndex(int position) {
if (mAdapter != null) {
if (position >= 0 && position <= mAdapter.getCount()) {
mAdapter.notifyItemSelected(position);
mSelectedIndex = position;
setText(mAdapter.getItemInDataset(position).toString());
} else {
throw new IllegalArgumentException("Position must be lower than adapter count!");
}
}
}
public void addOnItemClickListener(@NonNull AdapterView.OnItemClickListener onItemClickListener) {
mOnItemClickListener = onItemClickListener;
}
public void setOnItemSelectedListener(@NonNull AdapterView.OnItemSelectedListener onItemSelectedListener) {
mOnItemSelectedListener = onItemSelectedListener;
}
public <T> void attachDataSource(@NonNull List<T> dataset) {
mAdapter = new NiceSpinnerAdapter<>(getContext(), dataset);
setAdapterInternal(mAdapter);
}
public void setAdapter(@NonNull ListAdapter adapter) {
mAdapter = new NiceSpinnerAdapterWrapper(getContext(), adapter);
setAdapterInternal(mAdapter);
}
private void setAdapterInternal(@NonNull NiceSpinnerBaseAdapter adapter) {
mListView.setAdapter(adapter);
setText(adapter.getItemInDataset(mSelectedIndex).toString());
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mPopup.setWidth(MeasureSpec.getSize(widthMeasureSpec));
mPopup.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public boolean onTouchEvent(@NonNull MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
if (!mPopup.isShowing()) {
showDropDown();
} else {
dismissDropDown();
}
}
return super.onTouchEvent(event);
}
private void animateArrow(boolean shouldRotateUp) {
int start = shouldRotateUp ? 0 : MAX_LEVEL;
int end = shouldRotateUp ? MAX_LEVEL : 0;
ObjectAnimator animator = ObjectAnimator.ofInt(mDrawable, "level", start, end);
animator.setInterpolator(new LinearOutSlowInInterpolator());
animator.start();
}
public void dismissDropDown() {
if (!mHideArrow) {
animateArrow(false);
}
mPopup.dismiss();
}
public void showDropDown() {
if (!mHideArrow) {
animateArrow(true);
}
mPopup.showAsDropDown(this);
}
public void setTintColor(@ColorRes int resId) {
if (mDrawable != null && !mHideArrow) {
DrawableCompat.setTint(mDrawable, getResources().getColor(resId));
}
}
}