增加发现页
4
xrecyclerview/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.jcodecraeer.xrecyclerview">
|
||||
<application/>
|
||||
</manifest>
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.jcodecraeer.xrecyclerview;
|
||||
|
||||
|
||||
import com.google.android.material.appbar.AppBarLayout;
|
||||
|
||||
/**
|
||||
* Created by jianghejie on 16/6/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,322 @@
|
||||
package com.jcodecraeer.xrecyclerview;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
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.jcodecraeer.xrecyclerview.progressindicator.AVLoadingIndicatorView;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class ArrowRefreshHeader extends LinearLayout implements BaseRefreshHeader {
|
||||
|
||||
private static final String XR_REFRESH_KEY = "XR_REFRESH_KEY";
|
||||
private static final String XR_REFRESH_TIME_KEY = "XR_REFRESH_TIME_KEY";
|
||||
private LinearLayout mContainer;
|
||||
private ImageView mArrowImageView;
|
||||
private SimpleViewSwitcher mProgressBar;
|
||||
private TextView mStatusTextView;
|
||||
private int mState = STATE_NORMAL;
|
||||
|
||||
private TextView mHeaderTimeView;
|
||||
private LinearLayout mHeaderRefreshTimeContainer;
|
||||
|
||||
private Animation mRotateUpAnim;
|
||||
private Animation mRotateDownAnim;
|
||||
|
||||
private static final int ROTATE_ANIM_DURATION = 180;
|
||||
|
||||
public int mMeasuredHeight;
|
||||
private AVLoadingIndicatorView progressView;
|
||||
|
||||
public void destroy(){
|
||||
mProgressBar = null;
|
||||
if(progressView != null){
|
||||
progressView.destroy();
|
||||
progressView = null;
|
||||
}
|
||||
if(mRotateUpAnim != null){
|
||||
mRotateUpAnim.cancel();
|
||||
mRotateUpAnim = null;
|
||||
}
|
||||
if(mRotateDownAnim != null){
|
||||
mRotateDownAnim.cancel();
|
||||
mRotateDownAnim = null;
|
||||
}
|
||||
}
|
||||
|
||||
public ArrowRefreshHeader(Context context) {
|
||||
super(context);
|
||||
initView();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @param attrs
|
||||
*/
|
||||
public ArrowRefreshHeader(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView();
|
||||
}
|
||||
|
||||
public void setRefreshTimeVisible(boolean show){
|
||||
if(mHeaderRefreshTimeContainer != null)
|
||||
mHeaderRefreshTimeContainer.setVisibility(show?VISIBLE:GONE);
|
||||
}
|
||||
|
||||
private void initView() {
|
||||
// 初始情况,设置下拉刷新view高度为0
|
||||
mContainer = (LinearLayout) LayoutInflater.from(getContext()).inflate(
|
||||
R.layout.listview_header, null);
|
||||
|
||||
mHeaderRefreshTimeContainer
|
||||
= (LinearLayout) mContainer.findViewById(R.id.header_refresh_time_container);
|
||||
|
||||
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);
|
||||
progressView = new AVLoadingIndicatorView(getContext());
|
||||
progressView.setIndicatorColor(0xffB5B5B5);
|
||||
progressView.setIndicatorId(ProgressStyle.BallSpinFadeLoader);
|
||||
if(mProgressBar != null)
|
||||
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){
|
||||
if(mProgressBar != null)
|
||||
mProgressBar.setView(new ProgressBar(getContext(), null, android.R.attr.progressBarStyle));
|
||||
}else{
|
||||
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);
|
||||
if(mProgressBar != null)
|
||||
mProgressBar.setVisibility(View.VISIBLE);
|
||||
smoothScrollTo(mMeasuredHeight);
|
||||
} else if(state == STATE_DONE) {
|
||||
mArrowImageView.setVisibility(View.INVISIBLE);
|
||||
if(mProgressBar != null)
|
||||
mProgressBar.setVisibility(View.INVISIBLE);
|
||||
} else { // 显示箭头图片
|
||||
mArrowImageView.setVisibility(View.VISIBLE);
|
||||
if(mProgressBar != null){
|
||||
mProgressBar.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
mHeaderTimeView.setText(friendlyTime(getLastRefreshTime()));
|
||||
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;
|
||||
}
|
||||
|
||||
private long getLastRefreshTime(){
|
||||
SharedPreferences s =
|
||||
getContext()
|
||||
.getSharedPreferences(XR_REFRESH_KEY,Context.MODE_APPEND);
|
||||
return s.getLong(XR_REFRESH_TIME_KEY,new Date().getTime());
|
||||
}
|
||||
|
||||
private void saveLastRefreshTime(long refreshTime){
|
||||
SharedPreferences s =
|
||||
getContext()
|
||||
.getSharedPreferences(XR_REFRESH_KEY,Context.MODE_APPEND);
|
||||
s.edit().putLong(XR_REFRESH_TIME_KEY,refreshTime).commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshComplete(){
|
||||
mHeaderTimeView.setText(friendlyTime(getLastRefreshTime()));
|
||||
saveLastRefreshTime(System.currentTimeMillis());
|
||||
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;
|
||||
}
|
||||
if (mState != STATE_REFRESHING) {
|
||||
smoothScrollTo(0);
|
||||
}
|
||||
|
||||
if (mState == STATE_REFRESHING) {
|
||||
int 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) {
|
||||
return friendlyTime(time.getTime());
|
||||
}
|
||||
|
||||
public static String friendlyTime(long time) {
|
||||
//获取time距离当前的秒数
|
||||
int ct = (int)((System.currentTimeMillis() - time)/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.jcodecraeer.xrecyclerview;
|
||||
|
||||
/**
|
||||
* Created by jianghejie on 15/11/22.
|
||||
*/
|
||||
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,21 @@
|
||||
package com.jcodecraeer.xrecyclerview;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* 作者:林冠宏
|
||||
* <p>
|
||||
* My GitHub : https://github.com/af913337456/
|
||||
* <p>
|
||||
* My Blog : http://www.cnblogs.com/linguanh/
|
||||
* <p>
|
||||
* on 2017/11/8.
|
||||
*/
|
||||
|
||||
public interface CustomFooterViewCallBack {
|
||||
|
||||
void onLoadingMore(View yourFooterView);
|
||||
void onLoadMoreComplete(View yourFooterView);
|
||||
void onSetNoMore(View yourFooterView,boolean noMore);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.jcodecraeer.xrecyclerview;
|
||||
|
||||
|
||||
/**
|
||||
* Created by jianghejie on 16/6/20.
|
||||
*/
|
||||
|
||||
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,108 @@
|
||||
package com.jcodecraeer.xrecyclerview;
|
||||
|
||||
/**
|
||||
* Created by jianghejie on 15/11/22.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
|
||||
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,127 @@
|
||||
package com.jcodecraeer.xrecyclerview;
|
||||
|
||||
import android.content.Context;
|
||||
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.jcodecraeer.xrecyclerview.progressindicator.AVLoadingIndicatorView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
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;
|
||||
private String loadingHint;
|
||||
private String noMoreHint;
|
||||
private String loadingDoneHint;
|
||||
|
||||
private AVLoadingIndicatorView progressView;
|
||||
|
||||
public LoadingMoreFooter(Context context) {
|
||||
super(context);
|
||||
initView();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @param attrs
|
||||
*/
|
||||
public LoadingMoreFooter(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView();
|
||||
}
|
||||
|
||||
public void destroy(){
|
||||
progressCon = null;
|
||||
if(progressView != null){
|
||||
progressView.destroy();
|
||||
progressView = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setLoadingHint(String hint) {
|
||||
loadingHint = hint;
|
||||
}
|
||||
|
||||
public void setNoMoreHint(String hint) {
|
||||
noMoreHint = hint;
|
||||
}
|
||||
|
||||
public void setLoadingDoneHint(String hint) {
|
||||
loadingDoneHint = hint;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
progressView = new AVLoadingIndicatorView(this.getContext());
|
||||
progressView.setIndicatorColor(0xffB5B5B5);
|
||||
progressView.setIndicatorId(ProgressStyle.BallSpinFadeLoader);
|
||||
progressCon.setView(progressView);
|
||||
|
||||
addView(progressCon);
|
||||
mText = new TextView(getContext());
|
||||
mText.setText(getContext().getString(R.string.listview_loading));
|
||||
|
||||
if(loadingHint == null || loadingHint.equals("")){
|
||||
loadingHint = (String)getContext().getText(R.string.listview_loading);
|
||||
}
|
||||
if(noMoreHint == null || noMoreHint.equals("")){
|
||||
noMoreHint = (String)getContext().getText(R.string.nomore_loading);
|
||||
}
|
||||
if(loadingDoneHint == null || loadingDoneHint.equals("")){
|
||||
loadingDoneHint = (String)getContext().getText(R.string.loading_done);
|
||||
}
|
||||
|
||||
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
layoutParams.setMargins( (int)getResources().getDimension(R.dimen.textandiconmargin),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{
|
||||
progressView = new AVLoadingIndicatorView(this.getContext());
|
||||
progressView.setIndicatorColor(0xffB5B5B5);
|
||||
progressView.setIndicatorId(style);
|
||||
progressCon.setView(progressView);
|
||||
}
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
switch(state) {
|
||||
case STATE_LOADING:
|
||||
progressCon.setVisibility(View.VISIBLE);
|
||||
mText.setText(loadingHint);
|
||||
this.setVisibility(View.VISIBLE);
|
||||
break;
|
||||
case STATE_COMPLETE:
|
||||
mText.setText(loadingDoneHint);
|
||||
this.setVisibility(View.GONE);
|
||||
break;
|
||||
case STATE_NOMORE:
|
||||
mText.setText(noMoreHint);
|
||||
progressCon.setVisibility(View.GONE);
|
||||
this.setVisibility(View.VISIBLE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.jcodecraeer.xrecyclerview;
|
||||
|
||||
/**
|
||||
* Created by jianghejie on 15/11/23.
|
||||
*/
|
||||
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,88 @@
|
||||
package com.jcodecraeer.xrecyclerview;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* Created by jianghejie on 16/6/20.
|
||||
*/
|
||||
|
||||
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
||||
|
||||
public static final float ALPHA_FULL = 1.0f;
|
||||
|
||||
private final ItemTouchHelperAdapter mAdapter;
|
||||
private XRecyclerView mXrecyclerView;
|
||||
|
||||
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter, XRecyclerView recyclerView) {
|
||||
mAdapter = adapter;
|
||||
this.mXrecyclerView = 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.jcodecraeer.xrecyclerview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* Created by jianghejie on 15/11/22.
|
||||
*/
|
||||
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,292 @@
|
||||
package com.jcodecraeer.xrecyclerview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.OverScroller;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.view.NestedScrollingParent;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
||||
|
||||
/**
|
||||
* 作者:林冠宏
|
||||
* <p>
|
||||
* My GitHub : https://github.com/af913337456/
|
||||
* <p>
|
||||
* My Blog : http://www.cnblogs.com/linguanh/
|
||||
* <p>
|
||||
* on 2017/12/31.
|
||||
*
|
||||
* DES:
|
||||
* A LinearLayout which can combine with XRecyclerView in a sticky scroll status.
|
||||
*
|
||||
* Demo: see it in gitHub.
|
||||
*
|
||||
* Read_me:
|
||||
* Only support XRecyclerView for now,if you wanna to support other viewGroups which
|
||||
* has imp NestedScrollingChild interface,you can change my code,then it will be ok.
|
||||
* When you use it to XR,you best close pull refresh model,because it may
|
||||
* cause some new problems that i never met.
|
||||
* ----LinGuanHong
|
||||
*/
|
||||
|
||||
public class StickyScrollLinearLayout
|
||||
extends LinearLayout
|
||||
implements NestedScrollingParent
|
||||
{
|
||||
|
||||
private static final String TAG = "StickyScrollLayout";
|
||||
|
||||
private View mTopView;
|
||||
private View mTabView;
|
||||
private View mContentView;
|
||||
|
||||
private OverScroller mScroller;
|
||||
private VelocityTracker mVelocityTracker;
|
||||
private int mTopViewHeight;
|
||||
private RecyclerView.LayoutManager layoutManager = null;
|
||||
private int targetFirstVisiblePosition = 1;
|
||||
|
||||
public interface StickyScrollInitInterface{
|
||||
View setTopView();
|
||||
View setTabView();
|
||||
View setContentView();
|
||||
}
|
||||
|
||||
public StickyScrollLinearLayout(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public StickyScrollLinearLayout(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context){
|
||||
setOrientation(LinearLayout.VERTICAL);
|
||||
mScroller = new OverScroller(context);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void setInitInterface(@NonNull StickyScrollInitInterface initInterface){
|
||||
if(initInterface == null)
|
||||
throw new NullPointerException("initInterface can not be null!");
|
||||
this.mTopView = initInterface.setTopView();
|
||||
if(this.mTopView != null)
|
||||
getTopViewHeight();
|
||||
|
||||
this.mTabView = initInterface.setTabView();
|
||||
|
||||
this.mContentView = initInterface.setContentView();
|
||||
if(this.mContentView == null)
|
||||
return;
|
||||
setTotalHeight();
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
public View getContentView(){
|
||||
return this.mContentView;
|
||||
}
|
||||
|
||||
// 设置,当 XR 里面显示的 item 第一个的位置是多少时,触发拦截
|
||||
// to set a position of XR's dataList to control when we should call over scroll
|
||||
public void setTargetFirstVisiblePosition(int targetFirstVisiblePosition) {
|
||||
this.targetFirstVisiblePosition = targetFirstVisiblePosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
|
||||
Log.e(TAG, "onStartNestedScroll "+child.toString()+" "+target.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNestedScrollAccepted(View child, View target, int nestedScrollAxes) {
|
||||
Log.e(TAG, "onNestedScrollAccepted");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopNestedScroll(View target) {
|
||||
Log.e(TAG, "onStopNestedScroll "+target.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
|
||||
Log.e(TAG, "onNestedScroll "+dyConsumed+"----"+dyUnconsumed);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
|
||||
|
||||
if(!(target instanceof XRecyclerView))
|
||||
// todo 2017-12-31,make it more general
|
||||
throw new UnsupportedOperationException("insert your content must is XRecyclerView!");
|
||||
|
||||
layoutManager = ((RecyclerView)target).getLayoutManager();
|
||||
|
||||
int firstVisiblePosition;
|
||||
if (layoutManager instanceof GridLayoutManager) {
|
||||
firstVisiblePosition = ((GridLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition();
|
||||
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
|
||||
int[] into = new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
|
||||
((StaggeredGridLayoutManager) layoutManager).findFirstCompletelyVisibleItemPositions(into);
|
||||
firstVisiblePosition = into[0];
|
||||
} else {
|
||||
firstVisiblePosition = ((LinearLayoutManager) layoutManager).findFirstCompletelyVisibleItemPosition();
|
||||
}
|
||||
if(firstVisiblePosition < 0)
|
||||
return;
|
||||
|
||||
int scrollY = getScrollY();
|
||||
boolean temp = dy > 0 && (scrollY < mTopViewHeight);
|
||||
Log.e(TAG,
|
||||
"mTopViewHeight == "+mTopViewHeight
|
||||
+"\ndy == "+dy
|
||||
+"\nscrollY == "+scrollY
|
||||
+"\nhiddenTop && showTop "+temp);
|
||||
if(!temp){
|
||||
// judge
|
||||
temp = dy < 0
|
||||
&& (scrollY >= 0)
|
||||
&&
|
||||
(
|
||||
!ViewCompat.canScrollVertically(target, -1)
|
||||
||
|
||||
firstVisiblePosition==targetFirstVisiblePosition
|
||||
);
|
||||
Log.e(TAG,
|
||||
"mTopViewHeight == "+mTopViewHeight
|
||||
+"\ndy == "+dy
|
||||
+"\nscrollY == "+scrollY
|
||||
+"\nfirstVisiblePosition "+firstVisiblePosition);
|
||||
}
|
||||
if (temp) {
|
||||
scrollBy(0, dy);
|
||||
consumed[1] = dy;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
|
||||
Log.e(TAG, "onNestedFling");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
|
||||
Log.e(TAG, "onNestedPreFling");
|
||||
//down - //up+
|
||||
if (getScrollY() >= mTopViewHeight) return false;
|
||||
fling((int) velocityY);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNestedScrollAxes() {
|
||||
Log.e(TAG, "getNestedScrollAxes");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private void initVelocityTrackerIfNotExists() {
|
||||
if (mVelocityTracker == null)
|
||||
mVelocityTracker = VelocityTracker.obtain();
|
||||
}
|
||||
|
||||
// call this when destroy
|
||||
public void destroy() {
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.recycle();
|
||||
mVelocityTracker = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
// 你可以在 xml 文件内配置
|
||||
// you can init those views in your xml file
|
||||
|
||||
// mTopView = findViewById(R.id.topContainer);
|
||||
// mTabView = findViewById(R.id.tabLayout);
|
||||
// mContentView = findViewById(R.id.vp);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
if(mTabView == null || mTopView == null || mContentView == null)
|
||||
return;
|
||||
// getChildAt(0).
|
||||
// measure(
|
||||
// widthMeasureSpec,
|
||||
// MeasureSpec.makeMeasureSpec(
|
||||
// 0,
|
||||
// MeasureSpec.UNSPECIFIED
|
||||
// )
|
||||
// );
|
||||
setTotalHeight();
|
||||
}
|
||||
|
||||
private void setTotalHeight(){
|
||||
ViewGroup.LayoutParams params = mContentView.getLayoutParams();
|
||||
params.height = getMeasuredHeight() - mTabView.getMeasuredHeight();
|
||||
setMeasuredDimension(
|
||||
getMeasuredWidth(),
|
||||
mTopView.getMeasuredHeight()
|
||||
+ mTabView.getMeasuredHeight()
|
||||
+ mContentView.getMeasuredHeight()
|
||||
);
|
||||
}
|
||||
|
||||
private void getTopViewHeight(){
|
||||
if(mTopView == null)
|
||||
return;
|
||||
mTopViewHeight = mTopView.getMeasuredHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
||||
super.onSizeChanged(w, h, oldw, oldh);
|
||||
getTopViewHeight();
|
||||
}
|
||||
|
||||
|
||||
public void fling(int velocityY) {
|
||||
mScroller.fling(0, getScrollY(), 0, velocityY, 0, 0, 0, mTopViewHeight);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scrollTo(int x, int y) {
|
||||
if (y < 0)
|
||||
y = 0;
|
||||
|
||||
if (y > mTopViewHeight)
|
||||
// 边界限制,防止把 tabView 也挡住了
|
||||
// Prevent it from hiding the tabView,so we limit it
|
||||
y = mTopViewHeight;
|
||||
|
||||
if (y != getScrollY())
|
||||
super.scrollTo(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void computeScroll() {
|
||||
if (mScroller.computeScrollOffset()) {
|
||||
scrollTo(0, mScroller.getCurrY());
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,888 @@
|
||||
package com.jcodecraeer.xrecyclerview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
|
||||
import com.google.android.material.appbar.AppBarLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
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 static com.jcodecraeer.xrecyclerview.BaseRefreshHeader.STATE_DONE;
|
||||
|
||||
public class XRecyclerView extends RecyclerView {
|
||||
private boolean isLoadingData = false;
|
||||
private boolean isNoMore = false;
|
||||
private int mRefreshProgressStyle = ProgressStyle.SysProgress;
|
||||
private int mLoadingMoreProgressStyle = ProgressStyle.SysProgress;
|
||||
private ArrayList<View> mHeaderViews = new ArrayList<>();
|
||||
private WrapAdapter mWrapAdapter;
|
||||
private float mLastY = -1;
|
||||
private static final float DRAG_RATE = 3;
|
||||
private CustomFooterViewCallBack footerViewCallBack;
|
||||
private LoadingListener mLoadingListener;
|
||||
private ArrowRefreshHeader mRefreshHeader;
|
||||
private boolean pullRefreshEnabled = true;
|
||||
private boolean loadingMoreEnabled = true;
|
||||
//下面的ItemViewType是保留值(ReservedItemViewType),如果用户的adapter与它们重复将会强制抛出异常。不过为了简化,我们检测到重复时对用户的提示是ItemViewType必须小于10000
|
||||
private static final int TYPE_REFRESH_HEADER = 10000;//设置一个很大的数字,尽可能避免和用户的adapter冲突
|
||||
private static final int TYPE_FOOTER = 10001;
|
||||
private static final int HEADER_INIT_INDEX = 10002;
|
||||
private static List<Integer> sHeaderTypes = new ArrayList<>();//每个header必须有不同的type,不然滚动的时候顺序会变化
|
||||
|
||||
//adapter没有数据的时候显示,类似于listView的emptyView
|
||||
private View mEmptyView;
|
||||
private View mFootView;
|
||||
private final RecyclerView.AdapterDataObserver mDataObserver = new DataObserver();
|
||||
private AppBarStateChangeListener.State appbarState = AppBarStateChangeListener.State.EXPANDED;
|
||||
|
||||
// limit number to call load more
|
||||
// 控制多出多少条的时候调用 onLoadMore
|
||||
private int limitNumberToCallLoadMore = 1;
|
||||
|
||||
public XRecyclerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public XRecyclerView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public XRecyclerView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (pullRefreshEnabled) {
|
||||
mRefreshHeader = new ArrowRefreshHeader(getContext());
|
||||
mRefreshHeader.setProgressStyle(mRefreshProgressStyle);
|
||||
}
|
||||
LoadingMoreFooter footView = new LoadingMoreFooter(getContext());
|
||||
footView.setProgressStyle(mLoadingMoreProgressStyle);
|
||||
mFootView = footView;
|
||||
mFootView.setVisibility(GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* call it when you finish the activity,
|
||||
* when you call this,better don't call some kind of functions like
|
||||
* RefreshHeader,because the reference of mHeaderViews is NULL.
|
||||
*/
|
||||
public void destroy(){
|
||||
if(mHeaderViews != null){
|
||||
mHeaderViews.clear();
|
||||
mHeaderViews = null;
|
||||
}
|
||||
if(mFootView instanceof LoadingMoreFooter){
|
||||
((LoadingMoreFooter) mFootView).destroy();
|
||||
mFootView = null;
|
||||
}
|
||||
if(mRefreshHeader != null){
|
||||
mRefreshHeader.destroy();
|
||||
mRefreshHeader = null;
|
||||
}
|
||||
}
|
||||
|
||||
public ArrowRefreshHeader getDefaultRefreshHeaderView(){
|
||||
if(mRefreshHeader == null){
|
||||
return null;
|
||||
}
|
||||
return mRefreshHeader;
|
||||
}
|
||||
|
||||
public LoadingMoreFooter getDefaultFootView(){
|
||||
if(mFootView == null){
|
||||
return null;
|
||||
}
|
||||
if(mFootView instanceof LoadingMoreFooter){
|
||||
return ((LoadingMoreFooter) mFootView);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// set the number to control call load more,see the demo on linearActivity
|
||||
public void setLimitNumberToCallLoadMore(int limitNumberToCallLoadMore) {
|
||||
this.limitNumberToCallLoadMore = limitNumberToCallLoadMore;
|
||||
}
|
||||
|
||||
public View getFootView(){
|
||||
return mFootView;
|
||||
}
|
||||
|
||||
public void setFootViewText(String loading, String noMore) {
|
||||
if(mFootView instanceof LoadingMoreFooter){
|
||||
((LoadingMoreFooter) mFootView).setLoadingHint(loading);
|
||||
((LoadingMoreFooter) mFootView).setNoMoreHint(noMore);
|
||||
}
|
||||
}
|
||||
|
||||
public void addHeaderView(View view) {
|
||||
if(mHeaderViews == null || sHeaderTypes == null)
|
||||
return;
|
||||
sHeaderTypes.add(HEADER_INIT_INDEX + mHeaderViews.size());
|
||||
mHeaderViews.add(view);
|
||||
if (mWrapAdapter != null) {
|
||||
mWrapAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
//根据header的ViewType判断是哪个header
|
||||
private View getHeaderViewByType(int itemType) {
|
||||
if(!isHeaderType(itemType)) {
|
||||
return null;
|
||||
}
|
||||
if(mHeaderViews == null)
|
||||
return null;
|
||||
return mHeaderViews.get(itemType - HEADER_INIT_INDEX);
|
||||
}
|
||||
|
||||
//判断一个type是否为HeaderType
|
||||
private boolean isHeaderType(int itemViewType) {
|
||||
if(mHeaderViews == null || sHeaderTypes == null)
|
||||
return false;
|
||||
return mHeaderViews.size() > 0 && sHeaderTypes.contains(itemViewType);
|
||||
}
|
||||
|
||||
//判断是否是XRecyclerView保留的itemViewType
|
||||
private boolean isReservedItemViewType(int itemViewType) {
|
||||
if(itemViewType == TYPE_REFRESH_HEADER || itemViewType == TYPE_FOOTER || sHeaderTypes.contains(itemViewType)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public void setFootView(@NonNull final View view, @NonNull CustomFooterViewCallBack footerViewCallBack) {
|
||||
if(view == null || footerViewCallBack == null){
|
||||
return;
|
||||
}
|
||||
mFootView = view;
|
||||
this.footerViewCallBack = footerViewCallBack;
|
||||
}
|
||||
|
||||
public void loadMoreComplete() {
|
||||
isLoadingData = false;
|
||||
if (mFootView instanceof LoadingMoreFooter) {
|
||||
((LoadingMoreFooter) mFootView).setState(LoadingMoreFooter.STATE_COMPLETE);
|
||||
} else {
|
||||
if(footerViewCallBack != null){
|
||||
footerViewCallBack.onLoadMoreComplete(mFootView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setNoMore(boolean noMore){
|
||||
isLoadingData = false;
|
||||
isNoMore = noMore;
|
||||
if (mFootView instanceof LoadingMoreFooter) {
|
||||
((LoadingMoreFooter) mFootView).setState(isNoMore ? LoadingMoreFooter.STATE_NOMORE:LoadingMoreFooter.STATE_COMPLETE);
|
||||
} else {
|
||||
if(footerViewCallBack != null){
|
||||
footerViewCallBack.onSetNoMore(mFootView,noMore);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void refresh() {
|
||||
if (pullRefreshEnabled && mLoadingListener != null) {
|
||||
mRefreshHeader.setState(ArrowRefreshHeader.STATE_REFRESHING);
|
||||
mLoadingListener.onRefresh();
|
||||
}
|
||||
}
|
||||
public void reset(){
|
||||
setNoMore(false);
|
||||
loadMoreComplete();
|
||||
refreshComplete();
|
||||
}
|
||||
|
||||
public void refreshComplete() {
|
||||
if(mRefreshHeader != null)
|
||||
mRefreshHeader.refreshComplete();
|
||||
setNoMore(false);
|
||||
}
|
||||
|
||||
public void setRefreshHeader(ArrowRefreshHeader refreshHeader) {
|
||||
mRefreshHeader = refreshHeader;
|
||||
}
|
||||
|
||||
public void setPullRefreshEnabled(boolean enabled) {
|
||||
pullRefreshEnabled = enabled;
|
||||
}
|
||||
|
||||
public void setLoadingMoreEnabled(boolean enabled) {
|
||||
loadingMoreEnabled = enabled;
|
||||
if (!enabled) {
|
||||
if (mFootView instanceof LoadingMoreFooter) {
|
||||
((LoadingMoreFooter)mFootView).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 (mFootView instanceof LoadingMoreFooter) {
|
||||
((LoadingMoreFooter) mFootView).setProgressStyle(style);
|
||||
}
|
||||
}
|
||||
|
||||
public void setArrowImageView(int resId) {
|
||||
if (mRefreshHeader != null) {
|
||||
mRefreshHeader.setArrowImageView(resId);
|
||||
}
|
||||
}
|
||||
|
||||
// if you can't sure that you are 100% going to
|
||||
// have no data load back from server anymore,do not use this
|
||||
@Deprecated
|
||||
public void setEmptyView(View emptyView) {
|
||||
this.mEmptyView = emptyView;
|
||||
mDataObserver.onChanged();
|
||||
}
|
||||
|
||||
public View getEmptyView() {
|
||||
return mEmptyView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdapter(Adapter adapter) {
|
||||
mWrapAdapter = new WrapAdapter(adapter);
|
||||
super.setAdapter(mWrapAdapter);
|
||||
adapter.registerAdapterDataObserver(mDataObserver);
|
||||
mDataObserver.onChanged();
|
||||
}
|
||||
|
||||
//避免用户自己调用getAdapter() 引起的ClassCastException
|
||||
@Override
|
||||
public Adapter getAdapter() {
|
||||
if(mWrapAdapter != null)
|
||||
return mWrapAdapter.getOriginalAdapter();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLayoutManager(LayoutManager layout) {
|
||||
super.setLayoutManager(layout);
|
||||
if(mWrapAdapter != null){
|
||||
if (layout instanceof GridLayoutManager) {
|
||||
final GridLayoutManager gridManager = ((GridLayoutManager) layout);
|
||||
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
|
||||
@Override
|
||||
public int getSpanSize(int position) {
|
||||
return (mWrapAdapter.isHeader(position) || mWrapAdapter.isFooter(position) || mWrapAdapter.isRefreshHeader(position))
|
||||
? gridManager.getSpanCount() : 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** ===================== try to adjust the position for XR when you call those functions below ====================== */
|
||||
// which cause "Called attach on a child which is not detached" exception info.
|
||||
// {reason analyze @link:http://www.cnblogs.com/linguanh/p/5348510.html}
|
||||
// by lgh on 2017-11-13 23:55
|
||||
|
||||
// example: listData.remove(position); You can also see a demo on LinearActivity
|
||||
public<T> void notifyItemRemoved(List<T> listData,int position) {
|
||||
if(mWrapAdapter.adapter == null)
|
||||
return;
|
||||
int headerSize = getHeaders_includingRefreshCount();
|
||||
int adjPos = position + headerSize;
|
||||
mWrapAdapter.adapter.notifyItemRemoved(adjPos);
|
||||
mWrapAdapter.adapter.notifyItemRangeChanged(headerSize, listData.size(),new Object());
|
||||
}
|
||||
|
||||
public<T> void notifyItemInserted(List<T> listData,int position) {
|
||||
if(mWrapAdapter.adapter == null)
|
||||
return;
|
||||
int headerSize = getHeaders_includingRefreshCount();
|
||||
int adjPos = position + headerSize;
|
||||
mWrapAdapter.adapter.notifyItemInserted(adjPos);
|
||||
mWrapAdapter.adapter.notifyItemRangeChanged(headerSize, listData.size(),new Object());
|
||||
}
|
||||
|
||||
public void notifyItemChanged(int position) {
|
||||
if(mWrapAdapter.adapter == null)
|
||||
return;
|
||||
int adjPos = position + getHeaders_includingRefreshCount();
|
||||
mWrapAdapter.adapter.notifyItemChanged(adjPos);
|
||||
}
|
||||
|
||||
public void notifyItemChanged(int position,Object o) {
|
||||
if(mWrapAdapter.adapter == null)
|
||||
return;
|
||||
int adjPos = position + getHeaders_includingRefreshCount();
|
||||
mWrapAdapter.adapter.notifyItemChanged(adjPos,o);
|
||||
}
|
||||
|
||||
private int getHeaders_includingRefreshCount(){
|
||||
return mWrapAdapter.getHeadersCount()+1;
|
||||
}
|
||||
|
||||
/** ======================================================= end ======================================================= */
|
||||
|
||||
@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();
|
||||
}
|
||||
int adjAdapterItemCount = layoutManager.getItemCount()+getHeaders_includingRefreshCount();
|
||||
Log.e("aaaaa","adjAdapterItemCount "+adjAdapterItemCount +" getItemCount "+layoutManager.getItemCount());
|
||||
|
||||
int status = STATE_DONE;
|
||||
|
||||
if(mRefreshHeader != null)
|
||||
status = mRefreshHeader.getState();
|
||||
if (
|
||||
layoutManager.getChildCount() > 0
|
||||
&& lastVisibleItemPosition >= adjAdapterItemCount - limitNumberToCallLoadMore
|
||||
&& adjAdapterItemCount >= layoutManager.getChildCount()
|
||||
&& !isNoMore
|
||||
&& status < ArrowRefreshHeader.STATE_REFRESHING
|
||||
)
|
||||
{
|
||||
isLoadingData = true;
|
||||
if (mFootView instanceof LoadingMoreFooter) {
|
||||
((LoadingMoreFooter) mFootView).setState(LoadingMoreFooter.STATE_LOADING);
|
||||
} else {
|
||||
if(footerViewCallBack != null){
|
||||
footerViewCallBack.onLoadingMore(mFootView);
|
||||
}
|
||||
}
|
||||
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() && pullRefreshEnabled && appbarState == AppBarStateChangeListener.State.EXPANDED) {
|
||||
if(mRefreshHeader == null)
|
||||
break;
|
||||
mRefreshHeader.onMove(deltaY / DRAG_RATE);
|
||||
if (mRefreshHeader.getVisibleHeight() > 0 && mRefreshHeader.getState() < ArrowRefreshHeader.STATE_REFRESHING) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mLastY = -1; // reset
|
||||
if (isOnTop() && pullRefreshEnabled && appbarState == AppBarStateChangeListener.State.EXPANDED) {
|
||||
if (mRefreshHeader != null && 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() {
|
||||
if(mRefreshHeader == null)
|
||||
return false;
|
||||
if (mRefreshHeader.getParent() != null) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class DataObserver extends RecyclerView.AdapterDataObserver {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
if (mWrapAdapter != null) {
|
||||
mWrapAdapter.notifyDataSetChanged();
|
||||
}
|
||||
if (mWrapAdapter != null && mEmptyView != null) {
|
||||
int emptyCount = 1 + mWrapAdapter.getHeadersCount();
|
||||
if (loadingMoreEnabled) {
|
||||
emptyCount++;
|
||||
}
|
||||
if (mWrapAdapter.getItemCount() == emptyCount) {
|
||||
mEmptyView.setVisibility(View.VISIBLE);
|
||||
XRecyclerView.this.setVisibility(View.GONE);
|
||||
} else {
|
||||
mEmptyView.setVisibility(View.GONE);
|
||||
XRecyclerView.this.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
};
|
||||
|
||||
private class WrapAdapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
|
||||
private RecyclerView.Adapter adapter;
|
||||
|
||||
public WrapAdapter(RecyclerView.Adapter adapter) {
|
||||
this.adapter = adapter;
|
||||
}
|
||||
|
||||
public RecyclerView.Adapter getOriginalAdapter(){
|
||||
return this.adapter;
|
||||
}
|
||||
|
||||
public boolean isHeader(int position) {
|
||||
if(mHeaderViews == null)
|
||||
return false;
|
||||
return position >= 1 && position < mHeaderViews.size() + 1;
|
||||
}
|
||||
|
||||
public boolean isFooter(int position) {
|
||||
if(loadingMoreEnabled) {
|
||||
return position == getItemCount() - 1;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRefreshHeader(int position) {
|
||||
return position == 0;
|
||||
}
|
||||
|
||||
public int getHeadersCount() {
|
||||
if(mHeaderViews == null)
|
||||
return 0;
|
||||
return mHeaderViews.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
if (viewType == TYPE_REFRESH_HEADER) {
|
||||
return new SimpleViewHolder(mRefreshHeader);
|
||||
} else if (isHeaderType(viewType)) {
|
||||
return new SimpleViewHolder(getHeaderViewByType(viewType));
|
||||
} else if (viewType == TYPE_FOOTER) {
|
||||
return new SimpleViewHolder(mFootView);
|
||||
}
|
||||
return adapter.onCreateViewHolder(parent, viewType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
||||
if (isHeader(position) || isRefreshHeader(position)) {
|
||||
return;
|
||||
}
|
||||
int adjPosition = position - (getHeadersCount() + 1);
|
||||
int adapterCount;
|
||||
if (adapter != null) {
|
||||
adapterCount = adapter.getItemCount();
|
||||
if (adjPosition < adapterCount) {
|
||||
adapter.onBindViewHolder(holder, adjPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// some times we need to override this
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position,List<Object> payloads) {
|
||||
if (isHeader(position) || isRefreshHeader(position)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int adjPosition = position - (getHeadersCount() + 1);
|
||||
int adapterCount;
|
||||
if (adapter != null) {
|
||||
adapterCount = adapter.getItemCount();
|
||||
if (adjPosition < adapterCount) {
|
||||
if(payloads.isEmpty()){
|
||||
adapter.onBindViewHolder(holder, adjPosition);
|
||||
}
|
||||
else{
|
||||
adapter.onBindViewHolder(holder, adjPosition,payloads);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
int adjLen = (loadingMoreEnabled?2:1);
|
||||
if (adapter != null) {
|
||||
return getHeadersCount() + adapter.getItemCount() + adjLen;
|
||||
} else {
|
||||
return getHeadersCount() + adjLen;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
int adjPosition = position - (getHeadersCount() + 1);
|
||||
if (isRefreshHeader(position)) {
|
||||
return TYPE_REFRESH_HEADER;
|
||||
}
|
||||
if (isHeader(position)) {
|
||||
position = position - 1;
|
||||
return sHeaderTypes.get(position);
|
||||
}
|
||||
if (isFooter(position)) {
|
||||
return TYPE_FOOTER;
|
||||
}
|
||||
int adapterCount;
|
||||
if (adapter != null) {
|
||||
adapterCount = adapter.getItemCount();
|
||||
if (adjPosition < adapterCount) {
|
||||
int type = adapter.getItemViewType(adjPosition);
|
||||
if(isReservedItemViewType(type)) {
|
||||
throw new IllegalStateException("XRecyclerView require itemViewType in adapter should be less than 10000 " );
|
||||
}
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
if (adapter != null && position >= getHeadersCount() + 1) {
|
||||
int adjPosition = position - (getHeadersCount() + 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(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 RecyclerView.ViewHolder {
|
||||
public SimpleViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setLoadingListener(LoadingListener listener) {
|
||||
mLoadingListener = listener;
|
||||
}
|
||||
|
||||
public interface LoadingListener {
|
||||
|
||||
void onRefresh();
|
||||
|
||||
void onLoadMore();
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
|
||||
|
||||
private Drawable mDivider;
|
||||
private int mOrientation;
|
||||
|
||||
/**
|
||||
* Sole constructor. Takes in a {@link Drawable} to be used as the interior
|
||||
* divider.
|
||||
*
|
||||
* @param divider A divider {@code Drawable} to be drawn on the RecyclerView
|
||||
*/
|
||||
public DividerItemDecoration(Drawable divider) {
|
||||
mDivider = divider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws horizontal or vertical dividers onto the parent RecyclerView.
|
||||
*
|
||||
* @param canvas The {@link Canvas} onto which dividers will be drawn
|
||||
* @param parent The RecyclerView onto which dividers are being added
|
||||
* @param state The current RecyclerView.State of the RecyclerView
|
||||
*/
|
||||
@Override
|
||||
public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) {
|
||||
if (mOrientation == LinearLayoutManager.HORIZONTAL) {
|
||||
drawHorizontalDividers(canvas, parent);
|
||||
} else if (mOrientation == LinearLayoutManager.VERTICAL) {
|
||||
drawVerticalDividers(canvas, parent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the size and location of offsets between items in the parent
|
||||
* RecyclerView.
|
||||
*
|
||||
* @param outRect The {@link Rect} of offsets to be added around the child
|
||||
* view
|
||||
* @param view The child view to be decorated with an offset
|
||||
* @param parent The RecyclerView onto which dividers are being added
|
||||
* @param state The current RecyclerView.State of the RecyclerView
|
||||
*/
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
||||
super.getItemOffsets(outRect, view, parent, state);
|
||||
|
||||
if (parent.getChildAdapterPosition(view) <= mWrapAdapter.getHeadersCount() + 1) {
|
||||
return;
|
||||
}
|
||||
mOrientation = ((LinearLayoutManager) parent.getLayoutManager()).getOrientation();
|
||||
if (mOrientation == LinearLayoutManager.HORIZONTAL) {
|
||||
outRect.left = mDivider.getIntrinsicWidth();
|
||||
} else if (mOrientation == LinearLayoutManager.VERTICAL) {
|
||||
outRect.top = mDivider.getIntrinsicHeight();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds dividers to a RecyclerView with a LinearLayoutManager or its
|
||||
* subclass oriented horizontally.
|
||||
*
|
||||
* @param canvas The {@link Canvas} onto which horizontal dividers will be
|
||||
* drawn
|
||||
* @param parent The RecyclerView onto which horizontal dividers are being
|
||||
* added
|
||||
*/
|
||||
private void drawHorizontalDividers(Canvas canvas, RecyclerView parent) {
|
||||
int parentTop = parent.getPaddingTop();
|
||||
int parentBottom = parent.getHeight() - parent.getPaddingBottom();
|
||||
|
||||
int childCount = parent.getChildCount();
|
||||
for (int i = 0; i < childCount - 1; i++) {
|
||||
View child = parent.getChildAt(i);
|
||||
|
||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
|
||||
int parentLeft = child.getRight() + params.rightMargin;
|
||||
int parentRight = parentLeft + mDivider.getIntrinsicWidth();
|
||||
|
||||
mDivider.setBounds(parentLeft, parentTop, parentRight, parentBottom);
|
||||
mDivider.draw(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds dividers to a RecyclerView with a LinearLayoutManager or its
|
||||
* subclass oriented vertically.
|
||||
*
|
||||
* @param canvas The {@link Canvas} onto which vertical dividers will be
|
||||
* drawn
|
||||
* @param parent The RecyclerView onto which vertical dividers are being
|
||||
* added
|
||||
*/
|
||||
private void drawVerticalDividers(Canvas canvas, RecyclerView parent) {
|
||||
int parentLeft = parent.getPaddingLeft();
|
||||
int parentRight = parent.getWidth() - parent.getPaddingRight();
|
||||
|
||||
int childCount = parent.getChildCount();
|
||||
for (int i = 0; i < childCount - 1; i++) {
|
||||
View child = parent.getChildAt(i);
|
||||
|
||||
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
|
||||
int parentTop = child.getBottom() + params.bottomMargin;
|
||||
int parentBottom = parentTop + mDivider.getIntrinsicHeight();
|
||||
|
||||
mDivider.setBounds(parentLeft, parentTop, parentRight, parentBottom);
|
||||
mDivider.draw(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** add by LinGuanHong below */
|
||||
private int scrollDyCounter = 0;
|
||||
|
||||
@Override
|
||||
public void scrollToPosition(int position) {
|
||||
super.scrollToPosition(position);
|
||||
/** if we scroll to position 0, the scrollDyCounter should be reset */
|
||||
if(position == 0){
|
||||
scrollDyCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScrolled(int dx, int dy) {
|
||||
super.onScrolled(dx, dy);
|
||||
if(scrollAlphaChangeListener == null){
|
||||
return;
|
||||
}
|
||||
int height = scrollAlphaChangeListener.setLimitHeight();
|
||||
scrollDyCounter = scrollDyCounter + dy;
|
||||
if (scrollDyCounter <= 0) {
|
||||
scrollAlphaChangeListener.onAlphaChange(0);
|
||||
}else if(scrollDyCounter <= height && scrollDyCounter > 0){
|
||||
float scale = (float) scrollDyCounter / height; /** 255/height = x/255 */
|
||||
float alpha = (255 * scale);
|
||||
scrollAlphaChangeListener.onAlphaChange((int) alpha);
|
||||
}else {
|
||||
scrollAlphaChangeListener.onAlphaChange(255);
|
||||
}
|
||||
}
|
||||
|
||||
private ScrollAlphaChangeListener scrollAlphaChangeListener;
|
||||
public void setScrollAlphaChangeListener(
|
||||
ScrollAlphaChangeListener scrollAlphaChangeListener
|
||||
){
|
||||
this.scrollAlphaChangeListener = scrollAlphaChangeListener;
|
||||
}
|
||||
public interface ScrollAlphaChangeListener{
|
||||
void onAlphaChange(int alpha); /** you can handle the alpha insert it */
|
||||
int setLimitHeight(); /** set a height for the begging of the alpha start to change */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
package com.jcodecraeer.xrecyclerview.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 android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import com.jcodecraeer.xrecyclerview.R;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallBeatIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallClipRotateIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallClipRotateMultipleIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallClipRotatePulseIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallGridBeatIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallGridPulseIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallPulseIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallPulseRiseIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallPulseSyncIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallRotateIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallScaleIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallScaleMultipleIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallScaleRippleIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallScaleRippleMultipleIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallSpinFadeLoaderIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallTrianglePathIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallZigZagDeflectIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BallZigZagIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.BaseIndicatorController;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.CubeTransitionIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.LineScaleIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.LineScalePartyIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.LineScalePulseOutIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.LineScalePulseOutRapidIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.LineSpinFadeLoaderIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.PacmanIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.SemiCircleSpinIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.SquareSpinIndicator;
|
||||
import com.jcodecraeer.xrecyclerview.progressindicator.indicator.TriangleSkewSpinIndicator;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/15
|
||||
*
|
||||
.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);
|
||||
}
|
||||
|
||||
public void destroy(){
|
||||
mHasAnimation = true;
|
||||
if(mIndicatorController != null){
|
||||
mIndicatorController.destroy();
|
||||
mIndicatorController = null;
|
||||
}
|
||||
mPaint = null;
|
||||
}
|
||||
|
||||
@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(mIndicatorController == null)
|
||||
return;
|
||||
if (v == GONE || v == INVISIBLE) {
|
||||
mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.END);
|
||||
} else {
|
||||
mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.START);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if(mIndicatorController == null)
|
||||
return;
|
||||
mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.CANCEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
if(mIndicatorController == null)
|
||||
return;
|
||||
mIndicatorController.setAnimationStatus(BaseIndicatorController.AnimStatus.START);
|
||||
}
|
||||
|
||||
void drawIndicator(Canvas canvas){
|
||||
if(mIndicatorController == null)
|
||||
return;
|
||||
mIndicatorController.draw(canvas, mPaint);
|
||||
}
|
||||
|
||||
void applyAnimation(){
|
||||
if(mIndicatorController == null)
|
||||
return;
|
||||
mIndicatorController.initAnimation();
|
||||
}
|
||||
|
||||
private int dp2px(int dpValue) {
|
||||
return (int) getContext().getResources().getDisplayMetrics().density * dpValue;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.jcodecraeer.xrecyclerview.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 com.jcodecraeer.xrecyclerview.progressindicator.indicator.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.jcodecraeer.xrecyclerview.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/16.
|
||||
*/
|
||||
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.jcodecraeer.xrecyclerview.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/17.
|
||||
*/
|
||||
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.jcodecraeer.xrecyclerview.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/16.
|
||||
*/
|
||||
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.jcodecraeer.xrecyclerview.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/20.
|
||||
*/
|
||||
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.jcodecraeer.xrecyclerview.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/16.
|
||||
*/
|
||||
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.jcodecraeer.xrecyclerview.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/16.
|
||||
*/
|
||||
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.jcodecraeer.xrecyclerview.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/17.
|
||||
*/
|
||||
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.jcodecraeer.xrecyclerview.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.jcodecraeer.xrecyclerview.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/17.
|
||||
*/
|
||||
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.jcodecraeer.xrecyclerview.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.jcodecraeer.xrecyclerview.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.jcodecraeer.xrecyclerview.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.jcodecraeer.xrecyclerview.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.jcodecraeer.xrecyclerview.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/20.
|
||||
*/
|
||||
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.jcodecraeer.xrecyclerview.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,64 @@
|
||||
package com.jcodecraeer.xrecyclerview.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 com.jcodecraeer.xrecyclerview.progressindicator.indicator.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.jcodecraeer.xrecyclerview.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,127 @@
|
||||
package com.jcodecraeer.xrecyclerview.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/15.
|
||||
*/
|
||||
public abstract class BaseIndicatorController {
|
||||
|
||||
|
||||
private View mTarget;
|
||||
|
||||
private List<Animator> mAnimators;
|
||||
|
||||
public void destroy(){
|
||||
mTarget = null;
|
||||
releaseAnimations();
|
||||
mAnimators = null;
|
||||
}
|
||||
|
||||
public void setTarget(View target){
|
||||
this.mTarget=target;
|
||||
}
|
||||
|
||||
public View getTarget(){
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
|
||||
public int getWidth(){
|
||||
if(mTarget == null){
|
||||
return 0;
|
||||
}
|
||||
return mTarget.getWidth();
|
||||
}
|
||||
|
||||
public int getHeight(){
|
||||
if(mTarget == null){
|
||||
return 0;
|
||||
}
|
||||
return mTarget.getHeight();
|
||||
}
|
||||
|
||||
public void postInvalidate(){
|
||||
if(mTarget != null){
|
||||
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();
|
||||
}
|
||||
|
||||
// add by lgh
|
||||
private void releaseAnimations(){
|
||||
if (mAnimators==null){
|
||||
return;
|
||||
}
|
||||
int count=mAnimators.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
Animator animator = mAnimators.get(i);
|
||||
animator.cancel();
|
||||
animator.removeAllListeners();
|
||||
}
|
||||
mAnimators.clear();
|
||||
mAnimators = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.jcodecraeer.xrecyclerview.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/18.
|
||||
*/
|
||||
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.jcodecraeer.xrecyclerview.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.jcodecraeer.xrecyclerview.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.jcodecraeer.xrecyclerview.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.jcodecraeer.xrecyclerview.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,30 @@
|
||||
package com.jcodecraeer.xrecyclerview.progressindicator.indicator;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
|
||||
/**
|
||||
* Created by Jack on 2015/10/24.
|
||||
* Email:81813780@qq.com
|
||||
*/
|
||||
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.jcodecraeer.xrecyclerview.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/16.
|
||||
*/
|
||||
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.jcodecraeer.xrecyclerview.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/20.
|
||||
*/
|
||||
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.jcodecraeer.xrecyclerview.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/16.
|
||||
*/
|
||||
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.jcodecraeer.xrecyclerview.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/20.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
BIN
xrecyclerview/src/main/res/drawable-hdpi/ic_loading_rotate.png
Normal file
|
After Width: | Height: | Size: 444 B |
|
After Width: | Height: | Size: 1.4 KiB |
BIN
xrecyclerview/src/main/res/drawable-hdpi/loading_01.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
xrecyclerview/src/main/res/drawable-hdpi/loading_02.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
xrecyclerview/src/main/res/drawable-hdpi/loading_03.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
xrecyclerview/src/main/res/drawable-hdpi/loading_04.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
xrecyclerview/src/main/res/drawable-hdpi/loading_05.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
xrecyclerview/src/main/res/drawable-hdpi/loading_06.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
xrecyclerview/src/main/res/drawable-hdpi/loading_07.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
xrecyclerview/src/main/res/drawable-hdpi/loading_08.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
xrecyclerview/src/main/res/drawable-hdpi/loading_09.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
xrecyclerview/src/main/res/drawable-hdpi/loading_10.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
xrecyclerview/src/main/res/drawable-hdpi/loading_11.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
xrecyclerview/src/main/res/drawable-hdpi/loading_12.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
16
xrecyclerview/src/main/res/drawable-hdpi/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="@drawable/loading_01" />
|
||||
<item android:duration="100" android:drawable="@drawable/loading_02" />
|
||||
<item android:duration="100" android:drawable="@drawable/loading_03" />
|
||||
<item android:duration="100" android:drawable="@drawable/loading_04" />
|
||||
<item android:duration="100" android:drawable="@drawable/loading_05" />
|
||||
<item android:duration="100" android:drawable="@drawable/loading_06" />
|
||||
<item android:duration="100" android:drawable="@drawable/loading_07" />
|
||||
<item android:duration="100" android:drawable="@drawable/loading_08" />
|
||||
<item android:duration="100" android:drawable="@drawable/loading_09" />
|
||||
<item android:duration="100" android:drawable="@drawable/loading_10" />
|
||||
<item android:duration="100" android:drawable="@drawable/loading_11" />
|
||||
<item android:duration="100" android:drawable="@drawable/loading_12" />
|
||||
</animation-list>
|
||||
3
xrecyclerview/src/main/res/drawable/progressloading.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animated-rotate android:drawable="@drawable/ic_loading_rotate" android:pivotX="50.0%" android:pivotY="50.0%"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" />
|
||||
21
xrecyclerview/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>
|
||||
71
xrecyclerview/src/main/res/layout/listview_header.xml
Normal file
@@ -0,0 +1,71 @@
|
||||
<?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:id="@+id/header_refresh_time_container"
|
||||
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="@drawable/ic_pulltorefresh_arrow" />
|
||||
|
||||
<com.jcodecraeer.xrecyclerview.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>
|
||||
73
xrecyclerview/src/main/res/layout/pull_to_refresh_head.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?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="fill_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/head_contentLayout"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:paddingTop="10dip"
|
||||
android:paddingBottom="15dip">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="30dip"
|
||||
android:layout_marginRight="20dip">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/head_arrowImageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:src="@drawable/ic_pulltorefresh_arrow" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="100dip"
|
||||
android:layout_marginRight="10dip">
|
||||
<ImageView
|
||||
android:id="@+id/head_progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/progressbar"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/head_tipsTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/listview_header_hint_normal"
|
||||
android:textColor="#000000"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/head_lastUpdatedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#000000"
|
||||
android:textSize="10sp" />
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
10
xrecyclerview/src/main/res/values-zh/strings.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<resources>
|
||||
<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="loading_done">加载完成</string>
|
||||
<string name="listview_header_last_time">上次更新时间:</string>
|
||||
</resources>
|
||||
38
xrecyclerview/src/main/res/values/attrs.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<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>
|
||||
|
||||
</resources>
|
||||
4
xrecyclerview/src/main/res/values/dimens.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<resources>
|
||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||
<dimen name="textandiconmargin">10dp</dimen>
|
||||
</resources>
|
||||
10
xrecyclerview/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,10 @@
|
||||
<resources>
|
||||
<string name="listview_header_hint_normal">pull to refresh</string>
|
||||
<string name="listview_header_hint_release">release to start refresh</string>
|
||||
<string name="listview_loading">loading...</string>
|
||||
<string name="nomore_loading">no more to be loaded</string>
|
||||
<string name="refreshing">refreshing...</string>
|
||||
<string name="refresh_done">refresh done</string>
|
||||
<string name="loading_done">loading done</string>
|
||||
<string name="listview_header_last_time">last update:</string>
|
||||
</resources>
|
||||