垂直view page上拉加载更多 //这里是依赖垂直的viewpage的那个类的
/**
* 继承垂直的view page,实现最后一页弹性伸缩通知加载更多的功能
*/
public class LoadMoreViewPager extends VerticalViewPager {
// ===========================================================
// Constants
// ===========================================================
/**
* 控制弹性的最大的距离
*/
final static int DEFAULT_OVERSCROLL_TRANSLATION = 650;
/**
* 动画的时间
*/
final private static int DEFAULT_OVERSCROLL_ANIMATION_DURATION = 300;
private final static int INVALID_POINTER_ID = -1;
// ===========================================================
// Fields
// ===========================================================
final private OverscrollEffect mOverscrollEffect = new OverscrollEffect();
final private Camera mCamera = new Camera();
private OnPageChangeListener mScrollListener;
private float mLastMotionY;
private int mActivePointerId;
private int mScrollPosition;
private float mScrollPositionOffset;
final private int mTouchSlop;
private LoadMoreFromBounceViewPage loadMore;
//高度,默认是上面的150
private float mOverscrollTranslation;
//持续时间默认的是上面的400ms
private int mOverscrollAnimationDuration;
//用来过滤操作的
private boolean IsSend = false;
private boolean IsFromTouch = false;
private int mLastPosition = 0;
public LoadMoreViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
setStaticTransformationsEnabled(true);
final ViewConfiguration configuration = ViewConfiguration.get(context);
// getScaledTouchSlop是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件
mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
super.setOnPageChangeListener(new MyOnPageChangeListener());
init(attrs);
}
// ===========================================================
// Override Methods
// ===========================================================
@Override
public void setOnPageChangeListener(OnPageChangeListener listener) {
mScrollListener = listener;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
try {
return super.dispatchTouchEvent(ev);
} catch (IllegalArgumentException e) {
e.printStackTrace();
return false;
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
return false;
}
}
@Override
public void scrollBy(@Px int x, @Px int y) {
super.scrollBy(x, y);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean callSuper = false;
final int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN: {
callSuper = true;
mLastMotionY = ev.getY();
mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
break;
}
case MotionEvent.ACTION_MOVE: {
if (mActivePointerId != INVALID_POINTER_ID) {
// Scroll to follow the motion event
final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
final float y = MotionEventCompat.getY(ev, activePointerIndex);
final float deltay = mLastMotionY - y;
//对于view page永远getScrollY获取的值是0
//final float oldScrolly = getScrollY();
final int height = getHeight();
final int HeightWithMargin = height + getPageMargin();
final int lastItemIndex = getAdapter().getCount() - 1;
final int currentItemIndex = getCurrentItem();
final float bottom1Bound = Math.max(0, (currentItemIndex - 1) * HeightWithMargin);
float oldScrolly = (currentItemIndex) * HeightWithMargin + getTop();
final float top1Bound = Math.min(currentItemIndex + 1, lastItemIndex) * HeightWithMargin;
final float scrollY = oldScrolly + deltay;
if (mScrollPositionOffset == 0) {
if (scrollY < bottom1Bound) {
if (bottom1Bound == 0) {
final float over = deltay + mTouchSlop;
mOverscrollEffect.setPull(over / height);
//第一页下拉刷新
}
} else if (scrollY > top1Bound) {
//最后一个上拉加载更多
if (top1Bound == lastItemIndex * HeightWithMargin) {
final float over = scrollY - top1Bound - mTouchSlop;
// 在这里实现调用加载的动作,然后在监听里取消加载的图标的显示
// ((MainActivity) context1).show();
IsFromTouch = true;
mOverscrollEffect.setPull(over / height);
}
}
} else {
mLastMotionY = y;
}
} else {
mOverscrollEffect.onRelease();
}
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
callSuper = true;
mActivePointerId = INVALID_POINTER_ID;
mOverscrollEffect.onRelease();
break;
}
}
if (mOverscrollEffect.isOverScrolling() && !callSuper) {
return true;
} else {
return super.onTouchEvent(ev);
}
}
@Override
protected boolean getChildStaticTransformation(View child, Transformation t) {
if (child.getHeight() == 0) {
return false;
}
final int position = child.getTop() / child.getHeight();
final boolean isFirstOrLast = position == 0 || (position == getAdapter().getCount() - 1);
if (mOverscrollEffect.isOverScrolling() && isFirstOrLast) {
final float dx = getWidth() / 2;
final int dy = getHeight() / 2;
t.getMatrix().reset();
final float translateY = mOverscrollTranslation * (mOverscrollEffect.mOverscroll > 0 ? Math.min(mOverscrollEffect.mOverscroll, 1) : Math.max(mOverscrollEffect.mOverscroll, -1));
mCamera.save();
mCamera.translate(0, translateY, 0);
mCamera.getMatrix(t.getMatrix());
mCamera.restore();
//在这里通过矩阵的变换实现平移的操作,pre是前乘
t.getMatrix().preTranslate(-dx, -dy);
t.getMatrix().postTranslate(dx, dy);
if (getChildCount() == 1) {
this.invalidate();
} else {
child.invalidate();
}
return true;
}
return false;
}
// ===========================================================
// Define Methods
// ===========================================================
private void init(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.LoadMoreViewPager);
mOverscrollTranslation = a.getDimension(R.styleable.LoadMoreViewPager_overscroll_translation, DEFAULT_OVERSCROLL_TRANSLATION);
mOverscrollAnimationDuration = a.getInt(R.styleable.LoadMoreViewPager_overscroll_animation_duration, DEFAULT_OVERSCROLL_ANIMATION_DURATION);
a.recycle();
}
private void invalidateVisibleChilds() {
for (int i = 0; i < getChildCount(); i++) {
//请求重绘所有的Child
getChildAt(i).invalidate();
}
}
//设置需要刷新时候的操作
public void setLoadMorelisten(LoadMoreFromBounceViewPage loadMore) {
this.loadMore = loadMore;
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
/**
* 弹性的动画
*/
private class OverscrollEffect {
private float mOverscroll;
private Animator mAnimator;
/**
* 是否到尽头要开始动画了
*
* @param deltaDistance [0..1] 0->no overscroll, 1>full overscroll
*/
private void setPull(final float deltaDistance) {
mOverscroll = deltaDistance;
invalidateVisibleChilds();
}
/**
* 当手指离开的时候回调返回到原来的地方
*/
private void onRelease() {
if (mAnimator != null && mAnimator.isRunning()) {
mAnimator.cancel();
} else {
myStartAnimation(0);
}
}
private void myStartAnimation(final float target) {
//三个参数,操纵的view,动画名称,滑出去的位置,回来的位置
mAnimator = ObjectAnimator.ofFloat(this, "pull", mOverscroll, target);
mAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
if (IsSend && IsFromTouch) {
mAnimator.pause();
loadMore.loadMore();
IsSend = false;
IsFromTouch = false;
}
IsSend = true;
}
@Override
public void onAnimationCancel(Animator animation) {
IsSend = true;
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mAnimator.setInterpolator(new DecelerateInterpolator());
final float scale = Math.abs(target - mOverscroll);
mAnimator.setDuration((long) (mOverscrollAnimationDuration * scale));
mAnimator.start();
}
/**
* 这里判断是不是第一个或者最后一个
*
* @return true 是,否则不是
*/
private boolean isOverScrolling() {
/* if (mScrollPosition == 0 && mOverscroll < 0) {
return true;
}*/
if (getAdapter() != null) {//getAdapter容易为空导致下面crash
final boolean isLast = (getAdapter().getCount() - 1) == mScrollPosition;
if (isLast && mOverscroll > 0) {
return true;
}
return false;
}
return false;
}
}
private class MyOnPageChangeListener implements OnPageChangeListener {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (mScrollListener != null) {
mScrollListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
mScrollPosition = position;
mScrollPositionOffset = positionOffset;
mLastPosition = position;
//滑动的时候重新绘制一下
// invalidateVisibleChilds();
}
@Override
public void onPageSelected(int position) {
if (mScrollListener != null) {
mScrollListener.onPageSelected(position);
}
}
@Override
public void onPageScrollStateChanged(final int state) {
if (mScrollListener != null) {
mScrollListener.onPageScrollStateChanged(state);
}
if (state == SCROLL_STATE_IDLE) {
mScrollPositionOffset = 0;
}
}
}
// ===========================================================
// Getter & Setter
// ===========================================================
public int getOverscrollAnimationDuration() {
return mOverscrollAnimationDuration;
}
public void setOverscrollAnimationDuration(int mOverscrollAnimationDuration) {
this.mOverscrollAnimationDuration = mOverscrollAnimationDuration;
}
public float getOverscrollTranslation() {
return mOverscrollTranslation;
}
public void setOverscrollTranslation(int mOverscrollTranslation) {
this.mOverscrollTranslation = mOverscrollTranslation;
}
interface LoadMoreFromBounceViewPage {
void loadMore();
}
}
/////////////////////////////////////////////////////////
/**
* 封装好的一个垂直展示的view page里面有下拉加载更多
* 外界调用必须调用initViewPage()->setLoadMoreListen()->(各种设置非必选)->setAdapt()->处理完成后还得调一下loadFinish通知已经加载更多结束,方便控件进行关闭进度条类似的操作
* Created by hsp on 2017/8/11.
*/
public class MyViewPager extends RelativeLayout implements LoadMoreViewPager.LoadMoreFromBounceViewPage {
private LoadMoreViewPager mLoadMoreViewPager;
private TextView loadMoreText;
private ProgressBar loadMoreProgress;
private RelativeLayout mRelativeLayout;
//底部加载更多的时候显示的图片
private Context mContext;
private LoadMore loadMore;
private String defaultLoadMoreText = getResources().getString(R.string.main_activity_bottom_text);
private int defaultLoadMoreHeight = 0;
public MyViewPager(Context context) {
super(context);
mContext = context;
init();
}
public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MyViewPager);
if (!TextUtils.isEmpty(a.getString(R.styleable.MyViewPager_load_more_text))) {
defaultLoadMoreText = a.getString(R.styleable.MyViewPager_load_more_text);
}
defaultLoadMoreHeight = (int) a.getDimension(R.styleable.MyViewPager_load_more_height, defaultLoadMoreHeight);
a.recycle();
mContext = context;
init();
}
public MyViewPager(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
init();
}
@Override
public void loadMore() {
//从view page里传过来的要加载数据的操作
//我们在这里进行加载更多UI的操作,并且如果数据操作了就什么都不显示?感觉这个ui还是要activity层控制
mRelativeLayout.setVisibility(View.VISIBLE);
loadMore.loadMore();
}
// ===========================================================
// Define Methods
// ===========================================================
private void init() {
View.inflate(mContext, R.layout.my_viewpage_layout, this);
mLoadMoreViewPager = (LoadMoreViewPager) findViewById(R.id.my_viewpage_viewpager);
loadMoreText = (TextView) findViewById(R.id.my_viewpage_bottom_tv);
loadMoreProgress = (ProgressBar) findViewById(R.id.my_viewpage_bottom_progress);
mRelativeLayout = (RelativeLayout) findViewById(R.id.my_viewpage_bottom_rl);
reset();
}
public void initViewPage() {
mLoadMoreViewPager.setPageTransformer(true, new DefaultTransformer());
//禁止出现滑动的时候阴影效果
mLoadMoreViewPager.setOverScrollMode(View.OVER_SCROLL_NEVER);
mLoadMoreViewPager.setLoadMorelisten(this);
}
/**
* 在设置adapt之前可以设置各种属性
*
* @param adapter view page的适配器
*/
public void setAdapt(PagerAdapter adapter) {
loadMoreText.setText(defaultLoadMoreText);
ViewGroup.LayoutParams params = mRelativeLayout.getLayoutParams();
ViewGroup.MarginLayoutParams marginParams = null;
//获取view的margin设置参数
if (params instanceof ViewGroup.MarginLayoutParams) {
marginParams = (ViewGroup.MarginLayoutParams) params;
} else {
//不存在时创建一个新的参数
//基于View本身原有的布局参数对象
marginParams = new ViewGroup.MarginLayoutParams(params);
}
marginParams.setMargins(0, 0, 0, defaultLoadMoreHeight);
mRelativeLayout.setLayoutParams(params);
mLoadMoreViewPager.setAdapter(adapter);
}
//接收activity传过来的操作
public void setLoadMoreListen(LoadMore loadMore) {
this.loadMore = loadMore;
}
//这个是要传到activity层次的,给他们更新数据
public interface LoadMore {
void loadMore();
}
public void loadFinish() {
//关闭进度条,关闭动画效果
//先不要关
// mRelativeLayout.setVisibility(View.GONE);
}
// ===========================================================
// Getter & Setter
// ===========================================================
private void reset() {
if (loadMoreText != null) {
loadMoreText.setText(defaultLoadMoreText);
}
}
public void setNoMore() {
if (loadMoreText != null) {
loadMoreText.setText(getResources().getString(R.string.main_activity_no_more_text));
}
}
public void setCurrentItem(int position) {
if (mLoadMoreViewPager != null) {
mLoadMoreViewPager.setCurrentItem(position);
}
}
public LoadMoreViewPager getmLoadMoreViewPager() {
return mLoadMoreViewPager;
}
public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
if (mLoadMoreViewPager != null) {
mLoadMoreViewPager.setOnPageChangeListener(listener);
}
}
public String getDefaultLoadMoreText() {
return defaultLoadMoreText;
}
public void setLoadMoreText(String loadMoreText) {
this.defaultLoadMoreText = loadMoreText;
}
public int getDefaultLoadMoreHeight() {
return defaultLoadMoreHeight;
}
public void setLoadMoreHeight(int loadMoreHeight) {
this.defaultLoadMoreHeight = loadMoreHeight;
}
}
////////////////////////////////////////////////////////
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/my_viewpage_bottom_rl"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_alignParentBottom="true"
android:layout_marginBottom="0dp"
>
<ProgressBar
android:id="@+id/my_viewpage_bottom_progress"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_centerVertical="true"
android:layout_marginLeft="150dp" />
<TextView
android:id="@+id/my_viewpage_bottom_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignStart="@+id/my_viewpage_bottom_progress"
android:layout_centerVertical="true"
android:layout_marginLeft="50dp"
android:text="@string/main_activity_bottom_text" />
</RelativeLayout>
<com.example.meitu.feedtestproject.widget.LoadMoreViewPager
android:id="@+id/my_viewpage_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>