Android 日历实现简记

Android 日历实现简记_第1张图片
实现该界面,尝试过两种:

1.改造ViewPager
2.RecyclerView + 改造PagerSnapHelper

这里最后用了第二种。
尝试
记录下,实现该界面的历程:
第一种方法:
这里曾试着解决三个问题:

1).垂直滑动的ViewPager
2).一个界面显示多页
3).无限循环

1).垂直滑动的ViewPager
由于之前用ViewPager实现过一个界面显示多页的效果(水平方向上),所以,第一眼我觉得可以用ViewPager来实现。但是,后来发现要实现垂直方向滑动,需要改造ViewPager,实现垂直方向滑动的ViewPager采用了网上的做法:交换x,y的TouchEvent事件《30行代码,打造一个垂直的ViewPager》,感觉还是没有水平方向的好。。。

2).一个界面显示多页
在布局文件中配置ViewPager 和其父布局的 android:clipChildren属性为”false”(android:clipChildren表示是否限制子View在其范围内,默认为true),同时,其父布局添加android:layerType=”software”属性。但是需要设置layout_margin才有效果。
参考:ViewPager系列之ViewPager一屏显示多个子页面
但是滑动的时候又会只显示一个页面或者有闪屏的感觉。

3).实现无限循环
这里的无限循环是指:重复使用几个数据,然后滑动的时候不断更新这些数据,达到循环的感觉。
由于这里使用Fragment作为界面展示,且需要展示数据较多,因此这里Adapter继承的是FragmentStatePagerAdapter。
主要是先以下方法:

@Override
public int getCount() {
	return Integer.MAX_VALUE;
}
		
@Override
public Object instantiateItem(ViewGroup container, int position) {
	return super.instantiateItem(container,position % mRealCount);
}

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
	super.setPrimaryItem(container,position % mRealCount);
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
	super.destroyItem(container, position % mRealCount, object);
}

mRealCount 为数据的大小
采用这方方式,需要一开始先用ViewPager的setCurrentItem的方法,设置当前的页面为一个较大的数值,比如:Integer.MAX_VALUE / 2。

小结:感觉ViewPager更适合做水平方向,单页显示的。

第二种方法:
这里层试着解决:

1). 自定义SnapHelper
2). 无限循环

1).自定义SnapHelper:
这里直接附上目前可以顶部对齐并且回调对应位置的SnapHelper

import android.graphics.PointF;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.OrientationHelper;
import android.support.v7.widget.PagerSnapHelper;
import android.support.v7.widget.RecyclerView;
import android.view.View;

public class CustomPagerSnapHelper extends PagerSnapHelper {
    private OnPageListener mOnPageListener;
    private int mCurrentPosition = 0;
    @Nullable
    private OrientationHelper mVerticalHelper;
    @Nullable
    private OrientationHelper mHorizontalHelper;

    /**
     * 页面选择回调监听
     */
    public CustomPagerSnapHelper setOnPageListener(OnPageListener onPageListener) {
        mOnPageListener = onPageListener;
        return this;
    }

    @Nullable
    @Override
    public int[] calculateDistanceToFinalSnap(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView) {
        int[] out = new int[2];
        if (layoutManager.canScrollHorizontally()) {
            out[0] = this.distanceToStart(layoutManager, targetView, this.getHorizontalHelper(layoutManager));
        } else {
            out[0] = 0;
        }

        if (layoutManager.canScrollVertically()) {
            out[1] = this.distanceToStart(layoutManager, targetView, this.getVerticalHelper(layoutManager));
        } else {
            out[1] = 0;
        }
        RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) targetView.getLayoutParams();
        int position = params.getViewAdapterPosition();

        boolean isLastItem = position == layoutManager.getItemCount() - 1;

        if (mOnPageListener != null && mCurrentPosition != position && (out[0] == 0 || isLastItem)) {
            mOnPageListener.onPageSelected(mCurrentPosition = position);
        }

