Initial commit
@ -0,0 +1,13 @@
|
||||
package com.superrecycleview.superlibrary;
|
||||
|
||||
import android.app.Application;
|
||||
import android.test.ApplicationTestCase;
|
||||
|
||||
/**
|
||||
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
|
||||
*/
|
||||
public class ApplicationTest extends ApplicationTestCase<Application> {
|
||||
public ApplicationTest() {
|
||||
super(Application.class);
|
||||
}
|
||||
}
|
||||
9
superlibrary/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.superrecycleview.superlibrary">
|
||||
|
||||
<application android:allowBackup="true" android:label="@string/app_name"
|
||||
android:supportsRtl="true">
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@ -0,0 +1,10 @@
|
||||
package com.superrecycleview.superlibrary.adapter;
|
||||
|
||||
/**
|
||||
* Created by super南仔 on 07/28/16.
|
||||
* blog: http://supercwn.github.io/
|
||||
* GitHub: https://github.com/supercwn
|
||||
*/
|
||||
public enum AnimationType {
|
||||
ALPHA, SCALE, SLIDE_FROM_BOTTOM, SLIDE_FROM_LEFT, SLIDE_FROM_RIGHT
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
package com.superrecycleview.superlibrary.adapter;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
/**
|
||||
* Created by super南仔 on 07/28/16.
|
||||
* blog: http://supercwn.github.io/
|
||||
* GitHub: https://github.com/supercwn
|
||||
*/
|
||||
public class AnimationUtil {
|
||||
private AnimationType mAnimationType = AnimationType.ALPHA;
|
||||
private Animator mCustomAnimator;
|
||||
private View mTargetView;
|
||||
private Interpolator mInterpolator;
|
||||
private int mDuration = 300;
|
||||
|
||||
public AnimationUtil() {
|
||||
}
|
||||
|
||||
public AnimationUtil setAnimationType(AnimationType animationType) {
|
||||
mAnimationType = animationType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AnimationUtil setCustomAnimation(Animator animator) {
|
||||
mCustomAnimator = animator;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AnimationUtil setDuration(int duration) {
|
||||
mDuration = duration;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AnimationUtil setInterpolator(Interpolator interpolator) {
|
||||
mInterpolator = interpolator;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AnimationUtil setTargetView(View targetView) {
|
||||
mTargetView = targetView;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (null != mCustomAnimator) {
|
||||
mCustomAnimator.start();
|
||||
} else if (null == mTargetView) {
|
||||
throw new IllegalArgumentException("You must set a target view!");
|
||||
} else {
|
||||
startAnimation(mAnimationType);
|
||||
}
|
||||
}
|
||||
|
||||
private void startAnimation(AnimationType animationType) {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
switch (animationType) {
|
||||
case ALPHA:
|
||||
animatorSet.play(ObjectAnimator.ofFloat(mTargetView, "alpha", 0.7f, 1f));
|
||||
break;
|
||||
case SCALE:
|
||||
animatorSet.playTogether(ObjectAnimator.ofFloat(mTargetView, "scaleX", 0.6f, 1f)
|
||||
, ObjectAnimator.ofFloat(mTargetView, "scaleY", 0.6f, 1f));
|
||||
break;
|
||||
case SLIDE_FROM_BOTTOM:
|
||||
animatorSet.play(ObjectAnimator.ofFloat(mTargetView, "translationY", mTargetView
|
||||
.getMeasuredHeight(), 0));
|
||||
break;
|
||||
case SLIDE_FROM_LEFT:
|
||||
animatorSet.play(ObjectAnimator.ofFloat(mTargetView, "translationX", -mTargetView
|
||||
.getRootView().getWidth(), 0));
|
||||
break;
|
||||
case SLIDE_FROM_RIGHT:
|
||||
animatorSet.play(ObjectAnimator.ofFloat(mTargetView, "translationX", mTargetView
|
||||
.getRootView().getWidth(), 0));
|
||||
break;
|
||||
}
|
||||
|
||||
if (null != mInterpolator) {
|
||||
animatorSet.setInterpolator(mInterpolator);
|
||||
}
|
||||
animatorSet.setDuration(mDuration);
|
||||
animatorSet.start();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,140 @@
|
||||
|
||||
package com.superrecycleview.superlibrary.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* Created by super南仔 on 07/28/16. blog: http://supercwn.github.io/ GitHub:
|
||||
* https://github.com/supercwn
|
||||
*/
|
||||
public class BaseViewHolder extends RecyclerView.ViewHolder {
|
||||
private final SparseArray<View> mViews;
|
||||
private Context mContext;
|
||||
|
||||
public BaseViewHolder(View itemView, Context context) {
|
||||
super(itemView);
|
||||
mViews = new SparseArray<>();
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public <TView extends View> TView getView(int id) {
|
||||
View view = mViews.get(id);
|
||||
if (view == null) {
|
||||
view = itemView.findViewById(id);
|
||||
mViews.put(id, view);
|
||||
}
|
||||
return (TView) view;
|
||||
}
|
||||
|
||||
public BaseViewHolder setText(int viewId, CharSequence value) {
|
||||
TextView view = getView(viewId);
|
||||
view.setText(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseViewHolder setImageURI(int viewId, Uri uri) {
|
||||
ImageView view = getView(viewId);
|
||||
view.setImageURI(uri);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseViewHolder setTextColor(int viewId, int textColor) {
|
||||
TextView view = getView(viewId);
|
||||
view.setTextColor(textColor);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseViewHolder setTextColorRes(int viewId, int textColorRes) {
|
||||
TextView view = getView(viewId);
|
||||
view.setTextColor(mContext.getResources().getColor(textColorRes));
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseViewHolder setImageResource(int viewId, int imageResId) {
|
||||
ImageView view = getView(viewId);
|
||||
view.setImageResource(imageResId);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseViewHolder setBackgroundColor(int viewId, int color) {
|
||||
View view = getView(viewId);
|
||||
view.setBackgroundColor(color);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseViewHolder setBackgroundResource(int viewId, int backgroundRes) {
|
||||
View view = getView(viewId);
|
||||
view.setBackgroundResource(backgroundRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseViewHolder setVisible(int viewId, boolean visible) {
|
||||
View view = getView(viewId);
|
||||
view.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseViewHolder setTypeface(Typeface typeface, int... viewIds) {
|
||||
for (int viewId : viewIds) {
|
||||
TextView view = getView(viewId);
|
||||
view.setTypeface(typeface);
|
||||
view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseViewHolder setOnClickListener(int viewId, View.OnClickListener listener) {
|
||||
View view = getView(viewId);
|
||||
view.setOnClickListener(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseViewHolder setOnTouchListener(int viewId, View.OnTouchListener listener) {
|
||||
View view = getView(viewId);
|
||||
view.setOnTouchListener(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseViewHolder setOnLongClickListener(int viewId, View.OnLongClickListener listener) {
|
||||
View view = getView(viewId);
|
||||
view.setOnLongClickListener(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseViewHolder setOnClickListener(int viewId,
|
||||
SuperBaseAdapter.OnItemChildClickListener listener) {
|
||||
View view = getView(viewId);
|
||||
listener.mViewHolder = this;
|
||||
view.setOnClickListener(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the on longClick listener of the view.
|
||||
*
|
||||
* @param viewId
|
||||
* @param listener
|
||||
* @return
|
||||
*/
|
||||
public BaseViewHolder setOnLongClickListener(int viewId,
|
||||
SuperBaseAdapter.OnItemChildLongClickListener listener) {
|
||||
View view = getView(viewId);
|
||||
listener.mViewHolder = this;
|
||||
view.setOnLongClickListener(listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseViewHolder setTag(int viewId, Object tag) {
|
||||
View view = getView(viewId);
|
||||
view.setTag(tag);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,479 @@
|
||||
|
||||
package com.superrecycleview.superlibrary.adapter;
|
||||
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.content.Context;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by super南仔 on 07/28/16. blog: http://supercwn.github.io/ GitHub:
|
||||
* https://github.com/supercwn
|
||||
*/
|
||||
public abstract class SuperBaseAdapter<T> extends RecyclerView.Adapter<BaseViewHolder> {
|
||||
private static final String TAG = "SuperBaseAdapter";
|
||||
|
||||
public static class VIEW_TYPE {
|
||||
public static final int HEADER = 0x0010;
|
||||
public static final int FOOTER = 0x0011;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base config
|
||||
*/
|
||||
public List<T> mData;
|
||||
private Context mContext;
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
/**
|
||||
* Listener
|
||||
*/
|
||||
private OnItemClickListener mOnItemClickListener;
|
||||
private OnItemLongClickListener mOnItemLongClickListener;
|
||||
private OnRecyclerViewItemChildClickListener mChildClickListener;
|
||||
private OnRecyclerViewItemChildLongClickListener mChildLongClickListener;
|
||||
|
||||
/**
|
||||
* View type
|
||||
*/
|
||||
private Map<Integer, Integer> layoutIdMap, viewTypeMap;
|
||||
private int mCurrentViewTypeValue = 0x0107;
|
||||
|
||||
/**
|
||||
* Animation
|
||||
*/
|
||||
private AnimationType mAnimationType;
|
||||
private int mAnimationDuration = 300;
|
||||
private boolean showItemAnimationEveryTime = false;
|
||||
private Interpolator mItemAnimationInterpolator;
|
||||
private CustomAnimator mCustomAnimator;
|
||||
private int mLastItemPosition = -1;
|
||||
|
||||
/**
|
||||
* header and footer
|
||||
*/
|
||||
private LinearLayout mHeaderLayout;
|
||||
private LinearLayout mFooterLayout;
|
||||
private LinearLayout mCopyHeaderLayout = null;
|
||||
private LinearLayout mCopyFooterLayout = null;
|
||||
|
||||
public SuperBaseAdapter(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public SuperBaseAdapter(Context context, List<T> data) {
|
||||
mData = null == data ? new ArrayList<T>() : data;
|
||||
layoutIdMap = new HashMap<>();
|
||||
viewTypeMap = new HashMap<>();
|
||||
mContext = context;
|
||||
mInflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
BaseViewHolder baseViewHolder;
|
||||
switch (viewType) {
|
||||
case VIEW_TYPE.HEADER:// header
|
||||
baseViewHolder = new BaseViewHolder(mHeaderLayout, mContext);
|
||||
break;
|
||||
case VIEW_TYPE.FOOTER:// footer
|
||||
baseViewHolder = new BaseViewHolder(mFooterLayout, mContext);
|
||||
break;
|
||||
default:
|
||||
baseViewHolder = new BaseViewHolder(mInflater.inflate(layoutIdMap.get(viewType),
|
||||
parent, false), mContext);
|
||||
initItemClickListener(baseViewHolder);
|
||||
break;
|
||||
}
|
||||
return baseViewHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (position < getHeaderViewCount()) {
|
||||
return VIEW_TYPE.HEADER;
|
||||
} else if (position >= mData.size() + getHeaderViewCount()) {
|
||||
return VIEW_TYPE.FOOTER;
|
||||
} else {
|
||||
int currentPosition = position - getHeaderViewCount();
|
||||
int currentLayoutId = getItemViewLayoutId(currentPosition, mData.get(currentPosition));
|
||||
if (!viewTypeMap.containsKey(currentLayoutId)) {
|
||||
mCurrentViewTypeValue++;
|
||||
viewTypeMap.put(currentLayoutId, mCurrentViewTypeValue);
|
||||
layoutIdMap.put(viewTypeMap.get(currentLayoutId), currentLayoutId);
|
||||
}
|
||||
return viewTypeMap.get(currentLayoutId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(BaseViewHolder holder, int position) {
|
||||
switch (getItemViewType(position)) {
|
||||
case VIEW_TYPE.HEADER:
|
||||
// Do nothing
|
||||
break;
|
||||
case VIEW_TYPE.FOOTER:
|
||||
// Do nothing
|
||||
break;
|
||||
default:
|
||||
convert(holder, getItem(position - getHeaderViewCount()), position -
|
||||
getHeaderViewCount());
|
||||
addAnimation(holder);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected final void addAnimation(final BaseViewHolder holder) {
|
||||
int currentPosition = holder.getAdapterPosition();
|
||||
if (null != mCustomAnimator) {
|
||||
mCustomAnimator.getAnimator(holder.itemView).setDuration(mAnimationDuration).start();
|
||||
} else if (null != mAnimationType) {
|
||||
if (showItemAnimationEveryTime || currentPosition > mLastItemPosition) {
|
||||
new AnimationUtil()
|
||||
.setAnimationType(mAnimationType)
|
||||
.setTargetView(holder.itemView)
|
||||
.setDuration(mAnimationDuration)
|
||||
.setInterpolator(mItemAnimationInterpolator)
|
||||
.start();
|
||||
mLastItemPosition = currentPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* init the baseViewHolder to register mOnItemClickListener and
|
||||
* mOnItemLongClickListener
|
||||
*
|
||||
* @param holder
|
||||
*/
|
||||
protected final void initItemClickListener(final BaseViewHolder holder) {
|
||||
if (null != mOnItemClickListener) {
|
||||
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
final int position = holder.getAdapterPosition() - getHeaderViewCount();
|
||||
mOnItemClickListener.onItemClick(view, position);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (null != mOnItemLongClickListener) {
|
||||
holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
final int position = holder.getAdapterPosition() - getHeaderViewCount();
|
||||
mOnItemLongClickListener.onItemLongClick(v, position);
|
||||
return true;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base api
|
||||
*/
|
||||
protected abstract void convert(BaseViewHolder holder, T item, int position);
|
||||
|
||||
protected abstract int getItemViewLayoutId(int position, T item);
|
||||
|
||||
protected T getItem(int position) {
|
||||
return mData.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mData.size() + getHeaderViewCount() + getFooterViewCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener api
|
||||
*/
|
||||
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
|
||||
mOnItemClickListener = onItemClickListener;
|
||||
}
|
||||
|
||||
public void setOnItemLongClickListener(OnItemLongClickListener onItemLongClickListener) {
|
||||
mOnItemLongClickListener = onItemLongClickListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when childView in this AdapterView has
|
||||
* been clicked and held {@link OnRecyclerViewItemChildClickListener}
|
||||
*
|
||||
* @param childClickListener The callback that will run
|
||||
*/
|
||||
public void setOnItemChildClickListener(
|
||||
OnRecyclerViewItemChildClickListener childClickListener) {
|
||||
this.mChildClickListener = childClickListener;
|
||||
}
|
||||
|
||||
public class OnItemChildClickListener implements View.OnClickListener {
|
||||
public RecyclerView.ViewHolder mViewHolder;
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mChildClickListener != null)
|
||||
mChildClickListener.onItemChildClick(SuperBaseAdapter.this, v,
|
||||
mViewHolder.getLayoutPosition() - getHeaderViewCount());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be invoked when childView in this AdapterView has
|
||||
* been longClicked and held
|
||||
* {@link OnRecyclerViewItemChildLongClickListener}
|
||||
*
|
||||
* @param childLongClickListener The callback that will run
|
||||
*/
|
||||
public void setOnItemChildLongClickListener(
|
||||
OnRecyclerViewItemChildLongClickListener childLongClickListener) {
|
||||
this.mChildLongClickListener = childLongClickListener;
|
||||
}
|
||||
|
||||
public class OnItemChildLongClickListener implements View.OnLongClickListener {
|
||||
public RecyclerView.ViewHolder mViewHolder;
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
if (mChildLongClickListener != null) {
|
||||
return mChildLongClickListener.onItemChildLongClick(SuperBaseAdapter.this, v,
|
||||
mViewHolder.getLayoutPosition() - getHeaderViewCount());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Animation api
|
||||
*/
|
||||
public void setItemAnimation(AnimationType animationType) {
|
||||
mAnimationType = animationType;
|
||||
}
|
||||
|
||||
public void setItemAnimationDuration(int animationDuration) {
|
||||
mAnimationDuration = animationDuration;
|
||||
}
|
||||
|
||||
public void setItemAnimationInterpolator(Interpolator animationInterpolator) {
|
||||
mItemAnimationInterpolator = animationInterpolator;
|
||||
}
|
||||
|
||||
public void setShowItemAnimationEveryTime(boolean showItemAnimationEveryTime) {
|
||||
this.showItemAnimationEveryTime = showItemAnimationEveryTime;
|
||||
}
|
||||
|
||||
public void setCustomItemAnimator(CustomAnimator customAnimator) {
|
||||
mCustomAnimator = customAnimator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Header and footer api
|
||||
*/
|
||||
public LinearLayout getHeaderLayout() {
|
||||
return mHeaderLayout;
|
||||
}
|
||||
|
||||
public LinearLayout getFooterLayout() {
|
||||
return mFooterLayout;
|
||||
}
|
||||
|
||||
public void addHeaderView(View header) {
|
||||
addHeaderView(header, -1);
|
||||
}
|
||||
|
||||
public void addHeaderView(View header, int index) {
|
||||
if (mHeaderLayout == null) {
|
||||
if (mCopyHeaderLayout == null) {
|
||||
mHeaderLayout = new LinearLayout(header.getContext());
|
||||
mHeaderLayout.setOrientation(LinearLayout.VERTICAL);
|
||||
mHeaderLayout
|
||||
.setLayoutParams(new RecyclerView.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
|
||||
mCopyHeaderLayout = mHeaderLayout;
|
||||
} else {
|
||||
mHeaderLayout = mCopyHeaderLayout;
|
||||
}
|
||||
}
|
||||
index = index >= mHeaderLayout.getChildCount() ? -1 : index;
|
||||
mHeaderLayout.addView(header, index);
|
||||
this.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void addFooterView(View footer) {
|
||||
addFooterView(footer, -1);
|
||||
}
|
||||
|
||||
public void addFooterView(View footer, int index) {
|
||||
if (mFooterLayout == null) {
|
||||
if (mCopyFooterLayout == null) {
|
||||
mFooterLayout = new LinearLayout(footer.getContext());
|
||||
mFooterLayout.setOrientation(LinearLayout.VERTICAL);
|
||||
mFooterLayout
|
||||
.setLayoutParams(new RecyclerView.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
|
||||
mCopyFooterLayout = mFooterLayout;
|
||||
} else {
|
||||
mFooterLayout = mCopyFooterLayout;
|
||||
}
|
||||
}
|
||||
index = index >= mFooterLayout.getChildCount() ? -1 : index;
|
||||
mFooterLayout.addView(footer, index);
|
||||
this.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void removeHeaderView(View header) {
|
||||
if (mHeaderLayout == null)
|
||||
return;
|
||||
|
||||
mHeaderLayout.removeView(header);
|
||||
if (mHeaderLayout.getChildCount() == 0) {
|
||||
mHeaderLayout = null;
|
||||
}
|
||||
this.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void removeFooterView(View footer) {
|
||||
if (mFooterLayout == null)
|
||||
return;
|
||||
|
||||
mFooterLayout.removeView(footer);
|
||||
if (mFooterLayout.getChildCount() == 0) {
|
||||
mFooterLayout = null;
|
||||
}
|
||||
this.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void removeAllHeaderView() {
|
||||
if (mHeaderLayout == null)
|
||||
return;
|
||||
|
||||
mHeaderLayout.removeAllViews();
|
||||
mHeaderLayout = null;
|
||||
}
|
||||
|
||||
public void removeAllFooterView() {
|
||||
if (mFooterLayout == null)
|
||||
return;
|
||||
|
||||
mFooterLayout.removeAllViews();
|
||||
mFooterLayout = null;
|
||||
}
|
||||
|
||||
public int getHeaderViewCount() {
|
||||
return null == mHeaderLayout ? 0 : 1;
|
||||
}
|
||||
|
||||
public int getFooterViewCount() {
|
||||
return null == mFooterLayout ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some interface
|
||||
*/
|
||||
public interface OnItemClickListener {
|
||||
void onItemClick(View view, int position);
|
||||
}
|
||||
|
||||
public interface OnItemLongClickListener {
|
||||
void onItemLongClick(View view, int position);
|
||||
}
|
||||
|
||||
public interface OnRecyclerViewItemChildClickListener {
|
||||
void onItemChildClick(SuperBaseAdapter adapter, View view, int position);
|
||||
}
|
||||
|
||||
public interface OnRecyclerViewItemChildLongClickListener {
|
||||
boolean onItemChildLongClick(SuperBaseAdapter adapter, View view, int position);
|
||||
}
|
||||
|
||||
public interface CustomAnimator {
|
||||
Animator getAnimator(View itemView);
|
||||
}
|
||||
|
||||
private SpanSizeLookup mSpanSizeLookup;
|
||||
|
||||
public interface SpanSizeLookup {
|
||||
int getSpanSize(GridLayoutManager gridLayoutManager, int position);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param spanSizeLookup instance to be used to query number of spans
|
||||
* occupied by each item
|
||||
*/
|
||||
public void setSpanSizeLookup(SpanSizeLookup spanSizeLookup) {
|
||||
this.mSpanSizeLookup = spanSizeLookup;
|
||||
}
|
||||
|
||||
// 处理GridLayoutManager添加头部以及添加底部的错误
|
||||
@Override
|
||||
public void onAttachedToRecyclerView(final RecyclerView recyclerView) {
|
||||
super.onAttachedToRecyclerView(recyclerView);
|
||||
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
|
||||
if (manager instanceof GridLayoutManager) {
|
||||
final GridLayoutManager gridManager = ((GridLayoutManager) manager);
|
||||
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
|
||||
@Override
|
||||
public int getSpanSize(int position) {
|
||||
int type = getItemViewType(position - 1);
|
||||
if (mSpanSizeLookup == null)
|
||||
return (type == VIEW_TYPE.HEADER || type == VIEW_TYPE.FOOTER)
|
||||
? gridManager.getSpanCount() : 1;
|
||||
else
|
||||
return (type == VIEW_TYPE.HEADER || type == VIEW_TYPE.FOOTER)
|
||||
? gridManager.getSpanCount()
|
||||
: mSpanSizeLookup.getSpanSize(gridManager,
|
||||
position - getHeaderViewCount());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 处理StaggeredGridLayoutManager添加头部以及添加底部的
|
||||
@Override
|
||||
public void onViewAttachedToWindow(BaseViewHolder holder) {
|
||||
super.onViewAttachedToWindow(holder);
|
||||
super.onViewAttachedToWindow(holder);
|
||||
int type = holder.getItemViewType();
|
||||
if (type == VIEW_TYPE.HEADER || type == VIEW_TYPE.FOOTER) {
|
||||
if (holder.itemView
|
||||
.getLayoutParams() instanceof StaggeredGridLayoutManager.LayoutParams) {
|
||||
StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) holder.itemView
|
||||
.getLayoutParams();
|
||||
params.setFullSpan(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * 刷新数据,初始化数据
|
||||
*/
|
||||
public void setDatas(List<T> list) {
|
||||
if (this.mData != null) {
|
||||
if (null != list) {
|
||||
List<T> temp = new ArrayList<>();
|
||||
temp.addAll(list);
|
||||
this.mData.clear();
|
||||
this.mData.addAll(temp);
|
||||
} else {
|
||||
this.mData.clear();
|
||||
}
|
||||
} else {
|
||||
this.mData = list;
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,202 @@
|
||||
package com.superrecycleview.superlibrary.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.view.MotionEventCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import com.superrecycleview.superlibrary.R;
|
||||
import com.superrecycleview.superlibrary.callback.OnItemDragListener;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by super南仔 on 07/28/16.
|
||||
* blog: http://supercwn.github.io/
|
||||
* GitHub: https://github.com/supercwn
|
||||
*/
|
||||
public abstract class SuperBaseDragAdapter<T> extends SuperBaseAdapter<T> {
|
||||
|
||||
private static final int NO_TOGGLE_VIEW = 0;
|
||||
private int mToggleViewId = NO_TOGGLE_VIEW;
|
||||
private ItemTouchHelper mItemTouchHelper;
|
||||
private boolean itemDragEnabled = false;
|
||||
private boolean itemSwipeEnabled = false;
|
||||
private OnItemDragListener mOnItemDragListener;
|
||||
private boolean mDragOnLongPress = true;
|
||||
|
||||
private View.OnTouchListener mOnToggleViewTouchListener;
|
||||
private View.OnLongClickListener mOnToggleViewLongClickListener;
|
||||
|
||||
public SuperBaseDragAdapter(Context context, List<T> data) {
|
||||
super(context, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(BaseViewHolder holder, int position) {
|
||||
super.onBindViewHolder(holder, position);
|
||||
int viewType = holder.getItemViewType();
|
||||
if (mItemTouchHelper != null && itemDragEnabled ) {
|
||||
if (mToggleViewId != NO_TOGGLE_VIEW) {
|
||||
View toggleView = holder.getView(mToggleViewId);
|
||||
if (toggleView != null) {
|
||||
toggleView.setTag(R.id.BaseQuickAdapter_viewholder_support, holder);
|
||||
if (mDragOnLongPress) {
|
||||
toggleView.setOnLongClickListener(mOnToggleViewLongClickListener);
|
||||
} else {
|
||||
toggleView.setOnTouchListener(mOnToggleViewTouchListener);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
holder.itemView.setTag(R.id.BaseQuickAdapter_viewholder_support, holder);
|
||||
holder.itemView.setOnLongClickListener(mOnToggleViewLongClickListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the toggle view's id which will trigger drag event.
|
||||
* If the toggle view id is not set, drag event will be triggered when the item is long pressed.
|
||||
*
|
||||
* @param toggleViewId the toggle view's id
|
||||
*/
|
||||
public void setToggleViewId(int toggleViewId) {
|
||||
mToggleViewId = toggleViewId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the drag event should be trigger on long press.
|
||||
* Work when the toggleViewId has been set.
|
||||
*
|
||||
* @param longPress by default is true.
|
||||
*/
|
||||
public void setToggleDragOnLongPress(boolean longPress) {
|
||||
mDragOnLongPress = longPress;
|
||||
if (mDragOnLongPress) {
|
||||
mOnToggleViewTouchListener = null;
|
||||
mOnToggleViewLongClickListener = new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
if (mItemTouchHelper != null && itemDragEnabled) {
|
||||
mItemTouchHelper.startDrag((RecyclerView.ViewHolder) v.getTag(R.id.BaseQuickAdapter_viewholder_support));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
mOnToggleViewTouchListener = new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN
|
||||
&& !mDragOnLongPress) {
|
||||
if (mItemTouchHelper != null && itemDragEnabled) {
|
||||
mItemTouchHelper.startDrag((RecyclerView.ViewHolder) v.getTag(R.id.BaseQuickAdapter_viewholder_support));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
mOnToggleViewLongClickListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable drag items.
|
||||
* Use itemView as the toggleView when long pressed.
|
||||
*
|
||||
* @param itemTouchHelper {@link ItemTouchHelper}
|
||||
*/
|
||||
public void enableDragItem(@NonNull ItemTouchHelper itemTouchHelper) {
|
||||
enableDragItem(itemTouchHelper, NO_TOGGLE_VIEW, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable drag items. Use the specified view as toggle.
|
||||
*
|
||||
* @param itemTouchHelper {@link ItemTouchHelper}
|
||||
* @param toggleViewId The toggle view's id.
|
||||
* @param dragOnLongPress If true the drag event will be trigger on long press, otherwise on touch down.
|
||||
*/
|
||||
public void enableDragItem(@NonNull ItemTouchHelper itemTouchHelper, int toggleViewId, boolean dragOnLongPress) {
|
||||
itemDragEnabled = true;
|
||||
mItemTouchHelper = itemTouchHelper;
|
||||
setToggleViewId(toggleViewId);
|
||||
setToggleDragOnLongPress(dragOnLongPress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable drag items.
|
||||
*/
|
||||
public void disableDragItem() {
|
||||
itemDragEnabled = false;
|
||||
mItemTouchHelper = null;
|
||||
}
|
||||
|
||||
public boolean isItemDraggable() {
|
||||
return itemDragEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Enable swipe items.</p>
|
||||
*/
|
||||
public void enableSwipeItem() {
|
||||
itemSwipeEnabled = true;
|
||||
}
|
||||
|
||||
public void disableSwipeItem() {
|
||||
itemSwipeEnabled = false;
|
||||
}
|
||||
|
||||
public boolean isItemSwipeEnable() {
|
||||
return itemSwipeEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param onItemDragListener Register a callback to be invoked when drag event happen.
|
||||
*/
|
||||
public void setOnItemDragListener(OnItemDragListener onItemDragListener) {
|
||||
mOnItemDragListener = onItemDragListener;
|
||||
}
|
||||
|
||||
public int getViewHolderPosition(RecyclerView.ViewHolder viewHolder) {
|
||||
return viewHolder.getAdapterPosition() - getHeaderViewCount() -1;
|
||||
}
|
||||
|
||||
public void onItemDragStart(RecyclerView.ViewHolder viewHolder) {
|
||||
if (mOnItemDragListener != null && itemDragEnabled) {
|
||||
mOnItemDragListener.onItemDragStart(viewHolder, getViewHolderPosition(viewHolder));
|
||||
}
|
||||
}
|
||||
|
||||
public void onItemDragMoving(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
|
||||
int from = getViewHolderPosition(source);
|
||||
int to = getViewHolderPosition(target);
|
||||
|
||||
if (from < to) {
|
||||
for (int i = from; i < to; i++) {
|
||||
Collections.swap(mData, i, i + 1);
|
||||
}
|
||||
} else {
|
||||
for (int i = from; i > to; i--) {
|
||||
Collections.swap(mData, i, i - 1);
|
||||
}
|
||||
}
|
||||
notifyItemMoved(source.getAdapterPosition(), target.getAdapterPosition());
|
||||
|
||||
if (mOnItemDragListener != null && itemDragEnabled) {
|
||||
mOnItemDragListener.onItemDragMoving(source, from, target, to);
|
||||
}
|
||||
}
|
||||
|
||||
public void onItemDragEnd(RecyclerView.ViewHolder viewHolder) {
|
||||
if (mOnItemDragListener != null && itemDragEnabled) {
|
||||
mOnItemDragListener.onItemDragEnd(viewHolder, getViewHolderPosition(viewHolder));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,238 @@
|
||||
|
||||
package com.superrecycleview.superlibrary.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.collection.SparseArrayCompat;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* 介绍:一个给RecyclerView添加HeaderView FooterView的装饰Adapter类 重点哦~
|
||||
* RecyclerView的HeaderView将可以被系统回收,不像老版的HeaderView是一个强引用在内存里 作者:zhangxutong
|
||||
* 邮箱:zhangxutong@imcoming.com 时间: 2016/8/2.
|
||||
*/
|
||||
public abstract class SuperHeaderAndFooterAdapter
|
||||
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
private static final int BASE_ITEM_TYPE_HEADER = 1000000;// headerview的viewtype基准值
|
||||
private static final int BASE_ITEM_TYPE_FOOTER = 2000000;// footerView的ViewType基准值
|
||||
|
||||
// 存放HeaderViews的layoudID和data,key是viewType,value 是 layoudID和data,
|
||||
// 在createViewHOlder里根据layoutId创建UI,
|
||||
// 在onbindViewHOlder里依据这个data渲染UI,同时也将layoutId回传出去用于判断何种Header
|
||||
private SparseArrayCompat<SparseArrayCompat> mHeaderDatas = new SparseArrayCompat<SparseArrayCompat>();
|
||||
private SparseArrayCompat<View> mFooterViews = new SparseArrayCompat<>();// 存放FooterViews,key是viewType
|
||||
|
||||
protected RecyclerView.Adapter mInnerAdapter;// 内部的的普通Adapter
|
||||
private Context mContext;
|
||||
|
||||
public SuperHeaderAndFooterAdapter(Context mContext,
|
||||
RecyclerView.Adapter mInnerAdapter) {
|
||||
this.mInnerAdapter = mInnerAdapter;
|
||||
this.mContext = mContext;
|
||||
}
|
||||
|
||||
public int getHeaderViewCount() {
|
||||
return mHeaderDatas.size();
|
||||
}
|
||||
|
||||
public int getFooterViewCount() {
|
||||
return mFooterViews.size();
|
||||
}
|
||||
|
||||
private int getInnerItemCount() {
|
||||
return mInnerAdapter != null ? mInnerAdapter.getItemCount() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 传入position 判断是否是headerview
|
||||
*
|
||||
* @param position
|
||||
* @return
|
||||
*/
|
||||
public boolean isHeaderViewPos(int position) {// 举例, 2 个头,pos 0 1,true, 2+
|
||||
return getHeaderViewCount() > position;
|
||||
}
|
||||
|
||||
/**
|
||||
* 传入postion判断是否是footerview
|
||||
*
|
||||
* @param position
|
||||
* @return
|
||||
*/
|
||||
public boolean isFooterViewPos(int position) {// 举例, 2个头,2个inner,pos 0 1 2
|
||||
// 3// ,false,4+true
|
||||
return position >= getHeaderViewCount() + getInnerItemCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加HeaderView
|
||||
*
|
||||
* @param layoutId headerView 的LayoutId
|
||||
* @param data headerView 的data(可能多种不同类型的header 只能用Object了)
|
||||
*/
|
||||
public void addHeaderView(int layoutId, Object data) {
|
||||
SparseArrayCompat headerContainer = new SparseArrayCompat();
|
||||
headerContainer.put(layoutId, data);
|
||||
mHeaderDatas.put(mHeaderDatas.size() + BASE_ITEM_TYPE_HEADER, headerContainer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置(更新)某个layoutId的HeaderView的数据
|
||||
*
|
||||
* @param layoutId
|
||||
* @param data
|
||||
*/
|
||||
public void setHeaderView(int layoutId, Object data) {
|
||||
boolean isFinded = false;
|
||||
for (int i = 0; i < mHeaderDatas.size(); i++) {
|
||||
SparseArrayCompat sparse = mHeaderDatas.valueAt(i);
|
||||
if (layoutId == sparse.keyAt(0)) {
|
||||
sparse.setValueAt(0, data);
|
||||
isFinded = true;
|
||||
}
|
||||
}
|
||||
if (!isFinded) {// 没发现 说明是addHeaderView
|
||||
addHeaderView(layoutId, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置某个位置的HeaderView
|
||||
*
|
||||
* @param headerPos 从0开始,如果pos过大 就是addHeaderview
|
||||
* @param layoutId
|
||||
* @param data
|
||||
*/
|
||||
public void setHeaderView(int headerPos, int layoutId, Object data) {
|
||||
if (mHeaderDatas.size() > headerPos) {
|
||||
SparseArrayCompat headerContainer = new SparseArrayCompat();
|
||||
headerContainer.put(layoutId, data);
|
||||
mHeaderDatas.setValueAt(headerPos, headerContainer);
|
||||
} else if (mHeaderDatas.size() == headerPos) {// 调用addHeaderView
|
||||
addHeaderView(layoutId, data);
|
||||
} else {
|
||||
//
|
||||
addHeaderView(layoutId, data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加FooterView
|
||||
*
|
||||
* @param v
|
||||
*/
|
||||
public void addFooterView(View v) {
|
||||
mFooterViews.put(mFooterViews.size() + BASE_ITEM_TYPE_FOOTER, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空HeaderView数据
|
||||
*/
|
||||
public void clearHeaderView() {
|
||||
mHeaderDatas.clear();
|
||||
}
|
||||
|
||||
public void clearFooterView() {
|
||||
mFooterViews.clear();
|
||||
}
|
||||
|
||||
public void setFooterView(View v) {
|
||||
clearFooterView();
|
||||
addFooterView(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (isHeaderViewPos(position)) {
|
||||
return mHeaderDatas.keyAt(position);
|
||||
} else if (isFooterViewPos(position)) {// 举例:header 2, innter 2,
|
||||
// 0123都不是,4才是,4-2-2 = 0,ok。
|
||||
return mFooterViews.keyAt(position - getHeaderViewCount() - getInnerItemCount());
|
||||
}
|
||||
return super.getItemViewType(position - getHeaderViewCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
if (mHeaderDatas.get(viewType) != null) {
|
||||
View itemView = LayoutInflater.from(mContext).inflate(
|
||||
mHeaderDatas.get(viewType).keyAt(0), parent,
|
||||
false);
|
||||
return new BaseViewHolder(itemView, mContext);
|
||||
} else if (mFooterViews.get(viewType) != null) {// 不为空,说明是footerview
|
||||
return new BaseViewHolder(mFooterViews.get(viewType), mContext);
|
||||
}
|
||||
return mInnerAdapter.onCreateViewHolder(parent, viewType);
|
||||
|
||||
}
|
||||
|
||||
protected abstract void onBindHeaderHolder(BaseViewHolder holder, int headerPos, int layoutId,
|
||||
Object object);// 多回传一个layoutId出去,用于判断是第几个headerview
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
||||
if (isHeaderViewPos(position)) {
|
||||
int layoutId = mHeaderDatas.get(getItemViewType(position)).keyAt(0);
|
||||
onBindHeaderHolder((BaseViewHolder) holder, position, layoutId,
|
||||
mHeaderDatas.get(getItemViewType(position)).get(layoutId));
|
||||
return;
|
||||
} else if (isFooterViewPos(position)) {
|
||||
return;
|
||||
}
|
||||
// 举例子,2个header,0 1是头,2是开始,2-2 = 0
|
||||
mInnerAdapter.onBindViewHolder(holder, position - getHeaderViewCount());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return getInnerItemCount() + getHeaderViewCount() + getFooterViewCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
|
||||
mInnerAdapter.onAttachedToRecyclerView(recyclerView);
|
||||
// 为了兼容GridLayout
|
||||
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
|
||||
if (layoutManager instanceof GridLayoutManager) {
|
||||
final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
|
||||
final GridLayoutManager.SpanSizeLookup spanSizeLookup = gridLayoutManager
|
||||
.getSpanSizeLookup();
|
||||
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
|
||||
@Override
|
||||
public int getSpanSize(int position) {
|
||||
int viewType = getItemViewType(position);
|
||||
if (mHeaderDatas.get(viewType) != null) {
|
||||
return gridLayoutManager.getSpanCount();
|
||||
} else if (mFooterViews.get(viewType) != null) {
|
||||
return gridLayoutManager.getSpanCount();
|
||||
}
|
||||
if (spanSizeLookup != null)
|
||||
return spanSizeLookup.getSpanSize(position);
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
gridLayoutManager.setSpanCount(gridLayoutManager.getSpanCount());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
|
||||
mInnerAdapter.onViewAttachedToWindow(holder);
|
||||
int position = holder.getLayoutPosition();
|
||||
if (isHeaderViewPos(position) || isFooterViewPos(position)) {
|
||||
ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
|
||||
|
||||
if (lp != null
|
||||
&& lp instanceof StaggeredGridLayoutManager.LayoutParams) {
|
||||
|
||||
StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
|
||||
|
||||
p.setFullSpan(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
|
||||
package com.superrecycleview.superlibrary.callback;
|
||||
|
||||
/**
|
||||
* 介绍:分类悬停的接口 作者:zhangxutong 邮箱:mcxtzhang@163.com
|
||||
* 主页:http://blog.csdn.net/zxt0601 时间: 2016/11/7.
|
||||
*/
|
||||
|
||||
public interface ISuspensionInterface {
|
||||
// 是否需要显示悬停title
|
||||
boolean isShowSuspension();
|
||||
|
||||
// 悬停的title
|
||||
String getSuspensionTag();
|
||||
|
||||
}
|
||||
@ -0,0 +1,149 @@
|
||||
package com.superrecycleview.superlibrary.callback;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
|
||||
import com.superrecycleview.superlibrary.R;
|
||||
import com.superrecycleview.superlibrary.adapter.SuperBaseAdapter;
|
||||
import com.superrecycleview.superlibrary.adapter.SuperBaseDragAdapter;
|
||||
/**
|
||||
* Created by super南仔 on 07/28/16.
|
||||
* blog: http://supercwn.github.io/
|
||||
* GitHub: https://github.com/supercwn
|
||||
*/
|
||||
public class ItemDragCallback extends ItemTouchHelper.Callback {
|
||||
|
||||
// private static final String TAG = ItemDragCallback.class.getSimpleName();
|
||||
|
||||
SuperBaseDragAdapter mAdapter;
|
||||
|
||||
float mMoveThreshold = 0.1f;
|
||||
float mSwipeThreshold = 0.7f;
|
||||
|
||||
int mDragMoveFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
|
||||
int mSwipeMoveFlags = ItemTouchHelper.END;
|
||||
|
||||
public ItemDragCallback(SuperBaseDragAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLongPressDragEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemViewSwipeEnabled() {
|
||||
return mAdapter.isItemSwipeEnable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG
|
||||
&& !isViewCreateByAdapter(viewHolder)) {
|
||||
mAdapter.onItemDragStart(viewHolder);
|
||||
viewHolder.itemView.setTag(R.id.BaseQuickAdapter_dragging_support, true);
|
||||
}
|
||||
super.onSelectedChanged(viewHolder, actionState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||
super.clearView(recyclerView, viewHolder);
|
||||
if (isViewCreateByAdapter(viewHolder)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (viewHolder.itemView.getTag(R.id.BaseQuickAdapter_dragging_support) != null
|
||||
&& (Boolean)viewHolder.itemView.getTag(R.id.BaseQuickAdapter_dragging_support)) {
|
||||
mAdapter.onItemDragEnd(viewHolder);
|
||||
viewHolder.itemView.setTag(R.id.BaseQuickAdapter_dragging_support, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||
if (isViewCreateByAdapter(viewHolder)) {
|
||||
return makeMovementFlags(0, 0);
|
||||
}
|
||||
|
||||
return makeMovementFlags(mDragMoveFlags, mSwipeMoveFlags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
|
||||
return source.getItemViewType() == target.getItemViewType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder source, int fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) {
|
||||
mAdapter.onItemDragMoving(source, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMoveThreshold(RecyclerView.ViewHolder viewHolder) {
|
||||
return mMoveThreshold;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
|
||||
return mSwipeThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the fraction that the user should move the View to be considered as swiped.
|
||||
* The fraction is calculated with respect to RecyclerView's bounds.
|
||||
* <p>
|
||||
* Default value is .5f, which means, to swipe a View, user must move the View at least
|
||||
* half of RecyclerView's width or height, depending on the swipe direction.
|
||||
*
|
||||
* @param swipeThreshold A float value that denotes the fraction of the View size. Default value
|
||||
* is .8f .
|
||||
*/
|
||||
public void setSwipeThreshold(float swipeThreshold) {
|
||||
mSwipeThreshold = swipeThreshold;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the fraction that the user should move the View to be considered as it is
|
||||
* dragged. After a view is moved this amount, ItemTouchHelper starts checking for Views
|
||||
* below it for a possible drop.
|
||||
*
|
||||
* @param moveThreshold A float value that denotes the fraction of the View size. Default value is
|
||||
* .1f .
|
||||
*/
|
||||
public void setMoveThreshold(float moveThreshold) {
|
||||
mMoveThreshold = moveThreshold;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Set the drag movement direction.</p>
|
||||
* <p>The value should be ItemTouchHelper.UP, ItemTouchHelper.DOWN, ItemTouchHelper.LEFT, ItemTouchHelper.RIGHT or their combination.</p>
|
||||
* You can combine them like ItemTouchHelper.UP | ItemTouchHelper.DOWN, it means that the item could only move up and down when dragged.
|
||||
* @param dragMoveFlags the drag movement direction. Default value is ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT.
|
||||
*/
|
||||
public void setDragMoveFlags(int dragMoveFlags) {
|
||||
mDragMoveFlags = dragMoveFlags;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Set the swipe movement direction.</p>
|
||||
* <p>The value should be ItemTouchHelper.START, ItemTouchHelper.END or their combination.</p>
|
||||
* You can combine them like ItemTouchHelper.START | ItemTouchHelper.END, it means that the item could swipe to both left or right.
|
||||
* @param swipeMoveFlags the swipe movement direction. Default value is ItemTouchHelper.END.
|
||||
*/
|
||||
public void setSwipeMoveFlags(int swipeMoveFlags) {
|
||||
mSwipeMoveFlags = swipeMoveFlags;
|
||||
}
|
||||
|
||||
private boolean isViewCreateByAdapter(RecyclerView.ViewHolder viewHolder) {
|
||||
int type = viewHolder.getItemViewType();
|
||||
return type == SuperBaseAdapter.VIEW_TYPE.HEADER || type == SuperBaseAdapter.VIEW_TYPE.FOOTER;
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package com.superrecycleview.superlibrary.callback;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* Created by super南仔 on 07/28/16.
|
||||
* blog: http://supercwn.github.io/
|
||||
* GitHub: https://github.com/supercwn
|
||||
*/
|
||||
public interface OnItemDragListener {
|
||||
void onItemDragStart(RecyclerView.ViewHolder viewHolder, int pos);
|
||||
void onItemDragMoving(RecyclerView.ViewHolder source, int from, RecyclerView.ViewHolder target, int to);
|
||||
void onItemDragEnd(RecyclerView.ViewHolder viewHolder, int pos);
|
||||
|
||||
}
|
||||
@ -0,0 +1,300 @@
|
||||
|
||||
package com.superrecycleview.superlibrary.callback;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 介绍:分类、悬停的Decoration 作者:zhangxutong 邮箱:mcxtzhang@163.com
|
||||
* 主页:http://blog.csdn.net/zxt0601 时间: 2016/11/7.
|
||||
*/
|
||||
|
||||
public class SuspensionDecoration extends RecyclerView.ItemDecoration {
|
||||
private List<? extends ISuspensionInterface> mDatas;
|
||||
private Paint mPaint;
|
||||
private Rect mBounds;// 用于存放测量文字Rect
|
||||
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
private int mTitleHeight;// title的高
|
||||
private static int COLOR_TITLE_BG = Color.parseColor("#FFDFDFDF");
|
||||
private static int COLOR_TITLE_FONT = Color.parseColor("#FF999999");
|
||||
private static int mTitleFontSize;// title字体大小
|
||||
|
||||
private int mHeaderViewCount = 0;
|
||||
|
||||
public SuspensionDecoration(Context context, List<? extends ISuspensionInterface> datas) {
|
||||
super();
|
||||
mDatas = datas;
|
||||
mPaint = new Paint();
|
||||
mBounds = new Rect();
|
||||
mTitleHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30,
|
||||
context.getResources().getDisplayMetrics());
|
||||
mTitleFontSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16,
|
||||
context.getResources().getDisplayMetrics());
|
||||
mPaint.setTextSize(mTitleFontSize);
|
||||
mPaint.setAntiAlias(true);
|
||||
mInflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
public SuspensionDecoration setmTitleHeight(int mTitleHeight) {
|
||||
this.mTitleHeight = mTitleHeight;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuspensionDecoration setColorTitleBg(int colorTitleBg) {
|
||||
COLOR_TITLE_BG = colorTitleBg;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuspensionDecoration setColorTitleFont(int colorTitleFont) {
|
||||
COLOR_TITLE_FONT = colorTitleFont;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuspensionDecoration setTitleFontSize(int mTitleFontSize) {
|
||||
mPaint.setTextSize(mTitleFontSize);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuspensionDecoration setDatas(List<? extends ISuspensionInterface> mDatas) {
|
||||
this.mDatas = mDatas;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getHeaderViewCount() {
|
||||
return mHeaderViewCount;
|
||||
}
|
||||
|
||||
public SuspensionDecoration setHeaderViewCount(int headerViewCount) {
|
||||
mHeaderViewCount = headerViewCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
||||
super.onDraw(c, parent, state);
|
||||
final int left = parent.getPaddingLeft();
|
||||
final int right = parent.getWidth() - parent.getPaddingRight();
|
||||
final int childCount = parent.getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = parent.getChildAt(i);
|
||||
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
|
||||
.getLayoutParams();
|
||||
int position = params.getViewLayoutPosition();
|
||||
position -= getHeaderViewCount();
|
||||
// pos为1,size为1,1>0? true
|
||||
if (mDatas == null || mDatas.isEmpty() || position > mDatas.size() - 1 || position < 0
|
||||
|| !mDatas.get(position).isShowSuspension()) {
|
||||
continue;// 越界
|
||||
}
|
||||
// 我记得Rv的item position在重置时可能为-1.保险点判断一下吧
|
||||
if (position > -1) {
|
||||
if (position == 0) {// 等于0肯定要有title的
|
||||
drawTitleArea(c, left, right, child, params, position);
|
||||
|
||||
} else {// 其他的通过判断
|
||||
if (null != mDatas.get(position).getSuspensionTag()
|
||||
&& !mDatas.get(position).getSuspensionTag()
|
||||
.equals(mDatas.get(position - 1).getSuspensionTag())) {
|
||||
// 不为空 且跟前一个tag不一样了,说明是新的分类,也要title
|
||||
drawTitleArea(c, left, right, child, params, position);
|
||||
} else {
|
||||
// none
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制Title区域背景和文字的方法
|
||||
*
|
||||
* @param c
|
||||
* @param left
|
||||
* @param right
|
||||
* @param child
|
||||
* @param params
|
||||
* @param position
|
||||
*/
|
||||
private void drawTitleArea(Canvas c, int left, int right, View child,
|
||||
RecyclerView.LayoutParams params, int position) {// 最先调用,绘制在最下层
|
||||
mPaint.setColor(COLOR_TITLE_BG);
|
||||
c.drawRect(left, child.getTop() - params.topMargin - mTitleHeight, right,
|
||||
child.getTop() - params.topMargin, mPaint);
|
||||
mPaint.setColor(COLOR_TITLE_FONT);
|
||||
|
||||
mPaint.getTextBounds(mDatas.get(position).getSuspensionTag(), 0,
|
||||
mDatas.get(position).getSuspensionTag().length(), mBounds);
|
||||
c.drawText(mDatas.get(position).getSuspensionTag(), 40,
|
||||
child.getTop() - params.topMargin - (mTitleHeight / 2 - mBounds.height() / 2),
|
||||
mPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawOver(Canvas c, final RecyclerView parent, RecyclerView.State state) {// 最后调用
|
||||
// 绘制在最上层
|
||||
int pos = ((LinearLayoutManager) (parent.getLayoutManager()))
|
||||
.findFirstVisibleItemPosition();
|
||||
pos -= getHeaderViewCount();
|
||||
// pos为1,size为1,1>0? true
|
||||
if (mDatas == null || mDatas.isEmpty() || pos > mDatas.size() - 1 || pos < 0
|
||||
|| !mDatas.get(pos).isShowSuspension()) {
|
||||
return;// 越界
|
||||
}
|
||||
|
||||
String tag = mDatas.get(pos).getSuspensionTag();
|
||||
View child = parent.findViewHolderForLayoutPosition(pos + getHeaderViewCount()).itemView;// 出现一个奇怪的bug,有时候child为空,所以将
|
||||
// child
|
||||
// =
|
||||
// parent.getChildAt(i)。-》
|
||||
// parent.findViewHolderForLayoutPosition(pos).itemView
|
||||
|
||||
boolean flag = false;// 定义一个flag,Canvas是否位移过的标志
|
||||
if ((pos + 1) < mDatas.size()) {// 防止数组越界(一般情况不会出现)
|
||||
if (null != tag && !tag.equals(mDatas.get(pos + 1).getSuspensionTag())) {// 当前第一个可见的Item的tag,不等于其后一个item的tag,说明悬浮的View要切换了
|
||||
Log.d("zxt", "onDrawOver() called with: c = [" + child.getTop());// 当getTop开始变负,它的绝对值,是第一个可见的Item移出屏幕的距离,
|
||||
if (child.getHeight() + child.getTop() < mTitleHeight) {// 当第一个可见的item在屏幕中还剩的高度小于title区域的高度时,我们也该开始做悬浮Title的“交换动画”
|
||||
c.save();// 每次绘制前 保存当前Canvas状态,
|
||||
flag = true;
|
||||
|
||||
// 一种头部折叠起来的视效,个人觉得也还不错~
|
||||
// 可与123行 c.drawRect 比较,只有bottom参数不一样,由于 child.getHeight() +
|
||||
// child.getTop() < mTitleHeight,所以绘制区域是在不断的减小,有种折叠起来的感觉
|
||||
// c.clipRect(parent.getPaddingLeft(),
|
||||
// parent.getPaddingTop(), parent.getRight() -
|
||||
// parent.getPaddingRight(), parent.getPaddingTop() +
|
||||
// child.getHeight() + child.getTop());
|
||||
|
||||
// 类似饿了么点餐时,商品列表的悬停头部切换“动画效果”
|
||||
// 上滑时,将canvas上移 (y为负数) ,所以后面canvas
|
||||
// 画出来的Rect和Text都上移了,有种切换的“动画”感觉
|
||||
c.translate(0, child.getHeight() + child.getTop() - mTitleHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
mPaint.setColor(COLOR_TITLE_BG);
|
||||
c.drawRect(parent.getPaddingLeft(), parent.getPaddingTop(),
|
||||
parent.getRight() - parent.getPaddingRight(), parent.getPaddingTop() + mTitleHeight,
|
||||
mPaint);
|
||||
mPaint.setColor(COLOR_TITLE_FONT);
|
||||
mPaint.getTextBounds(tag, 0, tag.length(), mBounds);
|
||||
c.drawText(tag, 40,
|
||||
parent.getPaddingTop() + mTitleHeight - (mTitleHeight / 2 - mBounds.height() / 2),
|
||||
mPaint);
|
||||
if (flag)
|
||||
c.restore();// 恢复画布到之前保存的状态
|
||||
|
||||
/*
|
||||
* Button button = new Button(parent.getContext());
|
||||
* button.setOnClickListener(new View.OnClickListener() {
|
||||
* @Override public void onClick(View v) {
|
||||
* Toast.makeText(parent.getContext(), "啊哈",
|
||||
* Toast.LENGTH_SHORT).show();//即使给View设置了点击事件,也是无效的,它仅仅draw了 } });
|
||||
* ViewGroup.LayoutParams params = button.getLayoutParams(); if (params
|
||||
* == null){ params = new
|
||||
* ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
* ViewGroup.LayoutParams.WRAP_CONTENT); }
|
||||
* button.setLayoutParams(params); button.setBackgroundColor(Color.RED);
|
||||
* button.setText("无哈");
|
||||
*//*
|
||||
* button.measure(View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.
|
||||
* EXACTLY),View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.
|
||||
* EXACTLY));
|
||||
*//*
|
||||
* //必须经过 测量 和 布局,View才能被正常的显示出来
|
||||
* button.measure(View.MeasureSpec.makeMeasureSpec(9999,View.
|
||||
* MeasureSpec.UNSPECIFIED),View.MeasureSpec.makeMeasureSpec(9999,
|
||||
* View.MeasureSpec.UNSPECIFIED));
|
||||
* button.layout(parent.getPaddingLeft(),parent.getPaddingTop(),
|
||||
* parent.getPaddingLeft()+button.getMeasuredWidth(),parent.
|
||||
* getPaddingTop()+button.getMeasuredHeight()); button.draw(c);
|
||||
*/
|
||||
|
||||
// inflate一个复杂布局 并draw出来
|
||||
/*
|
||||
* View toDrawView = mInflater.inflate(R.layout.header_complex, parent,
|
||||
* false); int toDrawWidthSpec;//用于测量的widthMeasureSpec int
|
||||
* toDrawHeightSpec;//用于测量的heightMeasureSpec
|
||||
* //拿到复杂布局的LayoutParams,如果为空,就new一个。 // 后面需要根据这个lp
|
||||
* 构建toDrawWidthSpec,toDrawHeightSpec ViewGroup.LayoutParams lp =
|
||||
* toDrawView.getLayoutParams(); if (lp == null) { lp = new
|
||||
* ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
* ViewGroup.LayoutParams.WRAP_CONTENT);//这里是根据复杂布局layout的width
|
||||
* height,new一个Lp toDrawView.setLayoutParams(lp); } if (lp.width ==
|
||||
* ViewGroup.LayoutParams.MATCH_PARENT) {
|
||||
* //如果是MATCH_PARENT,则用父控件能分配的最大宽度和EXACTLY构建MeasureSpec。 toDrawWidthSpec
|
||||
* = View.MeasureSpec.makeMeasureSpec(parent.getWidth() -
|
||||
* parent.getPaddingLeft() - parent.getPaddingRight(),
|
||||
* View.MeasureSpec.EXACTLY); } else if (lp.width ==
|
||||
* ViewGroup.LayoutParams.WRAP_CONTENT) {
|
||||
* //如果是WRAP_CONTENT,则用父控件能分配的最大宽度和AT_MOST构建MeasureSpec。 toDrawWidthSpec
|
||||
* = View.MeasureSpec.makeMeasureSpec(parent.getWidth() -
|
||||
* parent.getPaddingLeft() - parent.getPaddingRight(),
|
||||
* View.MeasureSpec.AT_MOST); } else {
|
||||
* //否则则是具体的宽度数值,则用这个宽度和EXACTLY构建MeasureSpec。 toDrawWidthSpec =
|
||||
* View.MeasureSpec.makeMeasureSpec(lp.width, View.MeasureSpec.EXACTLY);
|
||||
* } //高度同理 if (lp.height == ViewGroup.LayoutParams.MATCH_PARENT) {
|
||||
* toDrawHeightSpec =
|
||||
* View.MeasureSpec.makeMeasureSpec(parent.getHeight() -
|
||||
* parent.getPaddingTop() - parent.getPaddingBottom(),
|
||||
* View.MeasureSpec.EXACTLY); } else if (lp.height ==
|
||||
* ViewGroup.LayoutParams.WRAP_CONTENT) { toDrawHeightSpec =
|
||||
* View.MeasureSpec.makeMeasureSpec(parent.getHeight() -
|
||||
* parent.getPaddingTop() - parent.getPaddingBottom(),
|
||||
* View.MeasureSpec.AT_MOST); } else { toDrawHeightSpec =
|
||||
* View.MeasureSpec.makeMeasureSpec(lp.width, View.MeasureSpec.EXACTLY);
|
||||
* } //依次调用 measure,layout,draw方法,将复杂头部显示在屏幕上。
|
||||
* toDrawView.measure(toDrawWidthSpec, toDrawHeightSpec);
|
||||
* toDrawView.layout(parent.getPaddingLeft(), parent.getPaddingTop(),
|
||||
* parent.getPaddingLeft() + toDrawView.getMeasuredWidth(),
|
||||
* parent.getPaddingTop() + toDrawView.getMeasuredHeight());
|
||||
* toDrawView.draw(c);
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
|
||||
RecyclerView.State state) {
|
||||
// super里会先设置0 0 0 0
|
||||
super.getItemOffsets(outRect, view, parent, state);
|
||||
int position = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition();
|
||||
position -= getHeaderViewCount();
|
||||
if (mDatas == null || mDatas.isEmpty() || position > mDatas.size() - 1) {// pos为1,size为1,1>0?
|
||||
// true
|
||||
return;// 越界
|
||||
}
|
||||
// 我记得Rv的item position在重置时可能为-1.保险点判断一下吧
|
||||
if (position > -1) {
|
||||
ISuspensionInterface titleCategoryInterface = mDatas.get(position);
|
||||
// 等于0肯定要有title的,
|
||||
// 2016 11 07 add 考虑到headerView 等于0 也不应该有title
|
||||
// 2016 11 10 add 通过接口里的isShowSuspension() 方法,先过滤掉不想显示悬停的item
|
||||
if (titleCategoryInterface.isShowSuspension()) {
|
||||
if (position == 0) {
|
||||
outRect.set(0, mTitleHeight, 0, 0);
|
||||
} else {// 其他的通过判断
|
||||
if (null != titleCategoryInterface.getSuspensionTag()
|
||||
&& !titleCategoryInterface.getSuspensionTag()
|
||||
.equals(mDatas.get(position - 1).getSuspensionTag())) {
|
||||
// 不为空 且跟前一个tag不一样了,说明是新的分类,也要title
|
||||
outRect.set(0, mTitleHeight, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
package com.superrecycleview.superlibrary.recycleview;
|
||||
|
||||
import com.google.android.material.appbar.AppBarLayout;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public abstract class AppBarStateChangeListener implements AppBarLayout.OnOffsetChangedListener {
|
||||
|
||||
public enum State {
|
||||
EXPANDED,
|
||||
COLLAPSED,
|
||||
IDLE
|
||||
}
|
||||
|
||||
private State mCurrentState = State.IDLE;
|
||||
|
||||
@Override
|
||||
public final void onOffsetChanged(AppBarLayout appBarLayout, int i) {
|
||||
if (i == 0) {
|
||||
if (mCurrentState != State.EXPANDED) {
|
||||
onStateChanged(appBarLayout, State.EXPANDED);
|
||||
}
|
||||
mCurrentState = State.EXPANDED;
|
||||
} else if (Math.abs(i) >= appBarLayout.getTotalScrollRange()) {
|
||||
if (mCurrentState != State.COLLAPSED) {
|
||||
onStateChanged(appBarLayout, State.COLLAPSED);
|
||||
}
|
||||
mCurrentState = State.COLLAPSED;
|
||||
} else {
|
||||
if (mCurrentState != State.IDLE) {
|
||||
onStateChanged(appBarLayout, State.IDLE);
|
||||
}
|
||||
mCurrentState = State.IDLE;
|
||||
}
|
||||
}
|
||||
public abstract void onStateChanged(AppBarLayout appBarLayout, State state);
|
||||
}
|
||||
|
||||
@ -0,0 +1,267 @@
|
||||
package com.superrecycleview.superlibrary.recycleview;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.RotateAnimation;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import com.superrecycleview.superlibrary.R;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.AVLoadingIndicatorView;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
* update by super南仔
|
||||
*/
|
||||
public class ArrowRefreshHeader extends LinearLayout implements BaseRefreshHeader {
|
||||
|
||||
private LinearLayout mContainer;
|
||||
private ImageView mArrowImageView;
|
||||
private SimpleViewSwitcher mProgressBar;
|
||||
private TextView mStatusTextView;
|
||||
private int mState = STATE_NORMAL;
|
||||
|
||||
private TextView mHeaderTimeView;
|
||||
|
||||
private Animation mRotateUpAnim;
|
||||
private Animation mRotateDownAnim;
|
||||
|
||||
private static final int ROTATE_ANIM_DURATION = 180;
|
||||
|
||||
public int mMeasuredHeight;
|
||||
|
||||
public ArrowRefreshHeader(Context context) {
|
||||
super(context);
|
||||
initView();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @param attrs
|
||||
*/
|
||||
public ArrowRefreshHeader(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView();
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
// 初始情况,设置下拉刷新view高度为0
|
||||
mContainer = (LinearLayout) LayoutInflater.from(getContext()).inflate(
|
||||
R.layout.listview_header, null);
|
||||
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
|
||||
lp.setMargins(0, 0, 0, 0);
|
||||
this.setLayoutParams(lp);
|
||||
this.setPadding(0, 0, 0, 0);
|
||||
|
||||
addView(mContainer, new LayoutParams(LayoutParams.MATCH_PARENT, 0));
|
||||
setGravity(Gravity.BOTTOM);
|
||||
|
||||
mArrowImageView = (ImageView)findViewById(R.id.listview_header_arrow);
|
||||
mStatusTextView = (TextView)findViewById(R.id.refresh_status_textview);
|
||||
|
||||
//init the progress view
|
||||
mProgressBar = (SimpleViewSwitcher)findViewById(R.id.listview_header_progressbar);
|
||||
AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(getContext());
|
||||
progressView.setIndicatorColor(0xffB5B5B5);
|
||||
progressView.setIndicatorId(ProgressStyle.BallSpinFadeLoader);
|
||||
mProgressBar.setView(progressView);
|
||||
|
||||
|
||||
mRotateUpAnim = new RotateAnimation(0.0f, -180.0f,
|
||||
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
|
||||
mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
|
||||
mRotateUpAnim.setFillAfter(true);
|
||||
mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f,
|
||||
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
|
||||
mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
|
||||
mRotateDownAnim.setFillAfter(true);
|
||||
|
||||
mHeaderTimeView = (TextView)findViewById(R.id.last_refresh_time);
|
||||
measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
mMeasuredHeight = getMeasuredHeight();
|
||||
}
|
||||
|
||||
public void setProgressStyle(int style) {
|
||||
if(style == ProgressStyle.SysProgress){
|
||||
mProgressBar.setView(new ProgressBar(getContext(), null, android.R.attr.progressBarStyle));
|
||||
}else{
|
||||
AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(this.getContext());
|
||||
progressView.setIndicatorColor(0xffB5B5B5);
|
||||
progressView.setIndicatorId(style);
|
||||
mProgressBar.setView(progressView);
|
||||
}
|
||||
}
|
||||
|
||||
public void setArrowImageView(int resid){
|
||||
mArrowImageView.setImageResource(resid);
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
if (state == mState) return ;
|
||||
|
||||
if (state == STATE_REFRESHING) { // 显示进度
|
||||
mArrowImageView.clearAnimation();
|
||||
mArrowImageView.setVisibility(View.INVISIBLE);
|
||||
mProgressBar.setVisibility(View.VISIBLE);
|
||||
} else if(state == STATE_DONE) {
|
||||
mArrowImageView.setVisibility(View.INVISIBLE);
|
||||
mProgressBar.setVisibility(View.INVISIBLE);
|
||||
} else { // 显示箭头图片
|
||||
mArrowImageView.setVisibility(View.VISIBLE);
|
||||
mProgressBar.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
switch(state){
|
||||
case STATE_NORMAL:
|
||||
if (mState == STATE_RELEASE_TO_REFRESH) {
|
||||
mArrowImageView.startAnimation(mRotateDownAnim);
|
||||
}
|
||||
if (mState == STATE_REFRESHING) {
|
||||
mArrowImageView.clearAnimation();
|
||||
}
|
||||
mStatusTextView.setText(R.string.listview_header_hint_normal);
|
||||
break;
|
||||
case STATE_RELEASE_TO_REFRESH:
|
||||
if (mState != STATE_RELEASE_TO_REFRESH) {
|
||||
mArrowImageView.clearAnimation();
|
||||
mArrowImageView.startAnimation(mRotateUpAnim);
|
||||
mStatusTextView.setText(R.string.listview_header_hint_release);
|
||||
}
|
||||
break;
|
||||
case STATE_REFRESHING:
|
||||
mStatusTextView.setText(R.string.refreshing);
|
||||
break;
|
||||
case STATE_DONE:
|
||||
mStatusTextView.setText(R.string.refresh_done);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
mState = state;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshComplete(){
|
||||
mHeaderTimeView.setText(friendlyTime(new Date()));
|
||||
setState(STATE_DONE);
|
||||
new Handler().postDelayed(new Runnable(){
|
||||
public void run() {
|
||||
reset();
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
public void setVisibleHeight(int height) {
|
||||
if (height < 0) height = 0;
|
||||
LayoutParams lp = (LayoutParams) mContainer .getLayoutParams();
|
||||
lp.height = height;
|
||||
mContainer.setLayoutParams(lp);
|
||||
}
|
||||
|
||||
public int getVisibleHeight() {
|
||||
LayoutParams lp = (LayoutParams) mContainer.getLayoutParams();
|
||||
return lp.height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMove(float delta) {
|
||||
if(getVisibleHeight() > 0 || delta > 0) {
|
||||
setVisibleHeight((int) delta + getVisibleHeight());
|
||||
if (mState <= STATE_RELEASE_TO_REFRESH) { // 未处于刷新状态,更新箭头
|
||||
if (getVisibleHeight() > mMeasuredHeight) {
|
||||
setState(STATE_RELEASE_TO_REFRESH);
|
||||
}else {
|
||||
setState(STATE_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean releaseAction() {
|
||||
boolean isOnRefresh = false;
|
||||
int height = getVisibleHeight();
|
||||
if (height == 0) // not visible.
|
||||
isOnRefresh = false;
|
||||
|
||||
if(getVisibleHeight() > mMeasuredHeight && mState < STATE_REFRESHING){
|
||||
setState(STATE_REFRESHING);
|
||||
isOnRefresh = true;
|
||||
}
|
||||
// refreshing and header isn't shown fully. do nothing.
|
||||
if (mState == STATE_REFRESHING && height <= mMeasuredHeight) {
|
||||
//return;
|
||||
}
|
||||
int destHeight = 0; // default: scroll back to dismiss header.
|
||||
// is refreshing, just scroll back to show all the header.
|
||||
if (mState == STATE_REFRESHING) {
|
||||
destHeight = mMeasuredHeight;
|
||||
}
|
||||
smoothScrollTo(destHeight);
|
||||
|
||||
return isOnRefresh;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
smoothScrollTo(0);
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
public void run() {
|
||||
setState(STATE_NORMAL);
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
private void smoothScrollTo(int destHeight) {
|
||||
ValueAnimator animator = ValueAnimator.ofInt(getVisibleHeight(), destHeight);
|
||||
animator.setDuration(300).start();
|
||||
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation)
|
||||
{
|
||||
setVisibleHeight((int) animation.getAnimatedValue());
|
||||
}
|
||||
});
|
||||
animator.start();
|
||||
}
|
||||
|
||||
public static String friendlyTime(Date time) {
|
||||
//获取time距离当前的秒数
|
||||
int ct = (int)((System.currentTimeMillis() - time.getTime())/1000);
|
||||
|
||||
if(ct == 0) {
|
||||
return "刚刚";
|
||||
}
|
||||
|
||||
if(ct > 0 && ct < 60) {
|
||||
return ct + "秒前";
|
||||
}
|
||||
|
||||
if(ct >= 60 && ct < 3600) {
|
||||
return Math.max(ct / 60,1) + "分钟前";
|
||||
}
|
||||
if(ct >= 3600 && ct < 86400)
|
||||
return ct / 3600 + "小时前";
|
||||
if(ct >= 86400 && ct < 2592000){ //86400 * 30
|
||||
int day = ct / 86400 ;
|
||||
return day + "天前";
|
||||
}
|
||||
if(ct >= 2592000 && ct < 31104000) { //86400 * 30
|
||||
return ct / 2592000 + "月前";
|
||||
}
|
||||
return ct / 31104000 + "年前";
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.superrecycleview.superlibrary.recycleview;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
interface BaseRefreshHeader {
|
||||
|
||||
int STATE_NORMAL = 0;
|
||||
int STATE_RELEASE_TO_REFRESH = 1;
|
||||
int STATE_REFRESHING = 2;
|
||||
int STATE_DONE = 3;
|
||||
|
||||
void onMove(float delta);
|
||||
|
||||
boolean releaseAction();
|
||||
|
||||
void refreshComplete();
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.superrecycleview.superlibrary.recycleview;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public interface ItemTouchHelperAdapter {
|
||||
|
||||
/**
|
||||
* Called when an item has been dragged far enough to trigger a move. This is called every time
|
||||
* an item is shifted, and <strong>not</strong> at the end of a "drop" event.<br/>
|
||||
* <br/>
|
||||
* Implementations should call {@link RecyclerView.Adapter#notifyItemMoved(int, int)} after
|
||||
* adjusting the underlying data to reflect this move.
|
||||
*
|
||||
* @param fromPosition The start position of the moved item.
|
||||
* @param toPosition Then resolved position of the moved item.
|
||||
*
|
||||
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
|
||||
* @see RecyclerView.ViewHolder#getAdapterPosition()
|
||||
*/
|
||||
void onItemMove(int fromPosition, int toPosition);
|
||||
|
||||
|
||||
/**
|
||||
* Called when an item has been dismissed by a swipe.<br/>
|
||||
* <br/>
|
||||
* Implementations should call {@link RecyclerView.Adapter#notifyItemRemoved(int)} after
|
||||
* adjusting the underlying data to reflect this removal.
|
||||
*
|
||||
* @param position The position of the item dismissed.
|
||||
*
|
||||
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
|
||||
* @see RecyclerView.ViewHolder#getAdapterPosition()
|
||||
*/
|
||||
void onItemDismiss(int position);
|
||||
}
|
||||
@ -0,0 +1,106 @@
|
||||
package com.superrecycleview.superlibrary.recycleview;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class JellyView extends View implements BaseRefreshHeader{
|
||||
Path path;
|
||||
|
||||
Paint paint;
|
||||
|
||||
private int minimumHeight = 0;
|
||||
|
||||
private int jellyHeight =0;
|
||||
|
||||
public JellyView(Context context) {
|
||||
super(context);
|
||||
init();
|
||||
}
|
||||
|
||||
public JellyView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init();
|
||||
}
|
||||
|
||||
public JellyView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public JellyView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (isInEditMode()) {
|
||||
return;
|
||||
}
|
||||
path = new Path();
|
||||
paint = new Paint();
|
||||
paint.setColor(getContext().getResources().getColor(android.R.color.holo_blue_bright));
|
||||
paint.setAntiAlias(true);
|
||||
}
|
||||
|
||||
public void setJellyColor(int jellyColor) {
|
||||
paint.setColor(jellyColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
path.reset();
|
||||
path.lineTo(0, minimumHeight);
|
||||
path.quadTo(getMeasuredWidth() / 2, minimumHeight + jellyHeight, getMeasuredWidth(), minimumHeight);
|
||||
path.lineTo(getMeasuredWidth(), 0);
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMinimumHeight(int minimumHeight) {
|
||||
this.minimumHeight = minimumHeight;
|
||||
}
|
||||
|
||||
public void setJellyHeight(int ribbonHeight) {
|
||||
this.jellyHeight = ribbonHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinimumHeight() {
|
||||
return minimumHeight;
|
||||
}
|
||||
|
||||
public int getJellyHeight() {
|
||||
return jellyHeight;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void refreshComplete(){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMove(float delta) {
|
||||
jellyHeight = jellyHeight + (int)delta;
|
||||
Log.i("jellyHeight", "delta = " + delta);
|
||||
this.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean releaseAction() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
package com.superrecycleview.superlibrary.recycleview;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.superrecycleview.superlibrary.R;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.AVLoadingIndicatorView;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
* update by super南仔
|
||||
*/
|
||||
public class LoadingMoreFooter extends LinearLayout {
|
||||
|
||||
private SimpleViewSwitcher progressCon;
|
||||
public final static int STATE_LOADING = 0;
|
||||
public final static int STATE_COMPLETE = 1;
|
||||
public final static int STATE_NOMORE = 2;
|
||||
private TextView mText;
|
||||
|
||||
|
||||
public LoadingMoreFooter(Context context) {
|
||||
super(context);
|
||||
initView();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @param attrs
|
||||
*/
|
||||
public LoadingMoreFooter(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView();
|
||||
}
|
||||
public void initView(){
|
||||
setGravity(Gravity.CENTER);
|
||||
setLayoutParams(new RecyclerView.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
progressCon = new SimpleViewSwitcher(getContext());
|
||||
progressCon.setLayoutParams(new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
|
||||
AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(this.getContext());
|
||||
progressView.setIndicatorColor(getResources().getColor(R.color.blue));
|
||||
progressView.setIndicatorId(ProgressStyle.BallSpinFadeLoader);
|
||||
progressCon.setView(progressView);
|
||||
|
||||
addView(progressCon);
|
||||
mText = new TextView(getContext());
|
||||
mText.setText("正在加载...");
|
||||
mText.setTextColor(getResources().getColor(R.color.blue));
|
||||
|
||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
layoutParams.setMargins(10,0,0,0 );
|
||||
|
||||
mText.setLayoutParams(layoutParams);
|
||||
addView(mText);
|
||||
}
|
||||
|
||||
public void setProgressStyle(int style) {
|
||||
if(style == ProgressStyle.SysProgress){
|
||||
progressCon.setView(new ProgressBar(getContext(), null, android.R.attr.progressBarStyle));
|
||||
}else{
|
||||
AVLoadingIndicatorView progressView = new AVLoadingIndicatorView(this.getContext());
|
||||
progressView.setIndicatorColor(getResources().getColor(R.color.blue));
|
||||
progressView.setIndicatorId(style);
|
||||
progressCon.setView(progressView);
|
||||
}
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
switch(state) {
|
||||
case STATE_LOADING:
|
||||
progressCon.setVisibility(View.VISIBLE);
|
||||
mText.setText("正在加载");
|
||||
this.setVisibility(View.VISIBLE);
|
||||
break;
|
||||
case STATE_COMPLETE:
|
||||
mText.setText("正在加载");
|
||||
this.setVisibility(View.GONE);
|
||||
break;
|
||||
case STATE_NOMORE:
|
||||
mText.setText("没有更多了");
|
||||
progressCon.setVisibility(View.GONE);
|
||||
this.setVisibility(View.VISIBLE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.superrecycleview.superlibrary.recycleview;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class ProgressStyle {
|
||||
public static final int SysProgress=-1;
|
||||
public static final int BallPulse=0;
|
||||
public static final int BallGridPulse=1;
|
||||
public static final int BallClipRotate=2;
|
||||
public static final int BallClipRotatePulse=3;
|
||||
public static final int SquareSpin=4;
|
||||
public static final int BallClipRotateMultiple=5;
|
||||
public static final int BallPulseRise=6;
|
||||
public static final int BallRotate=7;
|
||||
public static final int CubeTransition=8;
|
||||
public static final int BallZigZag=9;
|
||||
public static final int BallZigZagDeflect=10;
|
||||
public static final int BallTrianglePath=11;
|
||||
public static final int BallScale=12;
|
||||
public static final int LineScale=13;
|
||||
public static final int LineScaleParty=14;
|
||||
public static final int BallScaleMultiple=15;
|
||||
public static final int BallPulseSync=16;
|
||||
public static final int BallBeat=17;
|
||||
public static final int LineScalePulseOut=18;
|
||||
public static final int LineScalePulseOutRapid=19;
|
||||
public static final int BallScaleRipple=20;
|
||||
public static final int BallScaleRippleMultiple=21;
|
||||
public static final int BallSpinFadeLoader=22;
|
||||
public static final int LineSpinFadeLoader=23;
|
||||
public static final int TriangleSkewSpin=24;
|
||||
public static final int Pacman=25;
|
||||
public static final int BallGridBeat=26;
|
||||
public static final int SemiCircleSpin=27;
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
package com.superrecycleview.superlibrary.recycleview;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
||||
|
||||
public static final float ALPHA_FULL = 1.0f;
|
||||
|
||||
private final ItemTouchHelperAdapter mAdapter;
|
||||
private SuperRecyclerView mSrecyclerView;
|
||||
|
||||
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter, SuperRecyclerView recyclerView) {
|
||||
mAdapter = adapter;
|
||||
this.mSrecyclerView = recyclerView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLongPressDragEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemViewSwipeEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||
// Enable drag and swipe in both directions
|
||||
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
|
||||
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
|
||||
return makeMovementFlags(dragFlags, swipeFlags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
|
||||
if (source.getItemViewType() != target.getItemViewType()) {
|
||||
return false;
|
||||
}
|
||||
// Notify the adapter of the move
|
||||
mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
|
||||
// Notify the adapter of the dismissal
|
||||
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
|
||||
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
||||
|
||||
// Fade out the view as it is swiped out of the parent's bounds
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
|
||||
View itemView = viewHolder.itemView;
|
||||
final float alpha = ALPHA_FULL - Math.abs(dX) / (float) itemView.getWidth();
|
||||
itemView.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
|
||||
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
|
||||
// Let the view holder know that this item is being moved or dragged
|
||||
viewHolder.itemView.setBackgroundColor(Color.LTGRAY);
|
||||
}
|
||||
|
||||
super.onSelectedChanged(viewHolder, actionState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||
super.clearView(recyclerView, viewHolder);
|
||||
viewHolder.itemView.setAlpha(ALPHA_FULL);
|
||||
viewHolder.itemView.setBackgroundColor(0);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.superrecycleview.superlibrary.recycleview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class SimpleViewSwitcher extends ViewGroup {
|
||||
|
||||
public SimpleViewSwitcher(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public SimpleViewSwitcher(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public SimpleViewSwitcher(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int childCount = this.getChildCount();
|
||||
int maxHeight = 0;
|
||||
int maxWidth = 0;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
View child = this.getChildAt(i);
|
||||
this.measureChild(child, widthMeasureSpec, heightMeasureSpec);
|
||||
int cw = child.getMeasuredWidth();
|
||||
// int ch = child.getMeasuredHeight();
|
||||
maxWidth = child.getMeasuredWidth();
|
||||
maxHeight = child.getMeasuredHeight();
|
||||
}
|
||||
setMeasuredDimension(maxWidth, maxHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
final int count = getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() != View.GONE) {
|
||||
child.layout(0, 0, r - l, b - t);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setView(View view) {
|
||||
if (this.getChildCount() != 0){
|
||||
this.removeViewAt(0);
|
||||
}
|
||||
this.addView(view,0);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,534 @@
|
||||
|
||||
package com.superrecycleview.superlibrary.recycleview;
|
||||
|
||||
import android.content.Context;
|
||||
import com.google.android.material.appbar.AppBarLayout;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
|
||||
import com.superrecycleview.superlibrary.adapter.BaseViewHolder;
|
||||
import com.superrecycleview.superlibrary.adapter.SuperBaseAdapter;
|
||||
|
||||
/**
|
||||
* Created by super南仔 on 07/28/16. blog: http://supercwn.github.io/ GitHub:
|
||||
* https://github.com/supercwn
|
||||
*/
|
||||
public class SuperRecyclerView extends RecyclerView {
|
||||
private Context context;
|
||||
private boolean isLoadingData = false;
|
||||
private boolean isNoMore = false;
|
||||
private int mRefreshProgressStyle = ProgressStyle.SysProgress;
|
||||
private int mLoadingMoreProgressStyle = ProgressStyle.SysProgress;
|
||||
private WrapAdapter mWrapAdapter;
|
||||
private float mLastY = -1;
|
||||
private static final float DRAG_RATE = 3;
|
||||
private LoadingListener mLoadingListener;
|
||||
private ArrowRefreshHeader mRefreshHeader;
|
||||
private View mLoadMoreFootView;
|
||||
private View mEmptyView;
|
||||
private boolean refreshEnabled = true;
|
||||
private boolean loadingMoreEnabled = true;
|
||||
// 下面的ItemViewType是保留值(ReservedItemViewType),如果用户的adapter与它们重复将会强制抛出异常。不过为了简化,我们检测到重复时对用户的提示是ItemViewType必须小于10000
|
||||
private static final int TYPE_REFRESH_HEADER = 100000;// 设置一个很大的数字,尽可能避免和用户的adapter冲突
|
||||
private static final int TYPE_LOADMORE_FOOTER = 100001;
|
||||
private final RecyclerView.AdapterDataObserver mDataObserver = new DataObserver();
|
||||
private AppBarStateChangeListener.State appbarState = AppBarStateChangeListener.State.EXPANDED;
|
||||
|
||||
public SuperRecyclerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public SuperRecyclerView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public SuperRecyclerView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
this.context = context;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (refreshEnabled) {
|
||||
mRefreshHeader = new ArrowRefreshHeader(getContext());
|
||||
mRefreshHeader.setProgressStyle(mRefreshProgressStyle);
|
||||
}
|
||||
LoadingMoreFooter footView = new LoadingMoreFooter(getContext());
|
||||
footView.setProgressStyle(mLoadingMoreProgressStyle);
|
||||
mLoadMoreFootView = footView;
|
||||
mLoadMoreFootView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// 判断是否是SuperRecyclerView保留的itemViewType
|
||||
private boolean isReservedItemViewType(int itemViewType) {
|
||||
return itemViewType == TYPE_REFRESH_HEADER || itemViewType == TYPE_LOADMORE_FOOTER;
|
||||
}
|
||||
|
||||
public void setLoadMoreFootView(final View view) {
|
||||
mLoadMoreFootView = view;
|
||||
}
|
||||
|
||||
public void completeLoadMore() {
|
||||
isLoadingData = false;
|
||||
if (mLoadMoreFootView instanceof LoadingMoreFooter) {
|
||||
((LoadingMoreFooter) mLoadMoreFootView).setState(LoadingMoreFooter.STATE_COMPLETE);
|
||||
} else {
|
||||
mLoadMoreFootView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setNoMore(boolean noMore) {
|
||||
isLoadingData = false;
|
||||
isNoMore = noMore;
|
||||
if (mLoadMoreFootView instanceof LoadingMoreFooter) {
|
||||
((LoadingMoreFooter) mLoadMoreFootView).setState(
|
||||
isNoMore ? LoadingMoreFooter.STATE_NOMORE : LoadingMoreFooter.STATE_COMPLETE);
|
||||
} else {
|
||||
mLoadMoreFootView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void completeRefresh() {
|
||||
mRefreshHeader.refreshComplete();
|
||||
setNoMore(false);
|
||||
}
|
||||
|
||||
public void setRefreshHeader(ArrowRefreshHeader refreshHeader) {
|
||||
mRefreshHeader = refreshHeader;
|
||||
}
|
||||
|
||||
public void setRefreshEnabled(boolean enabled) {
|
||||
refreshEnabled = enabled;
|
||||
}
|
||||
|
||||
public void setLoadMoreEnabled(boolean enabled) {
|
||||
loadingMoreEnabled = enabled;
|
||||
if (!enabled) {
|
||||
if (mLoadMoreFootView instanceof LoadingMoreFooter) {
|
||||
((LoadingMoreFooter) mLoadMoreFootView).setState(LoadingMoreFooter.STATE_COMPLETE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setRefreshProgressStyle(int style) {
|
||||
mRefreshProgressStyle = style;
|
||||
if (mRefreshHeader != null) {
|
||||
mRefreshHeader.setProgressStyle(style);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLoadingMoreProgressStyle(int style) {
|
||||
mLoadingMoreProgressStyle = style;
|
||||
if (mLoadMoreFootView instanceof LoadingMoreFooter) {
|
||||
((LoadingMoreFooter) mLoadMoreFootView).setProgressStyle(style);
|
||||
}
|
||||
}
|
||||
|
||||
public void setArrowImageView(int resId) {
|
||||
if (mRefreshHeader != null) {
|
||||
mRefreshHeader.setArrowImageView(resId);
|
||||
}
|
||||
}
|
||||
|
||||
public void setEmptyView(View emptyView) {
|
||||
this.mEmptyView = emptyView;
|
||||
mDataObserver.onChanged();
|
||||
}
|
||||
|
||||
public View getEmptyView() {
|
||||
return mEmptyView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdapter(Adapter adapter) {
|
||||
if (adapter instanceof SuperBaseAdapter) {
|
||||
mWrapAdapter = new WrapAdapter(adapter);
|
||||
super.setAdapter(mWrapAdapter);
|
||||
} else {
|
||||
super.setAdapter(adapter);
|
||||
}
|
||||
adapter.registerAdapterDataObserver(mDataObserver);
|
||||
mDataObserver.onChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrollStateChanged(int state) {
|
||||
super.onScrollStateChanged(state);
|
||||
if (state == RecyclerView.SCROLL_STATE_IDLE && mLoadingListener != null && !isLoadingData
|
||||
&& loadingMoreEnabled) {
|
||||
LayoutManager layoutManager = getLayoutManager();
|
||||
int lastVisibleItemPosition;
|
||||
if (layoutManager instanceof GridLayoutManager) {
|
||||
lastVisibleItemPosition = ((GridLayoutManager) layoutManager)
|
||||
.findLastVisibleItemPosition();
|
||||
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
|
||||
int[] into = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
|
||||
((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(into);
|
||||
lastVisibleItemPosition = findMax(into);
|
||||
} else {
|
||||
lastVisibleItemPosition = ((LinearLayoutManager) layoutManager)
|
||||
.findLastVisibleItemPosition();
|
||||
}
|
||||
if (layoutManager.getChildCount() > 0
|
||||
&& lastVisibleItemPosition >= layoutManager.getItemCount() - 1
|
||||
&& layoutManager.getItemCount() > layoutManager.getChildCount() && !isNoMore
|
||||
&& mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING) {
|
||||
isLoadingData = true;
|
||||
if (mLoadMoreFootView instanceof LoadingMoreFooter) {
|
||||
((LoadingMoreFooter) mLoadMoreFootView)
|
||||
.setState(LoadingMoreFooter.STATE_LOADING);
|
||||
} else {
|
||||
mLoadMoreFootView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
mLoadingListener.onLoadMore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
if (mLastY == -1) {
|
||||
mLastY = ev.getRawY();
|
||||
}
|
||||
switch (ev.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mLastY = ev.getRawY();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
final float deltaY = ev.getRawY() - mLastY;
|
||||
mLastY = ev.getRawY();
|
||||
if (isOnTop() && refreshEnabled
|
||||
&& appbarState == AppBarStateChangeListener.State.EXPANDED) {
|
||||
mRefreshHeader.onMove(deltaY / DRAG_RATE);
|
||||
if (mRefreshHeader.getVisibleHeight() > 0
|
||||
&& mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mLastY = -1; // reset
|
||||
if (isOnTop() && refreshEnabled
|
||||
&& appbarState == AppBarStateChangeListener.State.EXPANDED) {
|
||||
if (mRefreshHeader.releaseAction()) {
|
||||
if (mLoadingListener != null) {
|
||||
mLoadingListener.onRefresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return super.onTouchEvent(ev);
|
||||
}
|
||||
|
||||
private int findMax(int[] lastPositions) {
|
||||
int max = lastPositions[0];
|
||||
for (int value : lastPositions) {
|
||||
if (value > max) {
|
||||
max = value;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
private boolean isOnTop() {
|
||||
return mRefreshHeader.getParent() != null;
|
||||
}
|
||||
|
||||
private class DataObserver extends RecyclerView.AdapterDataObserver {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
Adapter<?> adapter = getAdapter();
|
||||
if (adapter != null && mEmptyView != null) {
|
||||
int emptyCount = 1;
|
||||
if (refreshEnabled) {
|
||||
emptyCount++;
|
||||
}
|
||||
if (loadingMoreEnabled) {
|
||||
emptyCount++;
|
||||
}
|
||||
if (adapter.getItemCount() == emptyCount) {
|
||||
mEmptyView.setVisibility(View.VISIBLE);
|
||||
SuperRecyclerView.this.setVisibility(View.GONE);
|
||||
} else {
|
||||
mEmptyView.setVisibility(View.GONE);
|
||||
SuperRecyclerView.this.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
if (mWrapAdapter != null) {
|
||||
mWrapAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeInserted(int positionStart, int itemCount) {
|
||||
mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeChanged(int positionStart, int itemCount) {
|
||||
mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
|
||||
mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeRemoved(int positionStart, int itemCount) {
|
||||
mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
|
||||
mWrapAdapter.notifyItemMoved(fromPosition, toPosition);
|
||||
}
|
||||
}
|
||||
|
||||
public class WrapAdapter extends SuperBaseAdapter {
|
||||
|
||||
private RecyclerView.Adapter adapter;
|
||||
|
||||
public WrapAdapter(RecyclerView.Adapter adapter) {
|
||||
super(context);
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
public boolean isHeader(int position) {
|
||||
return position >= 1 && position < 1;
|
||||
}
|
||||
|
||||
public boolean isFooter(int position) {
|
||||
if (loadingMoreEnabled) {
|
||||
return position == getItemCount() - 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRefreshHeader(int position) {
|
||||
return position == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
if (viewType == TYPE_REFRESH_HEADER) {
|
||||
return new SimpleViewHolder(mRefreshHeader);
|
||||
} else if (viewType == TYPE_LOADMORE_FOOTER) {
|
||||
return new SimpleViewHolder(mLoadMoreFootView);
|
||||
}
|
||||
return (BaseViewHolder) adapter.onCreateViewHolder(parent,
|
||||
viewType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
|
||||
if (isHeader(position) || isRefreshHeader(position)) {
|
||||
return;
|
||||
}
|
||||
int adjPosition = position - 1;
|
||||
int adapterCount;
|
||||
if (adapter != null) {
|
||||
adapterCount = adapter.getItemCount();
|
||||
if (adjPosition < adapterCount) {
|
||||
adapter.onBindViewHolder(holder, adjPosition);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (loadingMoreEnabled) {
|
||||
if (adapter != null) {
|
||||
return adapter.getItemCount() + 2;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
if (adapter != null) {
|
||||
return adapter.getItemCount() + 1;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
int adjPosition = position - 1;
|
||||
if (isReservedItemViewType(adapter.getItemViewType(adjPosition))) {
|
||||
throw new IllegalStateException(
|
||||
"XRecyclerView require itemViewType in adapter should be less than 10000 ");
|
||||
}
|
||||
if (isRefreshHeader(position)) {
|
||||
return TYPE_REFRESH_HEADER;
|
||||
}
|
||||
if (isFooter(position)) {
|
||||
return TYPE_LOADMORE_FOOTER;
|
||||
}
|
||||
|
||||
int adapterCount;
|
||||
if (adapter != null) {
|
||||
adapterCount = adapter.getItemCount();
|
||||
if (adjPosition < adapterCount) {
|
||||
return adapter.getItemViewType(adjPosition);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void convert(BaseViewHolder holder, Object item, int position) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getItemViewLayoutId(int position, Object item) {
|
||||
// do nothing
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
if (adapter != null && position >= 1) {
|
||||
int adjPosition = position - 1;
|
||||
if (adjPosition < adapter.getItemCount()) {
|
||||
return adapter.getItemId(adjPosition);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
|
||||
super.onAttachedToRecyclerView(recyclerView);
|
||||
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
|
||||
if (manager instanceof GridLayoutManager) {
|
||||
final GridLayoutManager gridManager = ((GridLayoutManager) manager);
|
||||
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
|
||||
@Override
|
||||
public int getSpanSize(int position) {
|
||||
return (isHeader(position) || isFooter(position)
|
||||
|| isRefreshHeader(position))
|
||||
? gridManager.getSpanCount() : 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
adapter.onAttachedToRecyclerView(recyclerView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
|
||||
adapter.onDetachedFromRecyclerView(recyclerView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
|
||||
super.onViewAttachedToWindow((BaseViewHolder) holder);
|
||||
ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
|
||||
if (lp != null
|
||||
&& lp instanceof StaggeredGridLayoutManager.LayoutParams
|
||||
&& (isHeader(holder.getLayoutPosition())
|
||||
|| isRefreshHeader(holder.getLayoutPosition())
|
||||
|| isFooter(holder.getLayoutPosition()))) {
|
||||
StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
|
||||
p.setFullSpan(true);
|
||||
}
|
||||
adapter.onViewAttachedToWindow(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(RecyclerView.ViewHolder holder) {
|
||||
adapter.onViewDetachedFromWindow(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewRecycled(RecyclerView.ViewHolder holder) {
|
||||
adapter.onViewRecycled(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFailedToRecycleView(RecyclerView.ViewHolder holder) {
|
||||
return adapter.onFailedToRecycleView(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
|
||||
adapter.unregisterAdapterDataObserver(observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerAdapterDataObserver(AdapterDataObserver observer) {
|
||||
adapter.registerAdapterDataObserver(observer);
|
||||
}
|
||||
|
||||
private class SimpleViewHolder extends BaseViewHolder {
|
||||
public SimpleViewHolder(View itemView) {
|
||||
super(itemView, context);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setLoadingListener(LoadingListener listener) {
|
||||
mLoadingListener = listener;
|
||||
}
|
||||
|
||||
public interface LoadingListener {
|
||||
|
||||
void onRefresh();
|
||||
|
||||
void onLoadMore();
|
||||
}
|
||||
|
||||
public void setRefreshing(boolean refreshing) {
|
||||
if (refreshing && refreshEnabled && mLoadingListener != null) {
|
||||
mRefreshHeader.setState(ArrowRefreshHeader.STATE_REFRESHING);
|
||||
mRefreshHeader.onMove(mRefreshHeader.getMeasuredHeight());
|
||||
mLoadingListener.onRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
// 解决和CollapsingToolbarLayout冲突的问题
|
||||
AppBarLayout appBarLayout = null;
|
||||
ViewParent p = getParent();
|
||||
while (p != null) {
|
||||
if (p instanceof CoordinatorLayout) {
|
||||
break;
|
||||
}
|
||||
p = p.getParent();
|
||||
}
|
||||
if (p instanceof CoordinatorLayout) {
|
||||
CoordinatorLayout coordinatorLayout = (CoordinatorLayout) p;
|
||||
final int childCount = coordinatorLayout.getChildCount();
|
||||
for (int i = childCount - 1; i >= 0; i--) {
|
||||
final View child = coordinatorLayout.getChildAt(i);
|
||||
if (child instanceof AppBarLayout) {
|
||||
appBarLayout = (AppBarLayout) child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (appBarLayout != null) {
|
||||
appBarLayout.addOnOffsetChangedListener(new AppBarStateChangeListener() {
|
||||
@Override
|
||||
public void onStateChanged(AppBarLayout appBarLayout, State state) {
|
||||
appbarState = state;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,365 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Build;
|
||||
import androidx.annotation.IntDef;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import com.superrecycleview.superlibrary.R;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallBeatIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallClipRotateIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallClipRotateMultipleIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallClipRotatePulseIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallGridBeatIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallGridPulseIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallPulseIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallPulseRiseIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallPulseSyncIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallRotateIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallScaleIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallScaleMultipleIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallScaleRippleIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallScaleRippleMultipleIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallSpinFadeLoaderIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallTrianglePathIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallZigZagDeflectIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BallZigZagIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.BaseIndicatorController;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.CubeTransitionIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.LineScaleIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.LineScalePartyIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.LineScalePulseOutIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.LineScalePulseOutRapidIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.LineSpinFadeLoaderIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.PacmanIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.SemiCircleSpinIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.SquareSpinIndicator;
|
||||
import com.superrecycleview.superlibrary.recycleview.progressindicator.indicator.TriangleSkewSpinIndicator;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
.BallPulse,
|
||||
.BallGridPulse,
|
||||
.BallClipRotate,
|
||||
.BallClipRotatePulse,
|
||||
.SquareSpin,
|
||||
.BallClipRotateMultiple,
|
||||
.BallPulseRise,
|
||||
.BallRotate,
|
||||
.CubeTransition,
|
||||
.BallZigZag,
|
||||
.BallZigZagDeflect,
|
||||
.BallTrianglePath,
|
||||
.BallScale,
|
||||
.LineScale,
|
||||
.LineScaleParty,
|
||||
.BallScaleMultiple,
|
||||
.BallPulseSync,
|
||||
.BallBeat,
|
||||
.LineScalePulseOut,
|
||||
.LineScalePulseOutRapid,
|
||||
.BallScaleRipple,
|
||||
.BallScaleRippleMultiple,
|
||||
.BallSpinFadeLoader,
|
||||
.LineSpinFadeLoader,
|
||||
.TriangleSkewSpin,
|
||||
.Pacman,
|
||||
.BallGridBeat,
|
||||
.SemiCircleSpin
|
||||
*
|
||||
*/
|
||||
public class AVLoadingIndicatorView extends View {
|
||||
//indicators
|
||||
public static final int BallPulse=0;
|
||||
public static final int BallGridPulse=1;
|
||||
public static final int BallClipRotate=2;
|
||||
public static final int BallClipRotatePulse=3;
|
||||
public static final int SquareSpin=4;
|
||||
public static final int BallClipRotateMultiple=5;
|
||||
public static final int BallPulseRise=6;
|
||||
public static final int BallRotate=7;
|
||||
public static final int CubeTransition=8;
|
||||
public static final int BallZigZag=9;
|
||||
public static final int BallZigZagDeflect=10;
|
||||
public static final int BallTrianglePath=11;
|
||||
public static final int BallScale=12;
|
||||
public static final int LineScale=13;
|
||||
public static final int LineScaleParty=14;
|
||||
public static final int BallScaleMultiple=15;
|
||||
public static final int BallPulseSync=16;
|
||||
public static final int BallBeat=17;
|
||||
public static final int LineScalePulseOut=18;
|
||||
public static final int LineScalePulseOutRapid=19;
|
||||
public static final int BallScaleRipple=20;
|
||||
public static final int BallScaleRippleMultiple=21;
|
||||
public static final int BallSpinFadeLoader=22;
|
||||
public static final int LineSpinFadeLoader=23;
|
||||
public static final int TriangleSkewSpin=24;
|
||||
public static final int Pacman=25;
|
||||
public static final int BallGridBeat=26;
|
||||
public static final int SemiCircleSpin=27;
|
||||
|
||||
|
||||
@IntDef(flag = true,
|
||||
value = {
|
||||
BallPulse,
|
||||
BallGridPulse,
|
||||
BallClipRotate,
|
||||
BallClipRotatePulse,
|
||||
SquareSpin,
|
||||
BallClipRotateMultiple,
|
||||
BallPulseRise,
|
||||
BallRotate,
|
||||
CubeTransition,
|
||||
BallZigZag,
|
||||
BallZigZagDeflect,
|
||||
BallTrianglePath,
|
||||
BallScale,
|
||||
LineScale,
|
||||
LineScaleParty,
|
||||
BallScaleMultiple,
|
||||
BallPulseSync,
|
||||
BallBeat,
|
||||
LineScalePulseOut,
|
||||
LineScalePulseOutRapid,
|
||||
BallScaleRipple,
|
||||
BallScaleRippleMultiple,
|
||||
BallSpinFadeLoader,
|
||||
LineSpinFadeLoader,
|
||||
TriangleSkewSpin,
|
||||
Pacman,
|
||||
BallGridBeat,
|
||||
SemiCircleSpin
|
||||
})
|
||||
public @interface Indicator{}
|
||||
|
||||
//Sizes (with defaults in DP)
|
||||
public static final int DEFAULT_SIZE=30;
|
||||
|
||||
//attrs
|
||||
int mIndicatorId;
|
||||
int mIndicatorColor;
|
||||
|
||||
Paint mPaint;
|
||||
|
||||
BaseIndicatorController mIndicatorController;
|
||||
|
||||
private boolean mHasAnimation;
|
||||
|
||||
|
||||
public AVLoadingIndicatorView(Context context) {
|
||||
super(context);
|
||||
init(null, 0);
|
||||
}
|
||||
|
||||
public AVLoadingIndicatorView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(attrs, 0);
|
||||
}
|
||||
|
||||
public AVLoadingIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public AVLoadingIndicatorView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init(attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
private void init(AttributeSet attrs, int defStyle) {
|
||||
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.AVLoadingIndicatorView);
|
||||
mIndicatorId=a.getInt(R.styleable.AVLoadingIndicatorView_indicator, BallPulse);
|
||||
mIndicatorColor=a.getColor(R.styleable.AVLoadingIndicatorView_indicator_color, Color.WHITE);
|
||||
a.recycle();
|
||||
mPaint=new Paint();
|
||||
mPaint.setColor(mIndicatorColor);
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
mPaint.setAntiAlias(true);
|
||||
applyIndicator();
|
||||
}
|
||||
|
||||
public void setIndicatorId(int indicatorId){
|
||||
mIndicatorId = indicatorId;
|
||||
applyIndicator();
|
||||
}
|
||||
|
||||
public void setIndicatorColor(int color){
|
||||
mIndicatorColor = color;
|
||||
mPaint.setColor(mIndicatorColor);
|
||||
this.invalidate();
|
||||
}
|
||||
|
||||
private void applyIndicator(){
|
||||
switch (mIndicatorId){
|
||||
case BallPulse:
|
||||
mIndicatorController=new BallPulseIndicator();
|
||||
break;
|
||||
case BallGridPulse:
|
||||
mIndicatorController=new BallGridPulseIndicator();
|
||||
break;
|
||||
case BallClipRotate:
|
||||
mIndicatorController=new BallClipRotateIndicator();
|
||||
break;
|
||||
case BallClipRotatePulse:
|
||||
mIndicatorController=new BallClipRotatePulseIndicator();
|
||||
break;
|
||||
case SquareSpin:
|
||||
mIndicatorController=new SquareSpinIndicator();
|
||||
break;
|
||||
case BallClipRotateMultiple:
|
||||
mIndicatorController=new BallClipRotateMultipleIndicator();
|
||||
break;
|
||||
case BallPulseRise:
|
||||
mIndicatorController=new BallPulseRiseIndicator();
|
||||
break;
|
||||
case BallRotate:
|
||||
mIndicatorController=new BallRotateIndicator();
|
||||
break;
|
||||
case CubeTransition:
|
||||
mIndicatorController=new CubeTransitionIndicator();
|
||||
break;
|
||||
case BallZigZag:
|
||||
mIndicatorController=new BallZigZagIndicator();
|
||||
break;
|
||||
case BallZigZagDeflect:
|
||||
mIndicatorController=new BallZigZagDeflectIndicator();
|
||||
break;
|
||||
case BallTrianglePath:
|
||||
mIndicatorController=new BallTrianglePathIndicator();
|
||||
break;
|
||||
case BallScale:
|
||||
mIndicatorController=new BallScaleIndicator();
|
||||
break;
|
||||
case LineScale:
|
||||
mIndicatorController=new LineScaleIndicator();
|
||||
break;
|
||||
case LineScaleParty:
|
||||
mIndicatorController=new LineScalePartyIndicator();
|
||||
break;
|
||||
case BallScaleMultiple:
|
||||
mIndicatorController=new BallScaleMultipleIndicator();
|
||||
break;
|
||||
case BallPulseSync:
|
||||
mIndicatorController=new BallPulseSyncIndicator();
|
||||
break;
|
||||
case BallBeat:
|
||||
mIndicatorController=new BallBeatIndicator();
|
||||
break;
|
||||
case LineScalePulseOut:
|
||||
mIndicatorController=new LineScalePulseOutIndicator();
|
||||
break;
|
||||
case LineScalePulseOutRapid:
|
||||
mIndicatorController=new LineScalePulseOutRapidIndicator();
|
||||
break;
|
||||
case BallScaleRipple:
|
||||
mIndicatorController=new BallScaleRippleIndicator();
|
||||
break;
|
||||
case BallScaleRippleMultiple:
|
||||
mIndicatorController=new BallScaleRippleMultipleIndicator();
|
||||
break;
|
||||
case BallSpinFadeLoader:
|
||||
mIndicatorController=new BallSpinFadeLoaderIndicator();
|
||||
break;
|
||||
case LineSpinFadeLoader:
|
||||
mIndicatorController=new LineSpinFadeLoaderIndicator();
|
||||
break;
|
||||
case TriangleSkewSpin:
|
||||
mIndicatorController=new TriangleSkewSpinIndicator();
|
||||
break;
|
||||
case Pacman:
|
||||
mIndicatorController=new PacmanIndicator();
|
||||
break;
|
||||
case BallGridBeat:
|
||||
mIndicatorController=new BallGridBeatIndicator();
|
||||
break;
|
||||
case SemiCircleSpin:
|
||||
mIndicatorController=new SemiCircleSpinIndicator();
|
||||
break;
|
||||
}
|
||||
mIndicatorController.setTarget(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int width = measureDimension(dp2px(DEFAULT_SIZE), widthMeasureSpec);
|
||||
int height = measureDimension(dp2px(DEFAULT_SIZE), heightMeasureSpec);
|
||||
setMeasuredDimension(width, height);
|
||||
}
|
||||
|
||||
private int measureDimension(int defaultSize,int measureSpec){
|
||||
int result = defaultSize;
|
||||
int specMode = MeasureSpec.getMode(measureSpec);
|
||||
int specSize = MeasureSpec.getSize(measureSpec);
|
||||
if (specMode == MeasureSpec.EXACTLY) {
|
||||
result = specSize;
|
||||
} else if (specMode == MeasureSpec.AT_MOST) {
|
||||
result = Math.min(defaultSize, specSize);
|
||||
} else {
|
||||
result = defaultSize;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
drawIndicator(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
if (!mHasAnimation){
|
||||
mHasAnimation=true;
|
||||
applyAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int v) {
|
||||
if (getVisibility() != v) {
|
||||
super.setVisibility(v);
|
||||
if (v == GONE || v == INVISIBLE) {
|
||||
mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.END);
|
||||
} else {
|
||||
mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.START);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.CANCEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.START);
|
||||
}
|
||||
|
||||
void drawIndicator(Canvas canvas){
|
||||
mIndicatorController.draw(canvas, mPaint);
|
||||
}
|
||||
|
||||
void applyAnimation(){
|
||||
mIndicatorController.initAnimation();
|
||||
}
|
||||
|
||||
private int dp2px(int dpValue) {
|
||||
return (int) getContext().getResources().getDisplayMetrics().density * dpValue;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallBeatIndicator extends BaseIndicatorController {
|
||||
|
||||
public static final float SCALE=1.0f;
|
||||
|
||||
public static final int ALPHA=255;
|
||||
|
||||
private float[] scaleFloats=new float[]{SCALE,
|
||||
SCALE,
|
||||
SCALE};
|
||||
|
||||
int[] alphas=new int[]{ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,};
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float circleSpacing=4;
|
||||
float radius=(getWidth()-circleSpacing*2)/6;
|
||||
float x = getWidth()/ 2-(radius*2+circleSpacing);
|
||||
float y=getHeight() / 2;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
canvas.save();
|
||||
float translateX=x+(radius*2)*i+circleSpacing*i;
|
||||
canvas.translate(translateX, y);
|
||||
canvas.scale(scaleFloats[i], scaleFloats[i]);
|
||||
paint.setAlpha(alphas[i]);
|
||||
canvas.drawCircle(0, 0, radius, paint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
int[] delays=new int[]{350,0,350};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
final int index=i;
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(1,0.75f,1);
|
||||
scaleAnim.setDuration(700);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.setStartDelay(delays[i]);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleFloats[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
|
||||
ValueAnimator alphaAnim= ValueAnimator.ofInt(255,51,255);
|
||||
alphaAnim.setDuration(700);
|
||||
alphaAnim.setRepeatCount(-1);
|
||||
alphaAnim.setStartDelay(delays[i]);
|
||||
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
alphas[index] = (int) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
alphaAnim.start();
|
||||
animators.add(scaleAnim);
|
||||
animators.add(alphaAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallClipRotateIndicator extends BaseIndicatorController {
|
||||
|
||||
float scaleFloat=1,degrees;
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(3);
|
||||
|
||||
float circleSpacing=12;
|
||||
float x = (getWidth()) / 2;
|
||||
float y=(getHeight()) / 2;
|
||||
canvas.translate(x, y);
|
||||
canvas.scale(scaleFloat, scaleFloat);
|
||||
canvas.rotate(degrees);
|
||||
RectF rectF=new RectF(-x+circleSpacing,-y+circleSpacing,0+x-circleSpacing,0+y-circleSpacing);
|
||||
canvas.drawArc(rectF, -45, 270, false, paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(1,0.6f,0.5f,1);
|
||||
scaleAnim.setDuration(750);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleFloat = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
|
||||
ValueAnimator rotateAnim= ValueAnimator.ofFloat(0,180,360);
|
||||
rotateAnim.setDuration(750);
|
||||
rotateAnim.setRepeatCount(-1);
|
||||
rotateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
degrees = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
rotateAnim.start();
|
||||
animators.add(scaleAnim);
|
||||
animators.add(rotateAnim);
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallClipRotateMultipleIndicator extends BaseIndicatorController{
|
||||
|
||||
float scaleFloat=1,degrees;
|
||||
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
paint.setStrokeWidth(3);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
|
||||
float circleSpacing=12;
|
||||
float x=getWidth()/2;
|
||||
float y=getHeight()/2;
|
||||
|
||||
canvas.save();
|
||||
|
||||
canvas.translate(x, y);
|
||||
canvas.scale(scaleFloat, scaleFloat);
|
||||
canvas.rotate(degrees);
|
||||
|
||||
//draw two big arc
|
||||
float[] bStartAngles=new float[]{135,-45};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
RectF rectF=new RectF(-x+circleSpacing,-y+circleSpacing,x-circleSpacing,y-circleSpacing);
|
||||
canvas.drawArc(rectF, bStartAngles[i], 90, false, paint);
|
||||
}
|
||||
|
||||
canvas.restore();
|
||||
canvas.translate(x, y);
|
||||
canvas.scale(scaleFloat, scaleFloat);
|
||||
canvas.rotate(-degrees);
|
||||
//draw two small arc
|
||||
float[] sStartAngles=new float[]{225,45};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
RectF rectF=new RectF(-x/1.8f+circleSpacing,-y/1.8f+circleSpacing,x/1.8f-circleSpacing,y/1.8f-circleSpacing);
|
||||
canvas.drawArc(rectF, sStartAngles[i], 90, false, paint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(1,0.6f,1);
|
||||
scaleAnim.setDuration(1000);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleFloat = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
|
||||
ValueAnimator rotateAnim= ValueAnimator.ofFloat(0, 180,360);
|
||||
rotateAnim.setDuration(1000);
|
||||
rotateAnim.setRepeatCount(-1);
|
||||
rotateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
degrees = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
rotateAnim.start();
|
||||
animators.add(scaleAnim);
|
||||
animators.add(rotateAnim);
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,94 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallClipRotatePulseIndicator extends BaseIndicatorController {
|
||||
|
||||
float scaleFloat1,scaleFloat2,degrees;
|
||||
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float circleSpacing=12;
|
||||
float x=getWidth()/2;
|
||||
float y=getHeight()/2;
|
||||
|
||||
//draw fill circle
|
||||
canvas.save();
|
||||
canvas.translate(x, y);
|
||||
canvas.scale(scaleFloat1, scaleFloat1);
|
||||
paint.setStyle(Paint.Style.FILL);
|
||||
canvas.drawCircle(0, 0, x / 2.5f, paint);
|
||||
|
||||
canvas.restore();
|
||||
|
||||
canvas.translate(x, y);
|
||||
canvas.scale(scaleFloat2, scaleFloat2);
|
||||
canvas.rotate(degrees);
|
||||
|
||||
paint.setStrokeWidth(3);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
|
||||
//draw two arc
|
||||
float[] startAngles=new float[]{225,45};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
RectF rectF=new RectF(-x+circleSpacing,-y+circleSpacing,x-circleSpacing,y-circleSpacing);
|
||||
canvas.drawArc(rectF, startAngles[i], 90, false, paint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(1,0.3f,1);
|
||||
scaleAnim.setDuration(1000);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleFloat1 = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
|
||||
ValueAnimator scaleAnim2= ValueAnimator.ofFloat(1,0.6f,1);
|
||||
scaleAnim2.setDuration(1000);
|
||||
scaleAnim2.setRepeatCount(-1);
|
||||
scaleAnim2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleFloat2 = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim2.start();
|
||||
|
||||
ValueAnimator rotateAnim= ValueAnimator.ofFloat(0, 180,360);
|
||||
rotateAnim.setDuration(1000);
|
||||
rotateAnim.setRepeatCount(-1);
|
||||
rotateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
degrees = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
rotateAnim.start();
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
animators.add(scaleAnim);
|
||||
animators.add(scaleAnim2);
|
||||
animators.add(rotateAnim);
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallGridBeatIndicator extends BaseIndicatorController {
|
||||
|
||||
public static final int ALPHA=255;
|
||||
|
||||
int[] alphas=new int[]{ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA};
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float circleSpacing=4;
|
||||
float radius=(getWidth()-circleSpacing*4)/6;
|
||||
float x = getWidth()/ 2-(radius*2+circleSpacing);
|
||||
float y = getWidth()/ 2-(radius*2+circleSpacing);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
canvas.save();
|
||||
float translateX=x+(radius*2)*j+circleSpacing*j;
|
||||
float translateY=y+(radius*2)*i+circleSpacing*i;
|
||||
canvas.translate(translateX, translateY);
|
||||
paint.setAlpha(alphas[3 * i + j]);
|
||||
canvas.drawCircle(0, 0, radius, paint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
|
||||
int[] durations={960, 930, 1190, 1130, 1340, 940, 1200, 820, 1190};
|
||||
int[] delays= {360, 400, 680, 410, 710, -150, -120, 10, 320};
|
||||
|
||||
for (int i = 0; i < 9; i++) {
|
||||
final int index=i;
|
||||
ValueAnimator alphaAnim= ValueAnimator.ofInt(255, 168,255);
|
||||
alphaAnim.setDuration(durations[i]);
|
||||
alphaAnim.setRepeatCount(-1);
|
||||
alphaAnim.setStartDelay(delays[i]);
|
||||
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
alphas[index] = (int) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
alphaAnim.start();
|
||||
animators.add(alphaAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallGridPulseIndicator extends BaseIndicatorController{
|
||||
|
||||
public static final int ALPHA=255;
|
||||
|
||||
public static final float SCALE=1.0f;
|
||||
|
||||
int[] alphas=new int[]{ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA};
|
||||
|
||||
float[] scaleFloats=new float[]{SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE};
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float circleSpacing=4;
|
||||
float radius=(getWidth()-circleSpacing*4)/6;
|
||||
float x = getWidth()/ 2-(radius*2+circleSpacing);
|
||||
float y = getWidth()/ 2-(radius*2+circleSpacing);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
canvas.save();
|
||||
float translateX=x+(radius*2)*j+circleSpacing*j;
|
||||
float translateY=y+(radius*2)*i+circleSpacing*i;
|
||||
canvas.translate(translateX, translateY);
|
||||
canvas.scale(scaleFloats[3 * i + j], scaleFloats[3 * i + j]);
|
||||
paint.setAlpha(alphas[3 * i + j]);
|
||||
canvas.drawCircle(0, 0, radius, paint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
int[] durations={720, 1020, 1280, 1420, 1450, 1180, 870, 1450, 1060};
|
||||
int[] delays= {-60, 250, -170, 480, 310, 30, 460, 780, 450};
|
||||
|
||||
for (int i = 0; i < 9; i++) {
|
||||
final int index=i;
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(1,0.5f,1);
|
||||
scaleAnim.setDuration(durations[i]);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.setStartDelay(delays[i]);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleFloats[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
|
||||
ValueAnimator alphaAnim= ValueAnimator.ofInt(255, 210, 122, 255);
|
||||
alphaAnim.setDuration(durations[i]);
|
||||
alphaAnim.setRepeatCount(-1);
|
||||
alphaAnim.setStartDelay(delays[i]);
|
||||
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
alphas[index] = (int) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
alphaAnim.start();
|
||||
animators.add(scaleAnim);
|
||||
animators.add(alphaAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallPulseIndicator extends BaseIndicatorController{
|
||||
|
||||
public static final float SCALE=1.0f;
|
||||
|
||||
//scale x ,y
|
||||
private float[] scaleFloats=new float[]{SCALE,
|
||||
SCALE,
|
||||
SCALE};
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float circleSpacing=4;
|
||||
float radius=(Math.min(getWidth(),getHeight())-circleSpacing*2)/6;
|
||||
float x = getWidth()/ 2-(radius*2+circleSpacing);
|
||||
float y=getHeight() / 2;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
canvas.save();
|
||||
float translateX=x+(radius*2)*i+circleSpacing*i;
|
||||
canvas.translate(translateX, y);
|
||||
canvas.scale(scaleFloats[i], scaleFloats[i]);
|
||||
canvas.drawCircle(0, 0, radius, paint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
int[] delays=new int[]{120,240,360};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
final int index=i;
|
||||
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(1,0.3f,1);
|
||||
|
||||
scaleAnim.setDuration(750);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.setStartDelay(delays[i]);
|
||||
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleFloats[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
animators.add(scaleAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallPulseRiseIndicator extends BaseIndicatorController{
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float radius=getWidth()/10;
|
||||
canvas.drawCircle(getWidth()/4,radius*2,radius,paint);
|
||||
canvas.drawCircle(getWidth()*3/4,radius*2,radius,paint);
|
||||
|
||||
canvas.drawCircle(radius,getHeight()-2*radius,radius,paint);
|
||||
canvas.drawCircle(getWidth()/2,getHeight()-2*radius,radius,paint);
|
||||
canvas.drawCircle(getWidth()-radius,getHeight()-2*radius,radius,paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
PropertyValuesHolder rotation6= PropertyValuesHolder.ofFloat("rotationX",0,360);
|
||||
ObjectAnimator animator= ObjectAnimator.ofPropertyValuesHolder(getTarget(), rotation6);
|
||||
animator.setInterpolator(new LinearInterpolator());
|
||||
animator.setRepeatCount(-1);
|
||||
animator.setDuration(1500);
|
||||
animator.start();
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
animators.add(animator);
|
||||
return animators;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,57 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallPulseSyncIndicator extends BaseIndicatorController {
|
||||
|
||||
float[] translateYFloats=new float[3];
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float circleSpacing=4;
|
||||
float radius=(getWidth()-circleSpacing*2)/6;
|
||||
float x = getWidth()/ 2-(radius*2+circleSpacing);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
canvas.save();
|
||||
float translateX=x+(radius*2)*i+circleSpacing*i;
|
||||
canvas.translate(translateX, translateYFloats[i]);
|
||||
canvas.drawCircle(0, 0, radius, paint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
float circleSpacing=4;
|
||||
float radius=(getWidth()-circleSpacing*2)/6;
|
||||
int[] delays=new int[]{70,140,210};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
final int index=i;
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(getHeight()/2,getHeight()/2-radius*2,getHeight()/2);
|
||||
scaleAnim.setDuration(600);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.setStartDelay(delays[i]);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
translateYFloats[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
animators.add(scaleAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallRotateIndicator extends BaseIndicatorController{
|
||||
|
||||
float scaleFloat=0.5f;
|
||||
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float radius=getWidth()/10;
|
||||
float x = getWidth()/ 2;
|
||||
float y=getHeight()/2;
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(x - radius * 2 - radius, y);
|
||||
canvas.scale(scaleFloat, scaleFloat);
|
||||
canvas.drawCircle(0, 0, radius, paint);
|
||||
canvas.restore();
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(x, y);
|
||||
canvas.scale(scaleFloat, scaleFloat);
|
||||
canvas.drawCircle(0, 0, radius, paint);
|
||||
canvas.restore();
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(x + radius * 2 + radius, y);
|
||||
canvas.scale(scaleFloat, scaleFloat);
|
||||
canvas.drawCircle(0,0,radius, paint);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(0.5f,1,0.5f);
|
||||
scaleAnim.setDuration(1000);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleFloat = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
|
||||
ObjectAnimator rotateAnim= ObjectAnimator.ofFloat(getTarget(),"rotation",0,180,360);
|
||||
rotateAnim.setDuration(1000);
|
||||
rotateAnim.setRepeatCount(-1);
|
||||
rotateAnim.start();
|
||||
|
||||
animators.add(scaleAnim);
|
||||
animators.add(rotateAnim);
|
||||
return animators;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallScaleIndicator extends BaseIndicatorController {
|
||||
|
||||
float scale=1;
|
||||
int alpha=255;
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float circleSpacing=4;
|
||||
paint.setAlpha(alpha);
|
||||
canvas.scale(scale,scale,getWidth()/2,getHeight()/2);
|
||||
paint.setAlpha(alpha);
|
||||
canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2-circleSpacing,paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(0,1);
|
||||
scaleAnim.setInterpolator(new LinearInterpolator());
|
||||
scaleAnim.setDuration(1000);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scale = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
|
||||
ValueAnimator alphaAnim= ValueAnimator.ofInt(255, 0);
|
||||
alphaAnim.setInterpolator(new LinearInterpolator());
|
||||
alphaAnim.setDuration(1000);
|
||||
alphaAnim.setRepeatCount(-1);
|
||||
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
alpha = (int) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
alphaAnim.start();
|
||||
animators.add(scaleAnim);
|
||||
animators.add(alphaAnim);
|
||||
return animators;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallScaleMultipleIndicator extends BaseIndicatorController {
|
||||
|
||||
float[] scaleFloats=new float[]{1,1,1};
|
||||
int[] alphaInts=new int[]{255,255,255};
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float circleSpacing=4;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
paint.setAlpha(alphaInts[i]);
|
||||
canvas.scale(scaleFloats[i],scaleFloats[i],getWidth()/2,getHeight()/2);
|
||||
canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2-circleSpacing,paint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
long[] delays=new long[]{0, 200, 400};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
final int index=i;
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(0,1);
|
||||
scaleAnim.setInterpolator(new LinearInterpolator());
|
||||
scaleAnim.setDuration(1000);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleFloats[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.setStartDelay(delays[i]);
|
||||
scaleAnim.start();
|
||||
|
||||
ValueAnimator alphaAnim= ValueAnimator.ofInt(255,0);
|
||||
alphaAnim.setInterpolator(new LinearInterpolator());
|
||||
alphaAnim.setDuration(1000);
|
||||
alphaAnim.setRepeatCount(-1);
|
||||
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
alphaInts[index] = (int) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.setStartDelay(delays[i]);
|
||||
alphaAnim.start();
|
||||
|
||||
animators.add(scaleAnim);
|
||||
animators.add(alphaAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallScaleRippleIndicator extends BallScaleIndicator {
|
||||
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(3);
|
||||
super.draw(canvas, paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(0,1);
|
||||
scaleAnim.setInterpolator(new LinearInterpolator());
|
||||
scaleAnim.setDuration(1000);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scale = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
|
||||
ValueAnimator alphaAnim= ValueAnimator.ofInt(0, 255);
|
||||
alphaAnim.setInterpolator(new LinearInterpolator());
|
||||
alphaAnim.setDuration(1000);
|
||||
alphaAnim.setRepeatCount(-1);
|
||||
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
alpha = (int) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
alphaAnim.start();
|
||||
|
||||
animators.add(scaleAnim);
|
||||
animators.add(alphaAnim);
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallScaleRippleMultipleIndicator extends BallScaleMultipleIndicator{
|
||||
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(3);
|
||||
super.draw(canvas, paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
long[] delays=new long[]{0, 200, 400};
|
||||
for (int i = 0; i < 3; i++) {
|
||||
final int index=i;
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(0,1);
|
||||
scaleAnim.setInterpolator(new LinearInterpolator());
|
||||
scaleAnim.setDuration(1000);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleFloats[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.setStartDelay(delays[i]);
|
||||
scaleAnim.start();
|
||||
|
||||
ValueAnimator alphaAnim= ValueAnimator.ofInt(0,255);
|
||||
scaleAnim.setInterpolator(new LinearInterpolator());
|
||||
alphaAnim.setDuration(1000);
|
||||
alphaAnim.setRepeatCount(-1);
|
||||
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
alphaInts[index] = (int) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.setStartDelay(delays[i]);
|
||||
alphaAnim.start();
|
||||
|
||||
animators.add(scaleAnim);
|
||||
animators.add(alphaAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,116 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallSpinFadeLoaderIndicator extends BaseIndicatorController {
|
||||
|
||||
public static final float SCALE=1.0f;
|
||||
|
||||
public static final int ALPHA=255;
|
||||
|
||||
float[] scaleFloats=new float[]{SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE};
|
||||
|
||||
int[] alphas=new int[]{ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA,
|
||||
ALPHA};
|
||||
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float radius=getWidth()/10;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
canvas.save();
|
||||
Point point=circleAt(getWidth(),getHeight(),getWidth()/2-radius,i*(Math.PI/4));
|
||||
canvas.translate(point.x,point.y);
|
||||
canvas.scale(scaleFloats[i],scaleFloats[i]);
|
||||
paint.setAlpha(alphas[i]);
|
||||
canvas.drawCircle(0,0,radius,paint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 圆O的圆心为(a,b),半径为R,点A与到X轴的为角α.
|
||||
*则点A的坐标为(a+R*cosα,b+R*sinα)
|
||||
* @param width
|
||||
* @param height
|
||||
* @param radius
|
||||
* @param angle
|
||||
* @return
|
||||
*/
|
||||
Point circleAt(int width,int height,float radius,double angle){
|
||||
float x= (float) (width/2+radius*(Math.cos(angle)));
|
||||
float y= (float) (height/2+radius*(Math.sin(angle)));
|
||||
return new Point(x,y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
int[] delays= {0, 120, 240, 360, 480, 600, 720, 780, 840};
|
||||
for (int i = 0; i < 8; i++) {
|
||||
final int index=i;
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(1,0.4f,1);
|
||||
scaleAnim.setDuration(1000);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.setStartDelay(delays[i]);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleFloats[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
|
||||
ValueAnimator alphaAnim= ValueAnimator.ofInt(255, 77, 255);
|
||||
alphaAnim.setDuration(1000);
|
||||
alphaAnim.setRepeatCount(-1);
|
||||
alphaAnim.setStartDelay(delays[i]);
|
||||
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
alphas[index] = (int) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
alphaAnim.start();
|
||||
animators.add(scaleAnim);
|
||||
animators.add(alphaAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
final class Point{
|
||||
public float x;
|
||||
public float y;
|
||||
|
||||
public Point(float x, float y){
|
||||
this.x=x;
|
||||
this.y=y;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallTrianglePathIndicator extends BaseIndicatorController {
|
||||
|
||||
float[] translateX=new float[3],translateY=new float[3];
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
paint.setStrokeWidth(3);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
canvas.save();
|
||||
canvas.translate(translateX[i], translateY[i]);
|
||||
canvas.drawCircle(0, 0, getWidth() / 10, paint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
float startX=getWidth()/5;
|
||||
float startY=getWidth()/5;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
final int index=i;
|
||||
ValueAnimator translateXAnim= ValueAnimator.ofFloat(getWidth()/2,getWidth()-startX,startX,getWidth()/2);
|
||||
if (i==1){
|
||||
translateXAnim= ValueAnimator.ofFloat(getWidth()-startX,startX,getWidth()/2,getWidth()-startX);
|
||||
}else if (i==2){
|
||||
translateXAnim= ValueAnimator.ofFloat(startX,getWidth()/2,getWidth()-startX,startX);
|
||||
}
|
||||
ValueAnimator translateYAnim= ValueAnimator.ofFloat(startY,getHeight()-startY,getHeight()-startY,startY);
|
||||
if (i==1){
|
||||
translateYAnim= ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,startY,getHeight()-startY);
|
||||
}else if (i==2){
|
||||
translateYAnim= ValueAnimator.ofFloat(getHeight()-startY,startY,getHeight()-startY,getHeight()-startY);
|
||||
}
|
||||
|
||||
translateXAnim.setDuration(2000);
|
||||
translateXAnim.setInterpolator(new LinearInterpolator());
|
||||
translateXAnim.setRepeatCount(-1);
|
||||
translateXAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
translateX [index]= (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
translateXAnim.start();
|
||||
|
||||
translateYAnim.setDuration(2000);
|
||||
translateYAnim.setInterpolator(new LinearInterpolator());
|
||||
translateYAnim.setRepeatCount(-1);
|
||||
translateYAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
translateY [index]= (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
translateYAnim.start();
|
||||
|
||||
animators.add(translateXAnim);
|
||||
animators.add(translateYAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallZigZagDeflectIndicator extends BallZigZagIndicator {
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
float startX=getWidth()/6;
|
||||
float startY=getWidth()/6;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
final int index=i;
|
||||
ValueAnimator translateXAnim= ValueAnimator.ofFloat(startX,getWidth()-startX,startX,getWidth()-startX,startX);
|
||||
if (i==1){
|
||||
translateXAnim= ValueAnimator.ofFloat(getWidth()-startX,startX,getWidth()-startX,startX,getWidth()-startX);
|
||||
}
|
||||
ValueAnimator translateYAnim= ValueAnimator.ofFloat(startY,startY,getHeight()-startY,getHeight()-startY,startY);
|
||||
if (i==1){
|
||||
translateYAnim= ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,startY,startY,getHeight()-startY);
|
||||
}
|
||||
|
||||
translateXAnim.setDuration(2000);
|
||||
translateXAnim.setInterpolator(new LinearInterpolator());
|
||||
translateXAnim.setRepeatCount(-1);
|
||||
translateXAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
translateX [index]= (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
translateXAnim.start();
|
||||
|
||||
translateYAnim.setDuration(2000);
|
||||
translateYAnim.setInterpolator(new LinearInterpolator());
|
||||
translateYAnim.setRepeatCount(-1);
|
||||
translateYAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
translateY [index]= (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
translateYAnim.start();
|
||||
|
||||
animators.add(translateXAnim);
|
||||
animators.add(translateYAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class BallZigZagIndicator extends BaseIndicatorController {
|
||||
|
||||
float[] translateX=new float[2],translateY=new float[2];
|
||||
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
canvas.save();
|
||||
canvas.translate(translateX[i], translateY[i]);
|
||||
canvas.drawCircle(0, 0, getWidth() / 10, paint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
float startX=getWidth()/6;
|
||||
float startY=getWidth()/6;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
final int index=i;
|
||||
ValueAnimator translateXAnim= ValueAnimator.ofFloat(startX,getWidth()-startX,getWidth()/2,startX);
|
||||
if (i==1){
|
||||
translateXAnim= ValueAnimator.ofFloat(getWidth()-startX,startX,getWidth()/2,getWidth()-startX);
|
||||
}
|
||||
ValueAnimator translateYAnim= ValueAnimator.ofFloat(startY,startY,getHeight()/2,startY);
|
||||
if (i==1){
|
||||
translateYAnim= ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,getHeight()/2,getHeight()-startY);
|
||||
}
|
||||
|
||||
translateXAnim.setDuration(1000);
|
||||
translateXAnim.setInterpolator(new LinearInterpolator());
|
||||
translateXAnim.setRepeatCount(-1);
|
||||
translateXAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
translateX[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
translateXAnim.start();
|
||||
|
||||
translateYAnim.setDuration(1000);
|
||||
translateYAnim.setInterpolator(new LinearInterpolator());
|
||||
translateYAnim.setRepeatCount(-1);
|
||||
translateYAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
translateY[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
translateYAnim.start();
|
||||
animators.add(translateXAnim);
|
||||
animators.add(translateYAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,100 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.view.View;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public abstract class BaseIndicatorController {
|
||||
|
||||
|
||||
private View mTarget;
|
||||
|
||||
private List<Animator> mAnimators;
|
||||
|
||||
|
||||
public void setTarget(View target){
|
||||
this.mTarget=target;
|
||||
}
|
||||
|
||||
public View getTarget(){
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
|
||||
public int getWidth(){
|
||||
return mTarget.getWidth();
|
||||
}
|
||||
|
||||
public int getHeight(){
|
||||
return mTarget.getHeight();
|
||||
}
|
||||
|
||||
public void postInvalidate(){
|
||||
mTarget.postInvalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* draw indicator
|
||||
* @param canvas
|
||||
* @param paint
|
||||
*/
|
||||
public abstract void draw(Canvas canvas, Paint paint);
|
||||
|
||||
/**
|
||||
* create animation or animations
|
||||
*/
|
||||
public abstract List<Animator> createAnimation();
|
||||
|
||||
public void initAnimation(){
|
||||
mAnimators=createAnimation();
|
||||
}
|
||||
|
||||
/**
|
||||
* make animation to start or end when target
|
||||
* view was be Visible or Gone or Invisible.
|
||||
* make animation to cancel when target view
|
||||
* be onDetachedFromWindow.
|
||||
* @param animStatus
|
||||
*/
|
||||
public void setAnimationStatus(AnimStatus animStatus){
|
||||
if (mAnimators==null){
|
||||
return;
|
||||
}
|
||||
int count=mAnimators.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
Animator animator=mAnimators.get(i);
|
||||
boolean isRunning=animator.isRunning();
|
||||
switch (animStatus){
|
||||
case START:
|
||||
if (!isRunning){
|
||||
animator.start();
|
||||
}
|
||||
break;
|
||||
case END:
|
||||
if (isRunning){
|
||||
animator.end();
|
||||
}
|
||||
break;
|
||||
case CANCEL:
|
||||
if (isRunning){
|
||||
animator.cancel();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public enum AnimStatus{
|
||||
START,END,CANCEL
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,110 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class CubeTransitionIndicator extends BaseIndicatorController {
|
||||
|
||||
float[] translateX=new float[2],translateY=new float[2];
|
||||
float degrees,scaleFloat=1.0f;
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float rWidth=getWidth()/5;
|
||||
float rHeight=getHeight()/5;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
canvas.save();
|
||||
canvas.translate(translateX[i], translateY[i]);
|
||||
canvas.rotate(degrees);
|
||||
canvas.scale(scaleFloat,scaleFloat);
|
||||
RectF rectF=new RectF(-rWidth/2,-rHeight/2,rWidth/2,rHeight/2);
|
||||
canvas.drawRect(rectF,paint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
float startX=getWidth()/5;
|
||||
float startY=getHeight()/5;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
final int index=i;
|
||||
translateX[index]=startX;
|
||||
ValueAnimator translationXAnim= ValueAnimator.ofFloat(startX,getWidth()-startX,getWidth()-startX, startX,startX);
|
||||
if (i==1){
|
||||
translationXAnim= ValueAnimator.ofFloat(getWidth()-startX,startX,startX, getWidth()-startX,getWidth()-startX);
|
||||
}
|
||||
translationXAnim.setInterpolator(new LinearInterpolator());
|
||||
translationXAnim.setDuration(1600);
|
||||
translationXAnim.setRepeatCount(-1);
|
||||
translationXAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
translateX[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
translationXAnim.start();
|
||||
translateY[index]=startY;
|
||||
ValueAnimator translationYAnim= ValueAnimator.ofFloat(startY,startY,getHeight()-startY,getHeight()- startY,startY);
|
||||
if (i==1){
|
||||
translationYAnim= ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,startY,startY,getHeight()-startY);
|
||||
}
|
||||
translationYAnim.setDuration(1600);
|
||||
translationYAnim.setInterpolator(new LinearInterpolator());
|
||||
translationYAnim.setRepeatCount(-1);
|
||||
translationYAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
translateY[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
translationYAnim.start();
|
||||
|
||||
animators.add(translationXAnim);
|
||||
animators.add(translationYAnim);
|
||||
}
|
||||
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(1,0.5f,1,0.5f,1);
|
||||
scaleAnim.setDuration(1600);
|
||||
scaleAnim.setInterpolator(new LinearInterpolator());
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleFloat = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
|
||||
ValueAnimator rotateAnim= ValueAnimator.ofFloat(0,180,360,1.5f*360,2*360);
|
||||
rotateAnim.setDuration(1600);
|
||||
rotateAnim.setInterpolator(new LinearInterpolator());
|
||||
rotateAnim.setRepeatCount(-1);
|
||||
rotateAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
degrees = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
rotateAnim.start();
|
||||
|
||||
animators.add(scaleAnim);
|
||||
animators.add(rotateAnim);
|
||||
return animators;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class LineScaleIndicator extends BaseIndicatorController {
|
||||
|
||||
public static final float SCALE=1.0f;
|
||||
|
||||
float[] scaleYFloats=new float[]{SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE,};
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float translateX=getWidth()/11;
|
||||
float translateY=getHeight()/2;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
canvas.save();
|
||||
canvas.translate((2 + i * 2) * translateX - translateX / 2, translateY);
|
||||
canvas.scale(SCALE, scaleYFloats[i]);
|
||||
RectF rectF=new RectF(-translateX/2,-getHeight()/2.5f,translateX/2,getHeight()/2.5f);
|
||||
canvas.drawRoundRect(rectF, 5, 5, paint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
long[] delays=new long[]{100,200,300,400,500};
|
||||
for (int i = 0; i < 5; i++) {
|
||||
final int index=i;
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(1, 0.4f, 1);
|
||||
scaleAnim.setDuration(1000);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.setStartDelay(delays[i]);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleYFloats[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
animators.add(scaleAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class LineScalePartyIndicator extends BaseIndicatorController {
|
||||
|
||||
public static final float SCALE=1.0f;
|
||||
|
||||
float[] scaleFloats=new float[]{SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE,
|
||||
SCALE,};
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float translateX=getWidth()/9;
|
||||
float translateY=getHeight()/2;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
canvas.save();
|
||||
canvas.translate((2 + i * 2) * translateX - translateX / 2, translateY);
|
||||
canvas.scale(scaleFloats[i], scaleFloats[i]);
|
||||
RectF rectF=new RectF(-translateX/2,-getHeight()/2.5f,translateX/2,getHeight()/2.5f);
|
||||
canvas.drawRoundRect(rectF,5,5,paint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
long[] durations=new long[]{1260, 430, 1010, 730};
|
||||
long[] delays=new long[]{770, 290, 280, 740};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
final int index=i;
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(1,0.4f,1);
|
||||
scaleAnim.setDuration(durations[i]);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.setStartDelay(delays[i]);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleFloats[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
animators.add(scaleAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class LineScalePulseOutIndicator extends LineScaleIndicator {
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
long[] delays=new long[]{500,250,0,250,500};
|
||||
for (int i = 0; i < 5; i++) {
|
||||
final int index=i;
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(1,0.3f,1);
|
||||
scaleAnim.setDuration(900);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.setStartDelay(delays[i]);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleYFloats[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
animators.add(scaleAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class LineScalePulseOutRapidIndicator extends LineScaleIndicator {
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
long[] delays=new long[]{400,200,0,200,400};
|
||||
for (int i = 0; i < 5; i++) {
|
||||
final int index=i;
|
||||
ValueAnimator scaleAnim= ValueAnimator.ofFloat(1,0.4f,1);
|
||||
scaleAnim.setDuration(1000);
|
||||
scaleAnim.setRepeatCount(-1);
|
||||
scaleAnim.setStartDelay(delays[i]);
|
||||
scaleAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
scaleYFloats[index] = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
scaleAnim.start();
|
||||
animators.add(scaleAnim);
|
||||
}
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class LineSpinFadeLoaderIndicator extends BallSpinFadeLoaderIndicator {
|
||||
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
float radius=getWidth()/10;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
canvas.save();
|
||||
Point point=circleAt(getWidth(),getHeight(),getWidth()/2.5f-radius,i*(Math.PI/4));
|
||||
canvas.translate(point.x, point.y);
|
||||
canvas.scale(scaleFloats[i], scaleFloats[i]);
|
||||
canvas.rotate(i*45);
|
||||
paint.setAlpha(alphas[i]);
|
||||
RectF rectF=new RectF(-radius,-radius/1.5f,1.5f*radius,radius/1.5f);
|
||||
canvas.drawRoundRect(rectF,5,5,paint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,119 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class PacmanIndicator extends BaseIndicatorController{
|
||||
|
||||
private float translateX;
|
||||
|
||||
private int alpha;
|
||||
|
||||
private float degrees1,degrees2;
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
drawPacman(canvas,paint);
|
||||
drawCircle(canvas,paint);
|
||||
}
|
||||
|
||||
private void drawPacman(Canvas canvas, Paint paint){
|
||||
float x=getWidth()/2;
|
||||
float y=getHeight()/2;
|
||||
|
||||
canvas.save();
|
||||
|
||||
canvas.translate(x, y);
|
||||
canvas.rotate(degrees1);
|
||||
paint.setAlpha(255);
|
||||
RectF rectF1=new RectF(-x/1.7f,-y/1.7f,x/1.7f,y/1.7f);
|
||||
canvas.drawArc(rectF1, 0, 270, true, paint);
|
||||
|
||||
canvas.restore();
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(x, y);
|
||||
canvas.rotate(degrees2);
|
||||
paint.setAlpha(255);
|
||||
RectF rectF2=new RectF(-x/1.7f,-y/1.7f,x/1.7f,y/1.7f);
|
||||
canvas.drawArc(rectF2,90,270,true,paint);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
|
||||
private void drawCircle(Canvas canvas, Paint paint) {
|
||||
float radius=getWidth()/11;
|
||||
paint.setAlpha(alpha);
|
||||
canvas.drawCircle(translateX, getHeight() / 2, radius, paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
float startT=getWidth()/11;
|
||||
ValueAnimator translationAnim= ValueAnimator.ofFloat(getWidth()-startT,getWidth()/2);
|
||||
translationAnim.setDuration(650);
|
||||
translationAnim.setInterpolator(new LinearInterpolator());
|
||||
translationAnim.setRepeatCount(-1);
|
||||
translationAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
translateX = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
translationAnim.start();
|
||||
|
||||
ValueAnimator alphaAnim= ValueAnimator.ofInt(255,122);
|
||||
alphaAnim.setDuration(650);
|
||||
alphaAnim.setRepeatCount(-1);
|
||||
alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
alpha = (int) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
alphaAnim.start();
|
||||
|
||||
ValueAnimator rotateAnim1= ValueAnimator.ofFloat(0, 45, 0);
|
||||
rotateAnim1.setDuration(650);
|
||||
rotateAnim1.setRepeatCount(-1);
|
||||
rotateAnim1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
degrees1 = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
rotateAnim1.start();
|
||||
|
||||
ValueAnimator rotateAnim2= ValueAnimator.ofFloat(0,-45,0);
|
||||
rotateAnim2.setDuration(650);
|
||||
rotateAnim2.setRepeatCount(-1);
|
||||
rotateAnim2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
degrees2 = (float) animation.getAnimatedValue();
|
||||
postInvalidate();
|
||||
}
|
||||
});
|
||||
rotateAnim2.start();
|
||||
|
||||
animators.add(translationAnim);
|
||||
animators.add(alphaAnim);
|
||||
animators.add(rotateAnim1);
|
||||
animators.add(rotateAnim2);
|
||||
return animators;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class SemiCircleSpinIndicator extends BaseIndicatorController {
|
||||
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
RectF rectF=new RectF(0,0,getWidth(),getHeight());
|
||||
canvas.drawArc(rectF,-60,120,false,paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
ObjectAnimator rotateAnim= ObjectAnimator.ofFloat(getTarget(),"rotation",0,180,360);
|
||||
rotateAnim.setDuration(600);
|
||||
rotateAnim.setRepeatCount(-1);
|
||||
rotateAnim.start();
|
||||
animators.add(rotateAnim);
|
||||
return animators;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class SquareSpinIndicator extends BaseIndicatorController {
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
canvas.drawRect(new RectF(getWidth()/5,getHeight()/5,getWidth()*4/5,getHeight()*4/5),paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
PropertyValuesHolder rotation5= PropertyValuesHolder.ofFloat("rotationX",0,180,180,0,0);
|
||||
PropertyValuesHolder rotation6= PropertyValuesHolder.ofFloat("rotationY",0,0,180,180,0);
|
||||
ObjectAnimator animator= ObjectAnimator.ofPropertyValuesHolder(getTarget(), rotation6,rotation5);
|
||||
animator.setInterpolator(new LinearInterpolator());
|
||||
animator.setRepeatCount(-1);
|
||||
animator.setDuration(2500);
|
||||
animator.start();
|
||||
animators.add(animator);
|
||||
return animators;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.progressindicator.indicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/19.
|
||||
*/
|
||||
public class TriangleSkewSpinIndicator extends BaseIndicatorController {
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas, Paint paint) {
|
||||
Path path=new Path();
|
||||
path.moveTo(getWidth()/5,getHeight()*4/5);
|
||||
path.lineTo(getWidth()*4/5, getHeight()*4/5);
|
||||
path.lineTo(getWidth()/2,getHeight()/5);
|
||||
path.close();
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Animator> createAnimation() {
|
||||
List<Animator> animators=new ArrayList<>();
|
||||
PropertyValuesHolder rotation5= PropertyValuesHolder.ofFloat("rotationX",0,180,180,0,0);
|
||||
PropertyValuesHolder rotation6= PropertyValuesHolder.ofFloat("rotationY",0,0,180,180,0);
|
||||
|
||||
ObjectAnimator animator= ObjectAnimator.ofPropertyValuesHolder(getTarget(), rotation6,rotation5);
|
||||
animator.setInterpolator(new LinearInterpolator());
|
||||
animator.setRepeatCount(-1);
|
||||
animator.setDuration(2500);
|
||||
animator.start();
|
||||
|
||||
animators.add(animator);
|
||||
return animators;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,275 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.swipemenu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import androidx.core.view.GestureDetectorCompat;
|
||||
import androidx.core.widget.ScrollerCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.GestureDetector.OnGestureListener;
|
||||
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.superrecycleview.superlibrary.R;
|
||||
/**
|
||||
* Created by super南仔 on 07/28/16.
|
||||
* blog: http://supercwn.github.io/
|
||||
* GitHub: https://github.com/supercwn
|
||||
*/
|
||||
public class SuperSwipeMenuLayout extends FrameLayout {
|
||||
|
||||
private static final int STATE_CLOSE = 0;
|
||||
private static final int STATE_OPEN = 1;
|
||||
private static final boolean OVER_API_11 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
|
||||
private int mSwipeDirection;
|
||||
private View mContentView;
|
||||
private View mMenuView;
|
||||
private int mDownX;
|
||||
private int state = STATE_CLOSE;
|
||||
private GestureDetectorCompat mGestureDetector;
|
||||
private OnGestureListener mGestureListener;
|
||||
private boolean isFling;
|
||||
private ScrollerCompat mOpenScroller;
|
||||
private ScrollerCompat mCloseScroller;
|
||||
private int mBaseX;
|
||||
private Interpolator mCloseInterpolator;
|
||||
private Interpolator mOpenInterpolator;
|
||||
private ViewConfiguration mViewConfiguration;
|
||||
private boolean swipeEnable = true;
|
||||
private int animDuration;
|
||||
|
||||
public SuperSwipeMenuLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public SuperSwipeMenuLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public SuperSwipeMenuLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
if(!isInEditMode()){
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwipeMenu, 0, defStyle);
|
||||
animDuration = a.getInteger(R.styleable.SwipeMenu_anim_duration, 500);
|
||||
a.recycle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
setClickable(true);
|
||||
mContentView = findViewById(R.id.smContentView);
|
||||
if (mContentView == null) {
|
||||
throw new IllegalArgumentException("not find contentView by id smContentView");
|
||||
}
|
||||
mMenuView = findViewById(R.id.smMenuView);
|
||||
if (mMenuView == null) {
|
||||
throw new IllegalArgumentException("not find menuView by id smMenuView");
|
||||
}
|
||||
mViewConfiguration = ViewConfiguration.get(getContext());
|
||||
init();
|
||||
}
|
||||
|
||||
public void setSwipeDirection(int swipeDirection) {
|
||||
mSwipeDirection = swipeDirection;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
mGestureListener = new SimpleOnGestureListener() {
|
||||
@Override
|
||||
public boolean onDown(MotionEvent e) {
|
||||
isFling = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFling(MotionEvent e1, MotionEvent e2,
|
||||
float velocityX, float velocityY) {
|
||||
|
||||
if (velocityX > mViewConfiguration.getScaledMinimumFlingVelocity() || velocityY > mViewConfiguration.getScaledMinimumFlingVelocity())
|
||||
isFling = true;
|
||||
return isFling;
|
||||
}
|
||||
};
|
||||
mGestureDetector = new GestureDetectorCompat(getContext(),
|
||||
mGestureListener);
|
||||
|
||||
mCloseScroller = ScrollerCompat.create(getContext());
|
||||
mOpenScroller = ScrollerCompat.create(getContext());
|
||||
}
|
||||
|
||||
public void setCloseInterpolator(Interpolator closeInterpolator) {
|
||||
mCloseInterpolator = closeInterpolator;
|
||||
if (mCloseInterpolator != null) {
|
||||
mCloseScroller = ScrollerCompat.create(getContext(),
|
||||
mCloseInterpolator);
|
||||
}
|
||||
}
|
||||
|
||||
public void setOpenInterpolator(Interpolator openInterpolator) {
|
||||
mOpenInterpolator = openInterpolator;
|
||||
if (mOpenInterpolator != null) {
|
||||
mOpenScroller = ScrollerCompat.create(getContext(),
|
||||
mOpenInterpolator);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onSwipe(MotionEvent event) {
|
||||
mGestureDetector.onTouchEvent(event);
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mDownX = (int) event.getX();
|
||||
isFling = false;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
int dis = (int) (mDownX - event.getX());
|
||||
if (state == STATE_OPEN) {
|
||||
dis += mMenuView.getWidth() * mSwipeDirection;
|
||||
}
|
||||
swipe(dis);
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
if ((isFling || Math.abs(mDownX - event.getX()) > (mMenuView.getWidth() / 3)) &&
|
||||
Math.signum(mDownX - event.getX()) == mSwipeDirection) {
|
||||
smoothOpenMenu();
|
||||
} else {
|
||||
smoothCloseMenu();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return state == STATE_OPEN;
|
||||
}
|
||||
|
||||
private void swipe(int dis) {
|
||||
if (Math.signum(dis) != mSwipeDirection) {
|
||||
dis = 0;
|
||||
} else if (Math.abs(dis) > mMenuView.getWidth()) {
|
||||
dis = mMenuView.getWidth() * mSwipeDirection;
|
||||
state = STATE_OPEN;
|
||||
}
|
||||
|
||||
LayoutParams lp = (LayoutParams) mContentView.getLayoutParams();
|
||||
int lGap = getPaddingLeft() + lp.leftMargin;
|
||||
mContentView.layout(lGap - dis,
|
||||
mContentView.getTop(),
|
||||
lGap + (OVER_API_11 ? mContentView.getMeasuredWidthAndState() : mContentView.getMeasuredWidth()) - dis,
|
||||
mContentView.getBottom());
|
||||
|
||||
if (mSwipeDirection == SuperSwipeMenuRecyclerView.DIRECTION_LEFT) {
|
||||
mMenuView.layout(getMeasuredWidth() - dis, mMenuView.getTop(),
|
||||
getMeasuredWidth() + (OVER_API_11 ? mMenuView.getMeasuredWidthAndState() : mMenuView.getMeasuredWidth()) - dis,
|
||||
mMenuView.getBottom());
|
||||
} else {
|
||||
mMenuView.layout(-(OVER_API_11 ? mMenuView.getMeasuredWidthAndState() : mMenuView.getMeasuredWidth()) - dis, mMenuView.getTop(),
|
||||
-dis, mMenuView.getBottom());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computeScroll() {
|
||||
if (state == STATE_OPEN) {
|
||||
if (mOpenScroller.computeScrollOffset()) {
|
||||
swipe(mOpenScroller.getCurrX() * mSwipeDirection);
|
||||
postInvalidate();
|
||||
}
|
||||
} else {
|
||||
if (mCloseScroller.computeScrollOffset()) {
|
||||
swipe((mBaseX - mCloseScroller.getCurrX()) * mSwipeDirection);
|
||||
postInvalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void smoothCloseMenu() {
|
||||
closeOpenedMenu();
|
||||
}
|
||||
|
||||
public void closeOpenedMenu() {
|
||||
state = STATE_CLOSE;
|
||||
if (mSwipeDirection == SuperSwipeMenuRecyclerView.DIRECTION_LEFT) {
|
||||
mBaseX = -mContentView.getLeft();
|
||||
mCloseScroller.startScroll(0, 0, mMenuView.getWidth(), 0, animDuration);
|
||||
} else {
|
||||
mBaseX = mMenuView.getRight();
|
||||
mCloseScroller.startScroll(0, 0, mMenuView.getWidth(), 0, animDuration);
|
||||
}
|
||||
postInvalidate();
|
||||
}
|
||||
|
||||
public void smoothOpenMenu() {
|
||||
state = STATE_OPEN;
|
||||
if (mSwipeDirection == SuperSwipeMenuRecyclerView.DIRECTION_LEFT) {
|
||||
mOpenScroller.startScroll(-mContentView.getLeft(), 0, mMenuView.getWidth(), 0, animDuration);
|
||||
} else {
|
||||
mOpenScroller.startScroll(mContentView.getLeft(), 0, mMenuView.getWidth(), 0, animDuration);
|
||||
}
|
||||
postInvalidate();
|
||||
}
|
||||
|
||||
public void closeMenu() {
|
||||
if (mCloseScroller.computeScrollOffset()) {
|
||||
mCloseScroller.abortAnimation();
|
||||
}
|
||||
if (state == STATE_OPEN) {
|
||||
state = STATE_CLOSE;
|
||||
swipe(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void openMenu() {
|
||||
if (state == STATE_CLOSE) {
|
||||
state = STATE_OPEN;
|
||||
swipe(mMenuView.getWidth() * mSwipeDirection);
|
||||
}
|
||||
}
|
||||
|
||||
public View getMenuView() {
|
||||
return mMenuView;
|
||||
}
|
||||
|
||||
public View getContentView() {
|
||||
return mContentView;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
FrameLayout.LayoutParams lp = (LayoutParams) mContentView.getLayoutParams();
|
||||
int lGap = getPaddingLeft() + lp.leftMargin;
|
||||
int tGap = getPaddingTop() + lp.topMargin;
|
||||
mContentView.layout(lGap,
|
||||
tGap,
|
||||
lGap + (OVER_API_11 ? mContentView.getMeasuredWidthAndState() : mContentView.getMeasuredWidth()),
|
||||
tGap + (OVER_API_11 ? mContentView.getMeasuredHeightAndState() : mContentView.getMeasuredHeight()));
|
||||
|
||||
|
||||
lp = (LayoutParams) mMenuView.getLayoutParams();
|
||||
tGap = getPaddingTop() + lp.topMargin;
|
||||
if (mSwipeDirection == SuperSwipeMenuRecyclerView.DIRECTION_LEFT) {
|
||||
mMenuView.layout(getMeasuredWidth(), tGap,
|
||||
getMeasuredWidth() + (OVER_API_11 ? mMenuView.getMeasuredWidthAndState() : mMenuView.getMeasuredWidth()),
|
||||
tGap + mMenuView.getMeasuredHeightAndState());
|
||||
} else {
|
||||
mMenuView.layout(-(OVER_API_11 ? mMenuView.getMeasuredWidthAndState() : mMenuView.getMeasuredWidth()), tGap,
|
||||
0, tGap + mMenuView.getMeasuredHeightAndState());
|
||||
}
|
||||
}
|
||||
|
||||
public void setSwipeEnable(boolean swipeEnable) {
|
||||
this.swipeEnable = swipeEnable;
|
||||
}
|
||||
|
||||
public boolean isSwipeEnable() {
|
||||
return swipeEnable;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,257 @@
|
||||
package com.superrecycleview.superlibrary.recycleview.swipemenu;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.core.view.MotionEventCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.superrecycleview.superlibrary.recycleview.SuperRecyclerView;
|
||||
/**
|
||||
* Created by super南仔 on 07/28/16.
|
||||
* blog: http://supercwn.github.io/
|
||||
* GitHub: https://github.com/supercwn
|
||||
*/
|
||||
public class SuperSwipeMenuRecyclerView extends SuperRecyclerView {
|
||||
|
||||
public static final int TOUCH_STATE_NONE = 0;
|
||||
public static final int TOUCH_STATE_X = 1;
|
||||
public static final int TOUCH_STATE_Y = 2;
|
||||
|
||||
public static final int DIRECTION_LEFT = 1;
|
||||
public static final int DIRECTION_RIGHT = -1;
|
||||
protected int mDirection = DIRECTION_LEFT; // swipe from right to left by default
|
||||
|
||||
protected float mDownX;
|
||||
protected float mDownY;
|
||||
protected int mTouchState;
|
||||
protected int mTouchPosition;
|
||||
protected SuperSwipeMenuLayout mTouchView;
|
||||
protected OnSwipeListener mOnSwipeListener;
|
||||
|
||||
protected Interpolator mCloseInterpolator;
|
||||
protected Interpolator mOpenInterpolator;
|
||||
|
||||
protected LayoutManager mLlm;
|
||||
protected ViewConfiguration mViewConfiguration;
|
||||
protected long startClickTime;
|
||||
protected float dx;
|
||||
protected float dy;
|
||||
|
||||
public SuperSwipeMenuRecyclerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public SuperSwipeMenuRecyclerView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public SuperSwipeMenuRecyclerView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
mTouchState = TOUCH_STATE_NONE;
|
||||
mViewConfiguration = ViewConfiguration.get(getContext());
|
||||
}
|
||||
|
||||
public void setCloseInterpolator(Interpolator interpolator) {
|
||||
mCloseInterpolator = interpolator;
|
||||
}
|
||||
|
||||
public void setOpenInterpolator(Interpolator interpolator) {
|
||||
mOpenInterpolator = interpolator;
|
||||
}
|
||||
|
||||
public Interpolator getOpenInterpolator() {
|
||||
return mOpenInterpolator;
|
||||
}
|
||||
|
||||
public Interpolator getCloseInterpolator() {
|
||||
return mCloseInterpolator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
|
||||
if (ev.getAction() != MotionEvent.ACTION_DOWN && mTouchView == null){
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
int action = ev.getAction();
|
||||
switch (action & MotionEventCompat.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
dx = 0.0f; // reset
|
||||
dy = 0.0f; // reset
|
||||
startClickTime = System.currentTimeMillis(); // reset
|
||||
int oldPos = mTouchPosition;
|
||||
mDownX = ev.getX();
|
||||
mDownY = ev.getY();
|
||||
mTouchState = TOUCH_STATE_NONE;
|
||||
mTouchPosition = getChildAdapterPosition(findChildViewUnder((int) ev.getX(), (int) ev.getY()));
|
||||
if (mTouchPosition == oldPos && mTouchView != null
|
||||
&& mTouchView.isOpen()) {
|
||||
mTouchState = TOUCH_STATE_X;
|
||||
mTouchView.onSwipe(ev);
|
||||
}
|
||||
// find the touched child view
|
||||
View view = null;
|
||||
ViewHolder vh = findViewHolderForAdapterPosition(mTouchPosition);
|
||||
if(vh != null){
|
||||
view = vh.itemView;
|
||||
}
|
||||
// is not touched the opened menu view, so we intercept this touch event
|
||||
if (mTouchPosition != oldPos && mTouchView != null && mTouchView.isOpen()) {
|
||||
mTouchView.smoothCloseMenu();
|
||||
mTouchView = null;
|
||||
// try to cancel the touch event
|
||||
MotionEvent cancelEvent = MotionEvent.obtain(ev);
|
||||
cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
|
||||
super.onTouchEvent(cancelEvent);
|
||||
return true;
|
||||
}
|
||||
if (view instanceof SuperSwipeMenuLayout) {
|
||||
mTouchView = (SuperSwipeMenuLayout) view;
|
||||
mTouchView.setSwipeDirection(mDirection);
|
||||
}
|
||||
if (mTouchView != null) {
|
||||
mTouchView.onSwipe(ev);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
dy = Math.abs((ev.getY() - mDownY));
|
||||
dx = Math.abs((ev.getX() - mDownX));
|
||||
if (mTouchState == TOUCH_STATE_X && mTouchView.isSwipeEnable()) {
|
||||
mTouchView.onSwipe(ev);
|
||||
ev.setAction(MotionEvent.ACTION_CANCEL);
|
||||
super.onTouchEvent(ev);
|
||||
} else if (mTouchState == TOUCH_STATE_NONE && mTouchView.isSwipeEnable()) {
|
||||
if (Math.abs(dy) > mViewConfiguration.getScaledTouchSlop()) {
|
||||
mTouchState = TOUCH_STATE_Y;
|
||||
} else if (dx > mViewConfiguration.getScaledTouchSlop()) {
|
||||
mTouchState = TOUCH_STATE_X;
|
||||
if (mOnSwipeListener != null) {
|
||||
mOnSwipeListener.onSwipeStart(mTouchPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
boolean isCloseOnUpEvent = false;
|
||||
if (mTouchState == TOUCH_STATE_X && mTouchView.isSwipeEnable()) {
|
||||
isCloseOnUpEvent = !mTouchView.onSwipe(ev);
|
||||
if (mOnSwipeListener != null) {
|
||||
mOnSwipeListener.onSwipeEnd(mTouchPosition);
|
||||
}
|
||||
if (!mTouchView.isOpen()) {
|
||||
mTouchPosition = -1;
|
||||
mTouchView = null;
|
||||
}
|
||||
ev.setAction(MotionEvent.ACTION_CANCEL);
|
||||
super.onTouchEvent(ev);
|
||||
}
|
||||
long clickDuration = System.currentTimeMillis() - startClickTime;
|
||||
boolean isOutDuration = clickDuration > ViewConfiguration.getLongPressTimeout();
|
||||
boolean isOutX = dx > mViewConfiguration.getScaledTouchSlop();
|
||||
boolean isOutY = dy > mViewConfiguration.getScaledTouchSlop();
|
||||
// long pressed or scaled touch, we just intercept up touch event
|
||||
if(isOutDuration || isOutX || isOutY){
|
||||
return true;
|
||||
}else{
|
||||
float eX = ev.getX();
|
||||
float eY = ev.getY();
|
||||
View upView = findChildViewUnder(eX, eY);
|
||||
if(upView instanceof SuperSwipeMenuLayout){
|
||||
SuperSwipeMenuLayout smView = (SuperSwipeMenuLayout)upView;
|
||||
int x = (int)eX - smView.getLeft();
|
||||
int y = (int)eY - smView.getTop();
|
||||
View menuView = smView.getMenuView();
|
||||
final float translationX = ViewCompat.getTranslationX(menuView);
|
||||
final float translationY = ViewCompat.getTranslationY(menuView);
|
||||
// intercept the up event when touched on the contentView of the opened SwipeMenuLayout
|
||||
if (!(x >= menuView.getLeft() + translationX &&
|
||||
x <= menuView.getRight() + translationX &&
|
||||
y >= menuView.getTop() + translationY &&
|
||||
y <= menuView.getBottom() + translationY) &&
|
||||
isCloseOnUpEvent) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if(mTouchView != null && mTouchView.isSwipeEnable()){
|
||||
// when event has canceled, we just consider as up event
|
||||
ev.setAction(MotionEvent.ACTION_UP);
|
||||
mTouchView.onSwipe(ev);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* open menu manually
|
||||
* @param position the adapter position
|
||||
*/
|
||||
public void smoothOpenMenu(int position) {
|
||||
View view = mLlm.findViewByPosition(position);
|
||||
if (view instanceof SuperSwipeMenuLayout) {
|
||||
mTouchPosition = position;
|
||||
// close pre opened swipe menu
|
||||
if (mTouchView != null && mTouchView.isOpen()) {
|
||||
mTouchView.smoothCloseMenu();
|
||||
}
|
||||
mTouchView = (SuperSwipeMenuLayout) view;
|
||||
mTouchView.setSwipeDirection(mDirection);
|
||||
mTouchView.smoothOpenMenu();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* close the opened menu manually
|
||||
*/
|
||||
public void smoothCloseMenu() {
|
||||
// close the opened swipe menu
|
||||
if (mTouchView != null && mTouchView.isOpen()) {
|
||||
mTouchView.smoothCloseMenu();
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnSwipeListener(OnSwipeListener onSwipeListener) {
|
||||
this.mOnSwipeListener = onSwipeListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* get current touched view
|
||||
* @return touched view, maybe null
|
||||
*/
|
||||
public SuperSwipeMenuLayout getTouchView() {
|
||||
return mTouchView;
|
||||
}
|
||||
|
||||
public interface OnSwipeListener {
|
||||
void onSwipeStart(int position);
|
||||
void onSwipeEnd(int position);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the swipe direction
|
||||
* @param direction swipe direction (left or right)
|
||||
*/
|
||||
public void setSwipeDirection(int direction) {
|
||||
mDirection = direction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayoutManager(LayoutManager layout) {
|
||||
super.setLayoutManager(layout);
|
||||
mLlm = layout;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,266 @@
|
||||
|
||||
package com.superrecycleview.superlibrary.recycleview.swipemenu;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.core.view.MotionEventCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
/**
|
||||
* Created by super南仔 on 07/28/16. blog: http://supercwn.github.io/ GitHub:
|
||||
* https://github.com/supercwn 该类用于slide,不能使用SuperRecycle的侧滑
|
||||
*/
|
||||
public class SwipeMenuRecyclerView extends RecyclerView {
|
||||
|
||||
public static final int TOUCH_STATE_NONE = 0;
|
||||
public static final int TOUCH_STATE_X = 1;
|
||||
public static final int TOUCH_STATE_Y = 2;
|
||||
|
||||
public static final int DIRECTION_LEFT = 1;
|
||||
public static final int DIRECTION_RIGHT = -1;
|
||||
protected int mDirection = DIRECTION_LEFT; // swipe from right to left by
|
||||
// default
|
||||
|
||||
protected float mDownX;
|
||||
protected float mDownY;
|
||||
protected int mTouchState;
|
||||
protected int mTouchPosition;
|
||||
protected SuperSwipeMenuLayout mTouchView;
|
||||
protected OnSwipeListener mOnSwipeListener;
|
||||
|
||||
protected Interpolator mCloseInterpolator;
|
||||
protected Interpolator mOpenInterpolator;
|
||||
|
||||
protected LayoutManager mLlm;
|
||||
protected ViewConfiguration mViewConfiguration;
|
||||
protected long startClickTime;
|
||||
protected float dx;
|
||||
protected float dy;
|
||||
|
||||
public SwipeMenuRecyclerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public SwipeMenuRecyclerView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public SwipeMenuRecyclerView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
mTouchState = TOUCH_STATE_NONE;
|
||||
mViewConfiguration = ViewConfiguration.get(getContext());
|
||||
}
|
||||
|
||||
public void setCloseInterpolator(Interpolator interpolator) {
|
||||
mCloseInterpolator = interpolator;
|
||||
}
|
||||
|
||||
public void setOpenInterpolator(Interpolator interpolator) {
|
||||
mOpenInterpolator = interpolator;
|
||||
}
|
||||
|
||||
public Interpolator getOpenInterpolator() {
|
||||
return mOpenInterpolator;
|
||||
}
|
||||
|
||||
public Interpolator getCloseInterpolator() {
|
||||
return mCloseInterpolator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
|
||||
if (ev.getAction() != MotionEvent.ACTION_DOWN && mTouchView == null) {
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
int action = ev.getAction();
|
||||
switch (action & MotionEventCompat.ACTION_MASK) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
dx = 0.0f; // reset
|
||||
dy = 0.0f; // reset
|
||||
startClickTime = System.currentTimeMillis(); // reset
|
||||
int oldPos = mTouchPosition;
|
||||
mDownX = ev.getX();
|
||||
mDownY = ev.getY();
|
||||
mTouchState = TOUCH_STATE_NONE;
|
||||
mTouchPosition = getChildAdapterPosition(
|
||||
findChildViewUnder((int) ev.getX(), (int) ev.getY()));
|
||||
if (mTouchPosition == oldPos && mTouchView != null
|
||||
&& mTouchView.isOpen()) {
|
||||
mTouchState = TOUCH_STATE_X;
|
||||
mTouchView.onSwipe(ev);
|
||||
}
|
||||
// find the touched child view
|
||||
View view = null;
|
||||
ViewHolder vh = findViewHolderForAdapterPosition(mTouchPosition);
|
||||
if (vh != null) {
|
||||
view = vh.itemView;
|
||||
}
|
||||
// is not touched the opened menu view, so we intercept this
|
||||
// touch event
|
||||
if (mTouchPosition != oldPos && mTouchView != null && mTouchView.isOpen()) {
|
||||
mTouchView.smoothCloseMenu();
|
||||
mTouchView = null;
|
||||
// try to cancel the touch event
|
||||
MotionEvent cancelEvent = MotionEvent.obtain(ev);
|
||||
cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
|
||||
super.onTouchEvent(cancelEvent);
|
||||
return true;
|
||||
}
|
||||
if (view instanceof SuperSwipeMenuLayout) {
|
||||
mTouchView = (SuperSwipeMenuLayout) view;
|
||||
mTouchView.setSwipeDirection(mDirection);
|
||||
}
|
||||
if (mTouchView != null) {
|
||||
mTouchView.onSwipe(ev);
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
dy = Math.abs((ev.getY() - mDownY));
|
||||
dx = Math.abs((ev.getX() - mDownX));
|
||||
if (mTouchState == TOUCH_STATE_X && mTouchView.isSwipeEnable()) {
|
||||
mTouchView.onSwipe(ev);
|
||||
ev.setAction(MotionEvent.ACTION_CANCEL);
|
||||
super.onTouchEvent(ev);
|
||||
} else if (mTouchState == TOUCH_STATE_NONE && mTouchView.isSwipeEnable()) {
|
||||
if (Math.abs(dy) > mViewConfiguration.getScaledTouchSlop()) {
|
||||
mTouchState = TOUCH_STATE_Y;
|
||||
} else if (dx > mViewConfiguration.getScaledTouchSlop()) {
|
||||
mTouchState = TOUCH_STATE_X;
|
||||
if (mOnSwipeListener != null) {
|
||||
mOnSwipeListener.onSwipeStart(mTouchPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
boolean isCloseOnUpEvent = false;
|
||||
if (mTouchState == TOUCH_STATE_X && mTouchView.isSwipeEnable()) {
|
||||
isCloseOnUpEvent = !mTouchView.onSwipe(ev);
|
||||
if (mOnSwipeListener != null) {
|
||||
mOnSwipeListener.onSwipeEnd(mTouchPosition);
|
||||
}
|
||||
if (!mTouchView.isOpen()) {
|
||||
mTouchPosition = -1;
|
||||
mTouchView = null;
|
||||
}
|
||||
ev.setAction(MotionEvent.ACTION_CANCEL);
|
||||
super.onTouchEvent(ev);
|
||||
}
|
||||
long clickDuration = System.currentTimeMillis() - startClickTime;
|
||||
boolean isOutDuration = clickDuration > ViewConfiguration.getLongPressTimeout();
|
||||
boolean isOutX = dx > mViewConfiguration.getScaledTouchSlop();
|
||||
boolean isOutY = dy > mViewConfiguration.getScaledTouchSlop();
|
||||
// long pressed or scaled touch, we just intercept up touch
|
||||
// event
|
||||
if (isOutDuration || isOutX || isOutY) {
|
||||
return true;
|
||||
} else {
|
||||
float eX = ev.getX();
|
||||
float eY = ev.getY();
|
||||
View upView = findChildViewUnder(eX, eY);
|
||||
if (upView instanceof SuperSwipeMenuLayout) {
|
||||
SuperSwipeMenuLayout smView = (SuperSwipeMenuLayout) upView;
|
||||
int x = (int) eX - smView.getLeft();
|
||||
int y = (int) eY - smView.getTop();
|
||||
View menuView = smView.getMenuView();
|
||||
final float translationX = ViewCompat.getTranslationX(menuView);
|
||||
final float translationY = ViewCompat.getTranslationY(menuView);
|
||||
// intercept the up event when touched on the
|
||||
// contentView of the opened SwipeMenuLayout
|
||||
if (!(x >= menuView.getLeft() + translationX &&
|
||||
x <= menuView.getRight() + translationX &&
|
||||
y >= menuView.getTop() + translationY &&
|
||||
y <= menuView.getBottom() + translationY) &&
|
||||
isCloseOnUpEvent) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (mTouchView != null && mTouchView.isSwipeEnable()) {
|
||||
// when event has canceled, we just consider as up event
|
||||
ev.setAction(MotionEvent.ACTION_UP);
|
||||
mTouchView.onSwipe(ev);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* open menu manually
|
||||
*
|
||||
* @param position the adapter position
|
||||
*/
|
||||
public void smoothOpenMenu(int position) {
|
||||
View view = mLlm.findViewByPosition(position);
|
||||
if (view instanceof SuperSwipeMenuLayout) {
|
||||
mTouchPosition = position;
|
||||
// close pre opened swipe menu
|
||||
if (mTouchView != null && mTouchView.isOpen()) {
|
||||
mTouchView.smoothCloseMenu();
|
||||
}
|
||||
mTouchView = (SuperSwipeMenuLayout) view;
|
||||
mTouchView.setSwipeDirection(mDirection);
|
||||
mTouchView.smoothOpenMenu();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* close the opened menu manually
|
||||
*/
|
||||
public void smoothCloseMenu() {
|
||||
// close the opened swipe menu
|
||||
if (mTouchView != null && mTouchView.isOpen()) {
|
||||
mTouchView.smoothCloseMenu();
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnSwipeListener(OnSwipeListener onSwipeListener) {
|
||||
this.mOnSwipeListener = onSwipeListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* get current touched view
|
||||
*
|
||||
* @return touched view, maybe null
|
||||
*/
|
||||
public SuperSwipeMenuLayout getTouchView() {
|
||||
return mTouchView;
|
||||
}
|
||||
|
||||
public interface OnSwipeListener {
|
||||
void onSwipeStart(int position);
|
||||
|
||||
void onSwipeEnd(int position);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the swipe direction
|
||||
*
|
||||
* @param direction swipe direction (left or right)
|
||||
*/
|
||||
public void setSwipeDirection(int direction) {
|
||||
mDirection = direction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayoutManager(LayoutManager layout) {
|
||||
super.setLayoutManager(layout);
|
||||
mLlm = layout;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
|
||||
package com.superrecycleview.superlibrary.sidebar.bean;
|
||||
|
||||
import com.superrecycleview.superlibrary.callback.ISuspensionInterface;
|
||||
|
||||
/**
|
||||
* 介绍:索引类的标志位的实体基类 作者:zhangxutong 邮箱:mcxtzhang@163.com
|
||||
* CSDN:http://blog.csdn.net/zxt0601 时间: 16/09/04.
|
||||
*/
|
||||
|
||||
public abstract class BaseIndexBean implements ISuspensionInterface {
|
||||
private String baseIndexTag;// 所属的分类(城市的汉语拼音首字母)
|
||||
|
||||
public String getBaseIndexTag() {
|
||||
return baseIndexTag;
|
||||
}
|
||||
|
||||
public BaseIndexBean setBaseIndexTag(String baseIndexTag) {
|
||||
this.baseIndexTag = baseIndexTag;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSuspensionTag() {
|
||||
return baseIndexTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowSuspension() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
|
||||
package com.superrecycleview.superlibrary.sidebar.bean;
|
||||
|
||||
/**
|
||||
* 介绍:索引类的汉语拼音的接口 作者:zhangxutong 邮箱:mcxtzhang@163.com
|
||||
* CSDN:http://blog.csdn.net/zxt0601 时间: 16/09/04.
|
||||
*/
|
||||
|
||||
public abstract class BaseIndexPinyinBean extends BaseIndexBean {
|
||||
private String baseIndexPinyin;// 城市的拼音
|
||||
|
||||
public String getBaseIndexPinyin() {
|
||||
return baseIndexPinyin;
|
||||
}
|
||||
|
||||
public BaseIndexPinyinBean setBaseIndexPinyin(String baseIndexPinyin) {
|
||||
this.baseIndexPinyin = baseIndexPinyin;
|
||||
return this;
|
||||
}
|
||||
|
||||
// 是否需要被转化成拼音, 类似微信头部那种就不需要 美团的也不需要
|
||||
// 微信的头部 不需要显示索引
|
||||
// 美团的头部 索引自定义
|
||||
// 默认应该是需要的
|
||||
public boolean isNeedToPinyin() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 需要转化成拼音的目标字段
|
||||
public abstract String getTarget();
|
||||
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
|
||||
package com.superrecycleview.superlibrary.sidebar.helper;
|
||||
|
||||
import com.superrecycleview.superlibrary.sidebar.bean.BaseIndexPinyinBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 介绍:IndexBar 的 数据相关帮助类 1 将汉语转成拼音 2 填充indexTag 3 排序源数据源 4
|
||||
* 根据排序后的源数据源->indexBar的数据源 作者:zhangxutong 邮箱:mcxtzhang@163.com
|
||||
* 主页:http://blog.csdn.net/zxt0601 时间: 2016/11/28.
|
||||
*/
|
||||
|
||||
public interface IIndexBarDataHelper {
|
||||
// 汉语-》拼音
|
||||
IIndexBarDataHelper convert(List<? extends BaseIndexPinyinBean> data);
|
||||
|
||||
// 拼音->tag
|
||||
IIndexBarDataHelper fillInexTag(List<? extends BaseIndexPinyinBean> data);
|
||||
|
||||
// 对源数据进行排序(RecyclerView)
|
||||
IIndexBarDataHelper sortSourceDatas(List<? extends BaseIndexPinyinBean> datas);
|
||||
|
||||
// 对IndexBar的数据源进行排序(右侧栏),在 sortSourceDatas 方法后调用
|
||||
IIndexBarDataHelper getSortedIndexDatas(List<? extends BaseIndexPinyinBean> sourceDatas,
|
||||
List<String> datas);
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
|
||||
package com.superrecycleview.superlibrary.sidebar.helper;
|
||||
|
||||
|
||||
import com.github.promeg.pinyinhelper.Pinyin;
|
||||
import com.superrecycleview.superlibrary.sidebar.bean.BaseIndexPinyinBean;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 介绍:IndexBar 的 数据相关帮助类 实现 * 1 将汉语转成拼音(利用tinyPinyin) 2 填充indexTag (取拼音首字母) 3
|
||||
* 排序源数据源 4 根据排序后的源数据源->indexBar的数据源 作者:zhangxutong 邮箱:mcxtzhang@163.com
|
||||
* 主页:http://blog.csdn.net/zxt0601 时间: 2016/11/28.
|
||||
*/
|
||||
|
||||
public class IndexBarDataHelperImpl implements IIndexBarDataHelper {
|
||||
/**
|
||||
* 如果需要, 字符->拼音,
|
||||
*
|
||||
* @param datas
|
||||
*/
|
||||
@Override
|
||||
public IIndexBarDataHelper convert(List<? extends BaseIndexPinyinBean> datas) {
|
||||
if (null == datas || datas.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
int size = datas.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
BaseIndexPinyinBean indexPinyinBean = datas.get(i);
|
||||
StringBuilder pySb = new StringBuilder();
|
||||
// add by zhangxutong 2016 11 10 如果不是top 才转拼音,否则不用转了
|
||||
if (indexPinyinBean.isNeedToPinyin()) {
|
||||
String target = indexPinyinBean.getTarget();// 取出需要被拼音化的字段
|
||||
// 遍历target的每个char得到它的全拼音
|
||||
for (int i1 = 0; i1 < target.length(); i1++) {
|
||||
// 利用TinyPinyin将char转成拼音
|
||||
// 查看源码,方法内 如果char为汉字,则返回大写拼音
|
||||
// 如果c不是汉字,则返回String.valueOf(c)
|
||||
pySb.append(Pinyin.toPinyin(target.charAt(i1)).toUpperCase());
|
||||
}
|
||||
indexPinyinBean.setBaseIndexPinyin(pySb.toString());// 设置城市名全拼音
|
||||
} else {
|
||||
// pySb.append(indexPinyinBean.getBaseIndexPinyin());
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果需要取出,则 取出首字母->tag,或者特殊字母 "#". 否则,用户已经实现设置好
|
||||
*
|
||||
* @param datas
|
||||
*/
|
||||
@Override
|
||||
public IIndexBarDataHelper fillInexTag(List<? extends BaseIndexPinyinBean> datas) {
|
||||
if (null == datas || datas.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
int size = datas.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
BaseIndexPinyinBean indexPinyinBean = datas.get(i);
|
||||
if (indexPinyinBean.isNeedToPinyin()) {
|
||||
// 以下代码设置城市拼音首字母
|
||||
String tagString = indexPinyinBean.getBaseIndexPinyin().toString().substring(0, 1);
|
||||
if (tagString.matches("[A-Z]")) {// 如果是A-Z字母开头
|
||||
indexPinyinBean.setBaseIndexTag(tagString);
|
||||
} else {// 特殊字母这里统一用#处理
|
||||
indexPinyinBean.setBaseIndexTag("#");
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIndexBarDataHelper sortSourceDatas(List<? extends BaseIndexPinyinBean> datas) {
|
||||
if (null == datas || datas.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
convert(datas);
|
||||
fillInexTag(datas);
|
||||
// 对数据源进行排序
|
||||
Collections.sort(datas, new Comparator<BaseIndexPinyinBean>() {
|
||||
@Override
|
||||
public int compare(BaseIndexPinyinBean lhs, BaseIndexPinyinBean rhs) {
|
||||
if (!lhs.isNeedToPinyin()) {
|
||||
return 0;
|
||||
} else if (!rhs.isNeedToPinyin()) {
|
||||
return 0;
|
||||
} else if (lhs.getBaseIndexTag().equals("#")) {
|
||||
return 1;
|
||||
} else if (rhs.getBaseIndexTag().equals("#")) {
|
||||
return -1;
|
||||
} else {
|
||||
return lhs.getBaseIndexPinyin().compareTo(rhs.getBaseIndexPinyin());
|
||||
}
|
||||
}
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIndexBarDataHelper getSortedIndexDatas(List<? extends BaseIndexPinyinBean> sourceDatas,
|
||||
List<String> indexDatas) {
|
||||
if (null == sourceDatas || sourceDatas.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
// 按数据源来 此时sourceDatas 已经有序
|
||||
int size = sourceDatas.size();
|
||||
String baseIndexTag;
|
||||
for (int i = 0; i < size; i++) {
|
||||
baseIndexTag = sourceDatas.get(i).getBaseIndexTag();
|
||||
if (!indexDatas.contains(baseIndexTag)) {// 则判断是否已经将这个索引添加进去,若没有则添加
|
||||
indexDatas.add(baseIndexTag);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,393 @@
|
||||
|
||||
package com.superrecycleview.superlibrary.sidebar.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Typeface;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.superrecycleview.superlibrary.R;
|
||||
import com.superrecycleview.superlibrary.sidebar.bean.BaseIndexPinyinBean;
|
||||
import com.superrecycleview.superlibrary.sidebar.helper.IIndexBarDataHelper;
|
||||
import com.superrecycleview.superlibrary.sidebar.helper.IndexBarDataHelperImpl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 介绍:索引右侧边栏 作者:zhangxutong 邮箱:mcxtzhang@163.com
|
||||
* CSDN:http://blog.csdn.net/zxt0601 时间: 16/09/04.
|
||||
*/
|
||||
|
||||
public class SuperSideBar extends View {
|
||||
private static final String TAG = "zxt/IndexBar";
|
||||
|
||||
// #在最后面(默认的数据源)
|
||||
public static String[] INDEX_STRING = {
|
||||
"A", "B", "C", "D", "E", "F", "G", "H", "I",
|
||||
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
|
||||
"W", "X", "Y", "Z", "#"
|
||||
};
|
||||
// 是否需要根据实际的数据来生成索引数据源(例如 只有 A B C 三种tag,那么索引栏就 A B C 三项)
|
||||
private boolean isNeedRealIndex;
|
||||
// 索引数据源
|
||||
private List<String> mIndexDatas;
|
||||
// 每个index区域的高度
|
||||
private int mGapHeight;
|
||||
private Paint mPaint;
|
||||
private int offsetY;
|
||||
|
||||
/**
|
||||
* sideBar的字母size
|
||||
*/
|
||||
private int sideBarTextSize;
|
||||
/**
|
||||
* sideBar的背景颜色
|
||||
*/
|
||||
private int sideBarBg = android.R.color.transparent;
|
||||
/**
|
||||
* 按下的是显示的背景色
|
||||
*/
|
||||
private int sideBarPressBg = android.R.color.transparent;
|
||||
/**
|
||||
* indexBar的字母颜色
|
||||
*/
|
||||
private int sideBarTextColor = android.R.color.darker_gray;
|
||||
/**
|
||||
* indexBar选中的字母颜色
|
||||
*/
|
||||
private int sideBarTextColorPress = android.R.color.holo_blue_dark;
|
||||
/**
|
||||
* 该字母是否选中
|
||||
*/
|
||||
private int choose = -1;// 选中
|
||||
|
||||
// 以下是帮助类
|
||||
// 汉语->拼音,拼音->tag
|
||||
private IIndexBarDataHelper mDataHelper;
|
||||
|
||||
// 以下边变量是外部set进来的
|
||||
private TextView mPressedShowTextView;// 用于特写显示正在被触摸的index值
|
||||
private boolean isSourceDatasAlreadySorted;// 源数据 已经有序?
|
||||
private List<? extends BaseIndexPinyinBean> mSourceDatas;// Adapter的数据源
|
||||
private LinearLayoutManager mLayoutManager;
|
||||
private int mHeaderViewCount = 0;
|
||||
|
||||
public SuperSideBar(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public SuperSideBar(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public SuperSideBar(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public int getHeaderViewCount() {
|
||||
return mHeaderViewCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Headerview的Count
|
||||
*
|
||||
* @param headerViewCount
|
||||
* @return
|
||||
*/
|
||||
public SuperSideBar setHeaderViewCount(int headerViewCount) {
|
||||
mHeaderViewCount = headerViewCount;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isSourceDatasAlreadySorted() {
|
||||
return isSourceDatasAlreadySorted;
|
||||
}
|
||||
|
||||
/**
|
||||
* 源数据 是否已经有序
|
||||
*
|
||||
* @param sourceDatasAlreadySorted
|
||||
* @return
|
||||
*/
|
||||
public SuperSideBar setSourceDatasAlreadySorted(boolean sourceDatasAlreadySorted) {
|
||||
isSourceDatasAlreadySorted = sourceDatasAlreadySorted;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IIndexBarDataHelper getDataHelper() {
|
||||
return mDataHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置数据源帮助类
|
||||
*
|
||||
* @param dataHelper
|
||||
* @return
|
||||
*/
|
||||
public SuperSideBar setDataHelper(IIndexBarDataHelper dataHelper) {
|
||||
mDataHelper = dataHelper;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* @param context
|
||||
* @param attrs
|
||||
* @param defStyleAttr
|
||||
*/
|
||||
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
sideBarTextSize = (int) TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_SP, 12, getResources().getDisplayMetrics());// 默认的TextSize
|
||||
TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs,
|
||||
R.styleable.SuperSideBar, defStyleAttr, 0);
|
||||
int n = typedArray.getIndexCount();
|
||||
for (int i = 0; i < n; i++) {
|
||||
int attr = typedArray.getIndex(i);
|
||||
if (attr == R.styleable.SuperSideBar_super_sidebar_textsize) {
|
||||
sideBarTextSize = typedArray.getDimensionPixelSize(attr, sideBarTextSize);
|
||||
} else if (attr == R.styleable.SuperSideBar_super_sidebar_backgrond_press) {
|
||||
sideBarPressBg = typedArray.getColor(attr, sideBarPressBg);
|
||||
} else if (attr == R.styleable.SuperSideBar_super_sidebar_textcolor) {
|
||||
sideBarTextColor = typedArray.getColor(attr, sideBarTextColor);
|
||||
} else if (attr == R.styleable.SuperSideBar_super_sidebar_textcolor_press) {
|
||||
sideBarTextColorPress = typedArray.getColor(attr, sideBarTextColorPress);
|
||||
}
|
||||
}
|
||||
typedArray.recycle();
|
||||
initIndexDatas();
|
||||
mPaint = new Paint();
|
||||
mPaint.setAntiAlias(true);
|
||||
mPaint.setTextSize(sideBarTextSize);
|
||||
mPaint.setColor(Color.BLACK);
|
||||
|
||||
// 设置index触摸监听器
|
||||
setmOnIndexPressedListener(new onIndexPressedListener() {
|
||||
@Override
|
||||
public void onIndexPressed(int index, String text) {
|
||||
if (mPressedShowTextView != null) { // 显示hintTexView
|
||||
mPressedShowTextView.setVisibility(View.VISIBLE);
|
||||
mPressedShowTextView.setText(text);
|
||||
}
|
||||
// 滑动Rv
|
||||
if (mLayoutManager != null) {
|
||||
int position = getPosByTag(text);
|
||||
if (position != -1) {
|
||||
mLayoutManager.scrollToPositionWithOffset(position, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMotionEventEnd() {
|
||||
// 隐藏hintTextView
|
||||
if (mPressedShowTextView != null) {
|
||||
mPressedShowTextView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mDataHelper = new IndexBarDataHelperImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (mIndexDatas.isEmpty())
|
||||
return;
|
||||
int height = getHeight();// 获取对应的高度
|
||||
int width = getWidth();// 获取对应的宽度
|
||||
mGapHeight = height / mIndexDatas.size();// 获取每个字母的高度
|
||||
int dp24 = dip2px(24);
|
||||
mGapHeight = mGapHeight > dp24 ? dp24 : mGapHeight;
|
||||
offsetY = (height - mGapHeight * mIndexDatas.size()) / 2;
|
||||
for (int i = 0; i < mIndexDatas.size(); i++) {
|
||||
int colorId = i == choose ? android.R.color.holo_blue_bright
|
||||
: sideBarTextColor;
|
||||
mPaint.setColor(ContextCompat.getColor(getContext(), colorId));
|
||||
mPaint.setAntiAlias(true);
|
||||
mPaint.setTextSize(sideBarTextSize);
|
||||
mPaint.setTypeface(Typeface.DEFAULT);
|
||||
float xPos = width / 2 - mPaint.measureText(mIndexDatas.get(i)) / 2;
|
||||
float yPos = offsetY + mGapHeight * (i + 0.5F);
|
||||
if (i == choose) {
|
||||
// 选中的状态
|
||||
mPaint.setFakeBoldText(true);
|
||||
canvas.drawText(mIndexDatas.get(i), dip2px(-56), yPos, mPaint);
|
||||
}
|
||||
canvas.drawText(mIndexDatas.get(i), xPos, yPos, mPaint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchTouchEvent(MotionEvent event) {
|
||||
final int action = event.getAction();
|
||||
final float y = event.getY();// 点击y坐标
|
||||
final int oldChoose = choose;
|
||||
// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.
|
||||
final int c = (int) ((y - offsetY) / mGapHeight);
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
setBackgroundResource(sideBarPressBg);// 手指按下时背景变色
|
||||
// 注意这里没有break,因为down时,也要计算落点 回调监听器
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (oldChoose != c) {
|
||||
if (c >= 0 && c < mIndexDatas.size()) {
|
||||
choose = c;
|
||||
// 回调监听器
|
||||
if (null != mOnIndexPressedListener) {
|
||||
mOnIndexPressedListener.onIndexPressed(c, mIndexDatas.get(c));
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
default:
|
||||
choose = -1;
|
||||
setBackgroundResource(sideBarBg);
|
||||
if (null != mOnIndexPressedListener) {
|
||||
mOnIndexPressedListener.onMotionEventEnd();
|
||||
}
|
||||
invalidate();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int dip2px(float dpValue) {
|
||||
final float scale = Resources.getSystem().getDisplayMetrics().density;
|
||||
return (int) (dpValue * scale + 0.5f);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
if (null == mIndexDatas || mIndexDatas.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前被按下的index的监听器
|
||||
*/
|
||||
public interface onIndexPressedListener {
|
||||
void onIndexPressed(int index, String text);// 当某个Index被按下
|
||||
|
||||
void onMotionEventEnd();// 当触摸事件结束(UP CANCEL)
|
||||
}
|
||||
|
||||
private onIndexPressedListener mOnIndexPressedListener;
|
||||
|
||||
public onIndexPressedListener getmOnIndexPressedListener() {
|
||||
return mOnIndexPressedListener;
|
||||
}
|
||||
|
||||
public void setmOnIndexPressedListener(onIndexPressedListener mOnIndexPressedListener) {
|
||||
this.mOnIndexPressedListener = mOnIndexPressedListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示当前被按下的index的TextView
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
||||
public SuperSideBar setmPressedShowTextView(TextView mPressedShowTextView) {
|
||||
this.mPressedShowTextView = mPressedShowTextView;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SuperSideBar setmLayoutManager(LinearLayoutManager mLayoutManager) {
|
||||
this.mLayoutManager = mLayoutManager;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 一定要在设置数据源{@link #setSourceDatas(List)}之前调用
|
||||
*
|
||||
* @param needRealIndex
|
||||
* @return
|
||||
*/
|
||||
public SuperSideBar setNeedRealIndex(boolean needRealIndex) {
|
||||
isNeedRealIndex = needRealIndex;
|
||||
initIndexDatas();
|
||||
return this;
|
||||
}
|
||||
|
||||
private void initIndexDatas() {
|
||||
if (isNeedRealIndex) {
|
||||
mIndexDatas = new ArrayList<>();
|
||||
} else {
|
||||
mIndexDatas = Arrays.asList(INDEX_STRING);
|
||||
}
|
||||
}
|
||||
|
||||
public SuperSideBar setSourceDatas(List<? extends BaseIndexPinyinBean> mSourceDatas) {
|
||||
this.mSourceDatas = mSourceDatas;
|
||||
initSourceDatas();// 对数据源进行初始化
|
||||
invalidate();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化原始数据源,并取出索引数据源
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private void initSourceDatas() {
|
||||
// add by zhangxutong 2016 09 08 :解决源数据为空 或者size为0的情况,
|
||||
if (null == mSourceDatas || mSourceDatas.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!isSourceDatasAlreadySorted) {
|
||||
// 排序sourceDatas
|
||||
mDataHelper.sortSourceDatas(mSourceDatas);
|
||||
} else {
|
||||
// 汉语->拼音
|
||||
mDataHelper.convert(mSourceDatas);
|
||||
// 拼音->tag
|
||||
mDataHelper.fillInexTag(mSourceDatas);
|
||||
}
|
||||
if (isNeedRealIndex) {
|
||||
mDataHelper.getSortedIndexDatas(mSourceDatas, mIndexDatas);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据传入的pos返回tag
|
||||
*
|
||||
* @param tag
|
||||
* @return
|
||||
*/
|
||||
private int getPosByTag(String tag) {
|
||||
// add by zhangxutong 2016 09 08 :解决源数据为空 或者size为0的情况,
|
||||
if (null == mSourceDatas || mSourceDatas.isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
if (TextUtils.isEmpty(tag)) {
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < mSourceDatas.size(); i++) {
|
||||
if (tag.equals(mSourceDatas.get(i).getBaseIndexTag())) {
|
||||
return i + getHeaderViewCount();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,113 @@
|
||||
/**
|
||||
* Copyright 2016 bingoogolapple
|
||||
* <p/>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p/>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p/>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.superrecycleview.superlibrary.utils;
|
||||
|
||||
import android.app.Application;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.DimenRes;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by super南仔 on 07/28/16. <br/>
|
||||
* blog: http://supercwn.github.io/ <br/>
|
||||
* GitHub: https://github.com/supercwn
|
||||
*/
|
||||
public class SuperAdapterUtil {
|
||||
private static final Application sApp;
|
||||
|
||||
static {
|
||||
Application app = null;
|
||||
try {
|
||||
app = (Application) Class.forName("android.app.AppGlobals")
|
||||
.getMethod("getInitialApplication").invoke(null);
|
||||
if (app == null)
|
||||
throw new IllegalStateException(
|
||||
"Static initialization of Applications must be on main thread.");
|
||||
} catch (final Exception e) {
|
||||
Log.e(SuperAdapterUtil.class.getSimpleName(),
|
||||
"Failed to get current application from AppGlobals." + e.getMessage());
|
||||
try {
|
||||
app = (Application) Class.forName("android.app.ActivityThread")
|
||||
.getMethod("currentApplication").invoke(null);
|
||||
} catch (final Exception ex) {
|
||||
Log.e(SuperAdapterUtil.class.getSimpleName(),
|
||||
"Failed to get current application from ActivityThread." + e.getMessage());
|
||||
}
|
||||
} finally {
|
||||
sApp = app;
|
||||
}
|
||||
}
|
||||
|
||||
private SuperAdapterUtil() {
|
||||
}
|
||||
|
||||
public static Application getApp() {
|
||||
return sApp;
|
||||
}
|
||||
|
||||
public static int dp2px(float dpValue) {
|
||||
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue,
|
||||
getApp().getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
public static int sp2px(float dpValue) {
|
||||
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, dpValue,
|
||||
getApp().getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
public static int getDimensionPixelOffset(@DimenRes int resId) {
|
||||
return getApp().getResources().getDimensionPixelOffset(resId);
|
||||
}
|
||||
|
||||
public static int getColor(@ColorRes int resId) {
|
||||
return getApp().getResources().getColor(resId);
|
||||
}
|
||||
|
||||
public static Drawable rotateBitmap(Bitmap inputBitmap) {
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.setRotate(90, (float) inputBitmap.getWidth() / 2,
|
||||
(float) inputBitmap.getHeight() / 2);
|
||||
|
||||
float outputX = inputBitmap.getHeight();
|
||||
float outputY = 0;
|
||||
|
||||
final float[] values = new float[9];
|
||||
matrix.getValues(values);
|
||||
float x1 = values[Matrix.MTRANS_X];
|
||||
float y1 = values[Matrix.MTRANS_Y];
|
||||
matrix.postTranslate(outputX - x1, outputY - y1);
|
||||
Bitmap outputBitmap = Bitmap.createBitmap(inputBitmap.getHeight(), inputBitmap.getWidth(),
|
||||
Bitmap.Config.ARGB_8888);
|
||||
Paint paint = new Paint();
|
||||
Canvas canvas = new Canvas(outputBitmap);
|
||||
canvas.drawBitmap(inputBitmap, matrix, paint);
|
||||
return new BitmapDrawable(null, outputBitmap);
|
||||
}
|
||||
|
||||
public static boolean isListNotEmpty(List list) {
|
||||
return list != null && !list.isEmpty();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,291 @@
|
||||
/**
|
||||
* Copyright 2016 bingoogolapple
|
||||
* <p/>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p/>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p/>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.superrecycleview.superlibrary.utils;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.ColorRes;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.IntRange;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.superrecycleview.superlibrary.R;
|
||||
|
||||
/**
|
||||
* Created by super南仔 on 07/28/16. <br/>
|
||||
* blog: http://supercwn.github.io/ <br/>
|
||||
* GitHub: https://github.com/supercwn <br/>
|
||||
* RecyclerView 分隔线
|
||||
*/
|
||||
public class SuperDivider extends RecyclerView.ItemDecoration {
|
||||
private Drawable mDividerDrawable;
|
||||
private int mMarginLeft;
|
||||
private int mMarginRight;
|
||||
private int mOrientation = LinearLayout.VERTICAL;// 暂时只考虑竖直列表,不考虑横向列表以及Grid模式
|
||||
private int mStartSkipCount = 2;// 默认列表第一个没有;仅仅是在使用SuperRecycleView的情况下
|
||||
private int mEndSkipCount = 1;// 默认列表最后一个没有;仅仅是在使用SuperRecycleView的情况下
|
||||
private int mSize = 1;
|
||||
|
||||
private SuperDivider(@DrawableRes int drawableResId) {
|
||||
mDividerDrawable = ContextCompat.getDrawable(SuperAdapterUtil.getApp(), drawableResId);
|
||||
mSize = Math.min(mDividerDrawable.getIntrinsicHeight(),
|
||||
mDividerDrawable.getIntrinsicWidth());
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义 drawable 资源分隔线
|
||||
*
|
||||
* @param drawableResId
|
||||
* @return
|
||||
*/
|
||||
public static SuperDivider newDrawableDivider(@DrawableRes int drawableResId) {
|
||||
return new SuperDivider(drawableResId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认的 shape 资源分隔线
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static SuperDivider newShapeDivider() {
|
||||
return new SuperDivider(R.drawable.bga_adapter_divider_shape);
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认的图片分隔线
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static SuperDivider newBitmapDivider() {
|
||||
return new SuperDivider(R.mipmap.bga_adapter_divider_bitmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置左边距和右边距
|
||||
*
|
||||
* @param bothMarginDp 单位为 dp
|
||||
* @return
|
||||
*/
|
||||
public SuperDivider setBothMarginDp(int bothMarginDp) {
|
||||
mMarginLeft = SuperAdapterUtil.dp2px(bothMarginDp);
|
||||
mMarginRight = mMarginLeft;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置左边距
|
||||
*
|
||||
* @param marginLeftDp 单位为 dp
|
||||
* @return
|
||||
*/
|
||||
public SuperDivider setMarginLeftDp(int marginLeftDp) {
|
||||
mMarginLeft = SuperAdapterUtil.dp2px(marginLeftDp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置右边距
|
||||
*
|
||||
* @param marginRightDp 单位为 dp
|
||||
* @return
|
||||
*/
|
||||
public SuperDivider setMarginRightDp(int marginRightDp) {
|
||||
mMarginRight = SuperAdapterUtil.dp2px(marginRightDp);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置分隔线颜色资源 id
|
||||
*
|
||||
* @param resId
|
||||
* @return
|
||||
*/
|
||||
public SuperDivider setColor(@ColorRes int resId) {
|
||||
return setColorResource(SuperAdapterUtil.getColor(resId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置分隔线颜色
|
||||
*
|
||||
* @param color
|
||||
* @return
|
||||
*/
|
||||
private SuperDivider setColorResource(@ColorInt int color) {
|
||||
mDividerDrawable.setColorFilter(color, PorterDuff.Mode.SRC);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置为水平方向
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public SuperDivider setHorizontal() {
|
||||
mOrientation = LinearLayout.HORIZONTAL;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 旋转分隔线,仅用于分隔线为 Bitmap 时。应用场景:UI 给了一个水平分隔线,恰巧项目里需要一条一模一样的竖直分隔线
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public SuperDivider rotateDivider() {
|
||||
if (mDividerDrawable != null && mDividerDrawable instanceof BitmapDrawable) {
|
||||
mDividerDrawable = SuperAdapterUtil
|
||||
.rotateBitmap(((BitmapDrawable) mDividerDrawable).getBitmap());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳过开始的条数。默认值为 1,不绘制第一个 item 顶部的分隔线
|
||||
*
|
||||
* @param startSkipCount
|
||||
* @return
|
||||
*/
|
||||
public SuperDivider setStartSkipCount(@IntRange(from = 0) int startSkipCount) {
|
||||
mStartSkipCount = startSkipCount;
|
||||
if (mStartSkipCount < 0) {
|
||||
mStartSkipCount = 0;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳过末尾的条数
|
||||
*
|
||||
* @param endSkipCount
|
||||
* @return
|
||||
*/
|
||||
public SuperDivider setEndSkipCount(@IntRange(from = 0) int endSkipCount) {
|
||||
mEndSkipCount = endSkipCount;
|
||||
if (mEndSkipCount < 0) {
|
||||
mEndSkipCount = 0;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置分割线尺寸
|
||||
*
|
||||
* @param sizeDp 单位为 dp
|
||||
* @return
|
||||
*/
|
||||
public SuperDivider setSizeDp(int sizeDp) {
|
||||
mSize = SuperAdapterUtil.dp2px(sizeDp);
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean isNeedSkip(int childAdapterPosition,
|
||||
int realItemCount) {
|
||||
int lastPosition = realItemCount - 1;
|
||||
// 跳过最后 mEndSkipCount 个
|
||||
if (childAdapterPosition > lastPosition - mEndSkipCount) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// 跳过前 mStartSkipCount 个
|
||||
// 1
|
||||
if (childAdapterPosition < mStartSkipCount) {
|
||||
return true;
|
||||
}
|
||||
// 默认不跳过
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
|
||||
RecyclerView.State state) {
|
||||
if (parent.getLayoutManager() == null || parent.getAdapter() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int childAdapterPosition = parent.getChildAdapterPosition(view);
|
||||
int itemCount = parent.getAdapter().getItemCount();
|
||||
|
||||
int realChildAdapterPosition = childAdapterPosition;
|
||||
int realItemCount = itemCount;
|
||||
|
||||
if (isNeedSkip(childAdapterPosition, realItemCount)) {
|
||||
outRect.set(0, 0, 0, 0);
|
||||
} else {
|
||||
if (mOrientation == LinearLayout.VERTICAL) {
|
||||
getVerticalItemOffsets(outRect);
|
||||
} else {
|
||||
outRect.set(mSize, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void getVerticalItemOffsets(Rect outRect) {
|
||||
outRect.set(0, mSize, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrawOver(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
|
||||
if (parent.getLayoutManager() == null || parent.getAdapter() == null) {
|
||||
return;
|
||||
}
|
||||
int itemCount = parent.getAdapter().getItemCount();
|
||||
if (mOrientation == LinearLayout.VERTICAL) {
|
||||
drawVertical(canvas, parent, itemCount);
|
||||
} else {
|
||||
drawVertical(canvas, parent, itemCount);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawVertical(Canvas canvas, RecyclerView parent, int itemCount) {
|
||||
int dividerLeft = parent.getPaddingLeft() + mMarginLeft;
|
||||
int dividerRight = parent.getWidth() - parent.getPaddingRight() - mMarginRight;
|
||||
View itemView;
|
||||
RecyclerView.LayoutParams itemLayoutParams;
|
||||
|
||||
for (int childPosition = 0; childPosition < itemCount; childPosition++) {
|
||||
itemView = parent.getChildAt(childPosition);
|
||||
if (itemView == null || itemView.getLayoutParams() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int childAdapterPosition = parent.getChildAdapterPosition(itemView);
|
||||
|
||||
if (isNeedSkip(childAdapterPosition, itemCount)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
itemLayoutParams = (RecyclerView.LayoutParams) itemView.getLayoutParams();
|
||||
int dividerBottom = itemView.getTop() - itemLayoutParams.topMargin;
|
||||
|
||||
drawVertical(canvas, dividerLeft, dividerRight, dividerBottom);
|
||||
}
|
||||
}
|
||||
|
||||
public void drawVertical(Canvas canvas, int dividerLeft, int dividerRight, int itemTop) {
|
||||
int dividerBottom = itemTop;
|
||||
int dividerTop = dividerBottom - mSize;
|
||||
mDividerDrawable.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom);
|
||||
mDividerDrawable.draw(canvas);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="#DEDEDE" />
|
||||
<size
|
||||
android:width="1dp"
|
||||
android:height="1dp" />
|
||||
</shape>
|
||||
16
superlibrary/src/main/res/drawable/progressbar.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animation-list android:oneshot="false"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:duration="100" android:drawable="@mipmap/loading_01" />
|
||||
<item android:duration="100" android:drawable="@mipmap/loading_02" />
|
||||
<item android:duration="100" android:drawable="@mipmap/loading_03" />
|
||||
<item android:duration="100" android:drawable="@mipmap/loading_04" />
|
||||
<item android:duration="100" android:drawable="@mipmap/loading_05" />
|
||||
<item android:duration="100" android:drawable="@mipmap/loading_06" />
|
||||
<item android:duration="100" android:drawable="@mipmap/loading_07" />
|
||||
<item android:duration="100" android:drawable="@mipmap/loading_08" />
|
||||
<item android:duration="100" android:drawable="@mipmap/loading_09" />
|
||||
<item android:duration="100" android:drawable="@mipmap/loading_10" />
|
||||
<item android:duration="100" android:drawable="@mipmap/loading_11" />
|
||||
<item android:duration="100" android:drawable="@mipmap/loading_12" />
|
||||
</animation-list>
|
||||
3
superlibrary/src/main/res/drawable/progressloading.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animated-rotate android:drawable="@mipmap/ic_loading_rotate" android:pivotX="50.0%" android:pivotY="50.0%"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" />
|
||||
21
superlibrary/src/main/res/layout/listview_footer.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:padding="3dp">
|
||||
<ProgressBar
|
||||
android:id="@+id/listview_foot_progress"
|
||||
android:layout_width="30dip"
|
||||
android:layout_height="30dip"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/listview_foot_more"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:padding="5dp"
|
||||
android:text="加载中..."/>
|
||||
|
||||
</LinearLayout>
|
||||
70
superlibrary/src/main/res/layout/listview_header.xml
Normal file
@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="bottom" >
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/listview_header_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="80dp"
|
||||
android:paddingTop="10dip"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="100dip"
|
||||
android:layout_centerInParent="true"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/listview_header_text">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/refresh_status_textview"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/listview_header_hint_normal" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:layout_marginTop="3dp" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/listview_header_last_time"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/last_refresh_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/listview_header_arrow"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="35dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_toLeftOf="@id/listview_header_text"
|
||||
android:src="@mipmap/ic_pulltorefresh_arrow" />
|
||||
|
||||
<com.superrecycleview.superlibrary.recycleview.SimpleViewSwitcher
|
||||
android:id="@+id/listview_header_progressbar"
|
||||
android:layout_width="30dip"
|
||||
android:layout_height="30dip"
|
||||
android:layout_toLeftOf="@id/listview_header_text"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="40dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:visibility="invisible" />
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
BIN
superlibrary/src/main/res/mipmap-xhdpi/ic_loading_rotate.png
Normal file
|
After Width: | Height: | Size: 444 B |
|
After Width: | Height: | Size: 1.4 KiB |
BIN
superlibrary/src/main/res/mipmap-xhdpi/loading_01.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
superlibrary/src/main/res/mipmap-xhdpi/loading_02.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
superlibrary/src/main/res/mipmap-xhdpi/loading_03.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
superlibrary/src/main/res/mipmap-xhdpi/loading_04.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
superlibrary/src/main/res/mipmap-xhdpi/loading_05.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
superlibrary/src/main/res/mipmap-xhdpi/loading_06.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
superlibrary/src/main/res/mipmap-xhdpi/loading_07.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
superlibrary/src/main/res/mipmap-xhdpi/loading_08.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
superlibrary/src/main/res/mipmap-xhdpi/loading_09.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
superlibrary/src/main/res/mipmap-xhdpi/loading_10.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
superlibrary/src/main/res/mipmap-xhdpi/loading_11.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
superlibrary/src/main/res/mipmap-xhdpi/loading_12.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
57
superlibrary/src/main/res/values/attrs.xml
Normal file
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!--pull to refresh and loadmore-->
|
||||
<declare-styleable name="AVLoadingIndicatorView">
|
||||
<attr name="indicator">
|
||||
<flag name="BallPulse" value="0" />
|
||||
<flag name="BallGridPulse" value="1" />
|
||||
<flag name="BallClipRotate" value="2" />
|
||||
<flag name="BallClipRotatePulse" value="3" />
|
||||
<flag name="SquareSpin" value="4" />
|
||||
<flag name="BallClipRotateMultiple" value="5" />
|
||||
<flag name="BallPulseRise" value="6" />
|
||||
<flag name="BallRotate" value="7" />
|
||||
<flag name="CubeTransition" value="8" />
|
||||
<flag name="BallZigZag" value="9" />
|
||||
<flag name="BallZigZagDeflect" value="10" />
|
||||
<flag name="BallTrianglePath" value="11" />
|
||||
<flag name="BallScale" value="12" />
|
||||
<flag name="LineScale" value="13" />
|
||||
<flag name="LineScaleParty" value="14" />
|
||||
<flag name="BallScaleMultiple" value="15" />
|
||||
<flag name="BallPulseSync" value="16" />
|
||||
<flag name="BallBeat" value="17" />
|
||||
<flag name="LineScalePulseOut" value="18" />
|
||||
<flag name="LineScalePulseOutRapid" value="19" />
|
||||
<flag name="BallScaleRipple" value="20" />
|
||||
<flag name="BallScaleRippleMultiple" value="21" />
|
||||
<flag name="BallSpinFadeLoader" value="22" />
|
||||
<flag name="LineSpinFadeLoader" value="23" />
|
||||
<flag name="TriangleSkewSpin" value="24" />
|
||||
<flag name="Pacman" value="25" />
|
||||
<flag name="BallGridBeat" value="26" />
|
||||
<flag name="SemiCircleSpin" value="27" />
|
||||
</attr>
|
||||
<attr name="indicator_color" format="color" />
|
||||
</declare-styleable>
|
||||
<!-- end -->
|
||||
<!--swipeMenu-->
|
||||
<declare-styleable name="SwipeMenu">
|
||||
<attr name="anim_duration" format="integer" />
|
||||
</declare-styleable>
|
||||
<!--end-->
|
||||
<!--indexbar-->
|
||||
<declare-styleable name="SuperSideBar">
|
||||
<!--bar的字体大小-->
|
||||
<attr name="super_sidebar_textsize" format="dimension" />
|
||||
<!--bar的背景颜色-->
|
||||
<attr name="super_sidebar_backgrond" format="color" />
|
||||
<!--bar点击后的背景颜色-->
|
||||
<attr name="super_sidebar_backgrond_press" format="color" />
|
||||
<!--bar字体的颜色-->
|
||||
<attr name="super_sidebar_textcolor" format="color" />
|
||||
<!--bar点击后的字体颜色-->
|
||||
<attr name="super_sidebar_textcolor_press" format="color" />
|
||||
</declare-styleable>
|
||||
<!--end-->
|
||||
</resources>
|
||||
130
superlibrary/src/main/res/values/colors.xml
Normal file
@ -0,0 +1,130 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#3F51B5</color>
|
||||
<color name="colorPrimaryDark">#419DE4</color>
|
||||
<color name="colorAccent">#FF4081</color>
|
||||
|
||||
<color name="black">#000000</color>
|
||||
<color name="white">#fff</color>
|
||||
<color name="blue">#419DE4</color>
|
||||
|
||||
<color name="border_clo">#ccc</color>
|
||||
<color name="border_clo1">#EA0000</color>
|
||||
<color name="text_clo">#333</color>
|
||||
<color name="light_text_color">#ffd7d7d7</color>
|
||||
|
||||
<!-- 搜索框 -->
|
||||
<color name="myred">#2894ff</color>
|
||||
<color name="darkgray">#cccc</color>
|
||||
<color name="color_white">#ffffff</color>
|
||||
<color name="btn_press_color1">#5677fc</color>
|
||||
<color name="btn_pressed_color">#3ca0ec</color>
|
||||
<color name="btn_press_color">#66000000</color>
|
||||
<color name="btn_unpress_color">#22000000</color>
|
||||
|
||||
<!-- 信鸽 -->
|
||||
<color name="ccp_green">#ff00B486</color>
|
||||
<color name="gray">#858585</color>
|
||||
<color name="gray_t">#7f9a9b9c</color>
|
||||
<color name="gray_presentation">#B7B7B7</color>
|
||||
<color name="fuxk_base_color_white">#ffffff</color>
|
||||
<color name="fuxk_base_divide_line_color">#dcdcdc</color>
|
||||
|
||||
|
||||
<!-- 绿色 -->
|
||||
<color name="green">#45CD87</color>
|
||||
<color name="green01">#B8EFF9</color>
|
||||
<color name="green02">#59E1FA</color>
|
||||
<color name="green03">#C9FFDE</color>
|
||||
<color name="green04">#31F77E</color>
|
||||
<color name="green05">#9BECF9</color>
|
||||
|
||||
<!-- 紫色 -->
|
||||
<color name="violet01">#DB96FF</color>
|
||||
<color name="violet02">#BE55F5</color>
|
||||
<color name="violet03">#CBC3EE</color>
|
||||
<color name="violet04">#937FEF</color>
|
||||
|
||||
<!-- 浅黄绿 -->
|
||||
<color name="yellowGreen01">#D6FB9C</color>
|
||||
<color name="yellowGreen02">#A9F82E</color>
|
||||
<color name="yellow01">#FCDB70</color>
|
||||
<color name="yellow02">#F8C82E</color>
|
||||
|
||||
<!-- 红紫 -->
|
||||
<color name="red">#ffff5454</color>
|
||||
<color name="red01">#F9B2C0</color>
|
||||
<color name="red02">#F6728C</color>
|
||||
<color name="redViolet01">#F6D1F3</color>
|
||||
<color name="redViolet02">#F6728C</color>
|
||||
|
||||
<!-- 灰色 -->
|
||||
<color name="gray01">#DADDE2</color>
|
||||
<color name="gray02">#A3A1A1</color>
|
||||
<color name="gray03">#9FA2A3</color>
|
||||
<color name="gray04">#757778</color>
|
||||
<color name="gray05">#95A3AE</color>
|
||||
<color name="gray06">#f5f5f5</color>
|
||||
<color name="gray07">#838181</color>
|
||||
<color name="gray_black">#727272</color>
|
||||
<color name="gray_patrol">#EDEDED</color>
|
||||
|
||||
<!-- 半透明 -->
|
||||
<color name="translucent01">#55000000</color>
|
||||
<color name="translucent02">#97000000</color>
|
||||
<color name="lucen">#00000000</color>
|
||||
<color name="forgetpwd">#91B1C7</color>
|
||||
<color name="pa_item_bg">#E9E9E9</color>
|
||||
<color name="fav_click_color">#66000000</color>
|
||||
<color name="sign_mood_selected">#ff9B9B9C</color>
|
||||
<color name="sign_mood_nomal">#00000000</color>
|
||||
<color name="sign_mood_nomal_0">#e0e0e0</color>
|
||||
|
||||
<color name="picker_white">#ffffff</color>
|
||||
<color name="picker_bg_floder_press">#bdbdbd</color>
|
||||
|
||||
<color name="list_bg_gaoliang">#E1FFFF</color>
|
||||
|
||||
<color name="bar">#31F77E</color>
|
||||
<color name="bar1">#B5C2CA</color>
|
||||
<color name="bar2">#F5E6BF</color>
|
||||
<color name="bar3">#81D8C8</color>
|
||||
|
||||
<color name="color_gr_white">#7fffffff</color>
|
||||
<color name="color_luc_blue">#661774ac</color>
|
||||
<color name="color_luc_blue_login">#cc01b4ed</color>
|
||||
|
||||
<color name="app_title_color_second">#FFFFFF</color>
|
||||
<color name="gray_text">#A8A8A8</color>
|
||||
<color name="app_title_color_first">#01b4ee</color>
|
||||
|
||||
<color name="description">#686868</color>
|
||||
|
||||
<color name="line">#4DD4B3</color>
|
||||
<color name="linefill">#DEEFE4</color>
|
||||
<color name="line1">#E9C517</color>
|
||||
<color name="line1fill">#ECEAD0</color>
|
||||
<color name="line2">#9F8FBA</color>
|
||||
<color name="line2fill">#EBE4F8</color>
|
||||
<color name="result_view">#b0000000</color>
|
||||
<color name="transparent">#00000000</color>
|
||||
|
||||
<color name="ccp_green_alpha">#7f00B486</color>
|
||||
<item name="green_btn_color_disable" type="color">@color/ccp_green_alpha</item>
|
||||
<color name="green_btn_color_pressed">#ff298409</color>
|
||||
|
||||
<color name="red_btn_color_normal">#ffff5454</color>
|
||||
<color name="red_btn_color_pressed">#ffd24242</color>
|
||||
<color name="red_btn_color_disable">#7fff5454</color>
|
||||
<color name="error_red">#E0796C</color>
|
||||
<color name="error_yellow">#FF8400</color>
|
||||
|
||||
<color name="title_blue">#43B3FF</color>
|
||||
<color name="blues">#66b3ff</color>
|
||||
<color name="little_blue">#43B3FF</color>
|
||||
<color name="viewfinder_mask">#60000000</color>
|
||||
<color name="possible_result_points">#c0ffff00</color>
|
||||
|
||||
<color name="btn_normal_unpressed_bg">#2CC8F2</color>
|
||||
<color name="btn_normal_pressed_bg">#2CA6E0</color>
|
||||
</resources>
|
||||
9
superlibrary/src/main/res/values/ids.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<item name="smContentView" type="id"/>
|
||||
<item name="smMenuView" type="id"/>
|
||||
|
||||
<item name="BaseQuickAdapter_viewholder_support" type="id"/>
|
||||
<item name="BaseQuickAdapter_swiping_support" type="id"/>
|
||||
<item name="BaseQuickAdapter_dragging_support" type="id"/>
|
||||
</resources>
|
||||
11
superlibrary/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<resources>
|
||||
<string name="app_name">SuperLibrary</string>
|
||||
|
||||
<string name="listview_header_hint_normal">下拉刷新</string>
|
||||
<string name="listview_header_hint_release">释放立即刷新</string>
|
||||
<string name="listview_loading">正在加载</string>
|
||||
<string name="nomore_loading">没有了</string>
|
||||
<string name="refreshing">正在刷新</string>
|
||||
<string name="refresh_done">刷新完成</string>
|
||||
<string name="listview_header_last_time">上次更新时间:</string>
|
||||
</resources>
|
||||
@ -0,0 +1,15 @@
|
||||
package com.superrecycleview.superlibrary;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* To work on unit tests, switch the Test Artifact in the Build Variants view.
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() throws Exception {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||