        return out;
    }

    @Override
    public View findSnapView(RecyclerView.LayoutManager layoutManager) {
        if (layoutManager.canScrollVertically()) {
            return this.findStartView(layoutManager, this.getVerticalHelper(layoutManager));
        } else {
            return layoutManager.canScrollHorizontally() ? this.findStartView(layoutManager, this.getHorizontalHelper(layoutManager)) : null;
        }
    }

    @Override
    public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
        int itemCount = layoutManager.getItemCount();
        if (itemCount == 0) {
            return -1;
        } else {
            View mStartMostChildView = null;
            if (layoutManager.canScrollVertically()) {
                mStartMostChildView = this.findStartView(layoutManager, this.getVerticalHelper(layoutManager));
            } else if (layoutManager.canScrollHorizontally()) {
                mStartMostChildView = this.findStartView(layoutManager, this.getHorizontalHelper(layoutManager));
            }

            if (mStartMostChildView == null) {
                return -1;
            } else {
                int centerPosition = layoutManager.getPosition(mStartMostChildView);
                if (centerPosition == -1) {
                    return -1;
                } else {
                    boolean forwardDirection;
                    if (layoutManager.canScrollHorizontally()) {
                        forwardDirection = velocityX > 0;
                    } else {
                        forwardDirection = velocityY > 0;
                    }

                    boolean reverseLayout = false;
                    if (layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider) {
                        RecyclerView.SmoothScroller.ScrollVectorProvider vectorProvider = (RecyclerView.SmoothScroller.ScrollVectorProvider)layoutManager;
                        PointF vectorForEnd = vectorProvider.computeScrollVectorForPosition(itemCount - 1);
                        if (vectorForEnd != null) {
                            reverseLayout = vectorForEnd.x < 0.0F || vectorForEnd.y < 0.0F;
                        }
                    }

                    return reverseLayout ? (forwardDirection ? centerPosition - 1 : centerPosition) : (forwardDirection ? centerPosition + 1 : centerPosition);
                }
            }
        }
    }

    private int distanceToStart(@NonNull RecyclerView.LayoutManager layoutManager, @NonNull View targetView, OrientationHelper helper) {
        int childStart = helper.getDecoratedStart(targetView);
        int containerStart;
        if (layoutManager.getClipToPadding()) {
            containerStart = helper.getStartAfterPadding();
        } else {
            containerStart = 0;
        }

        return childStart - containerStart;
    }

    @Nullable
    private View findStartView(RecyclerView.LayoutManager layoutManager, OrientationHelper helper) {
        int childCount = layoutManager.getChildCount();
        if (childCount == 0) {
            return null;
        } else {
            View closestChild = null;
            int start;
            if (layoutManager.getClipToPadding()) {
                start = helper.getStartAfterPadding();
            } else {
                start = 0 ;
            }

            int absClosest = Integer.MAX_VALUE;

            for(int i = 0; i < childCount; ++i) {
                View child = layoutManager.getChildAt(i);
                int childStart = helper.getDecoratedStart(child);
                int absDistance = Math.abs(childStart - start);
                if (absDistance < absClosest) {
                    absClosest = absDistance;
                    closestChild = child;
                }
            }

            return closestChild;
        }
    }

    @NonNull
    private OrientationHelper getVerticalHelper(@NonNull RecyclerView.LayoutManager layoutManager) {
        if (this.mVerticalHelper == null || this.mVerticalHelper.getLayoutManager() != layoutManager) {
            this.mVerticalHelper = OrientationHelper.createVerticalHelper(layoutManager);
        }

        return this.mVerticalHelper;
    }

    @NonNull
    private OrientationHelper getHorizontalHelper(@NonNull RecyclerView.LayoutManager layoutManager) {
        if (this.mHorizontalHelper == null || this.mHorizontalHelper.getLayoutManager() != layoutManager) {
            this.mHorizontalHelper = OrientationHelper.createHorizontalHelper(layoutManager);
        }

        return this.mHorizontalHelper;
    }

    public interface OnPageListener {
        void onPageSelected(int position);
    }
}

外部要获取当前顶部为的位置,可用如下方式获取

  new CustomPagerSnapHelper().setOnPageListener(new CustomPagerSnapHelper.OnPageListener() {
                @Override
                public void onPageSelected(int position) {
                   // do something
                }
            }).attachToRecyclerView(mRecyclerView);

参考:
让你明明白白的使用RecyclerView——SnapHelper详解
SnapHelper学习记录

2).无限循环
这种无限循环的思路和前面的ViewPager的一样,但是更简单
在Adapter中实现方式如下:

 @Override
    public int getItemCount() {
        if (mData.size() > 0) {
		return Integer.MAX_VALUE;
	}
	
        return 0;
    }
 @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    	if (mData.size() <= 0) {
	    	return;
    	}
    	
	DataInfo dataInfo = mData.get(position % mData.size());
    }

其中,mData为数据列表
同样的,需要调用如下方法,滚动到较大的位置。

 mRecyclerView.getLayoutManager().scrollToPosition();

**小结:**比较适合做固定数据的无限循环,例如banner。如果要左右滑动都能加载数据,且不能有闪屏的,则不合适。

总结
最后,这里采用第二种方法,但没有实现无限循环,由于不知如何处理前后滑动加载数据而又不闪屏,这里采用最简单的方式,就是直接加载100年的数据。。。

你可能感兴趣的:(android)