/** * <pre> * @author 楊充 * blog : https://github.com/yangchong211 * time : 2019/6/20 * desc : 自定義ViewPager,主要是處理邊界極端狀況 * revise: * </pre> */
public class VerticalViewPager extends ViewPager {
private boolean isVertical = false;
private long mRecentTouchTime;
public VerticalViewPager(@NonNull Context context) {
super(context);
}
public VerticalViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
private void init() {
setPageTransformer(true, new HorizontalVerticalPageTransformer());
setOverScrollMode(OVER_SCROLL_NEVER);
}
public boolean isVertical() {
return isVertical;
}
public void setVertical(boolean vertical) {
isVertical = vertical;
init();
}
private class HorizontalVerticalPageTransformer implements PageTransformer {
private static final float MIN_SCALE = 0.25f;
@Override
public void transformPage(@NonNull View page, float position) {
if (isVertical) {
if (position < -1) {
page.setAlpha(0);
} else if (position <= 1) {
page.setAlpha(1);
// Counteract the default slide transition
float xPosition = page.getWidth() * -position;
page.setTranslationX(xPosition);
//set Y position to swipe in from top
float yPosition = position * page.getHeight();
page.setTranslationY(yPosition);
} else {
page.setAlpha(0);
}
} else {
int pageWidth = page.getWidth();
if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
page.setAlpha(0);
} else if (position <= 0) { // [-1,0]
// Use the default slide transition when moving to the left page
page.setAlpha(1);
page.setTranslationX(0);
page.setScaleX(1);
page.setScaleY(1);
} else if (position <= 1) { // (0,1]
// Fade the page out.
page.setAlpha(1 - position);
// Counteract the default slide transition
page.setTranslationX(pageWidth * -position);
page.setTranslationY(0);
// Scale the page down (between MIN_SCALE and 1)
float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position));
page.setScaleX(scaleFactor);
page.setScaleY(scaleFactor);
} else { // (1,+Infinity]
// This page is way off-screen to the right.
page.setAlpha(0);
}
}
}
}
/** * 交換x軸和y軸的移動距離 * @param event 獲取事件類型的封裝類MotionEvent */
private MotionEvent swapXY(MotionEvent event) {
//獲取寬高
float width = getWidth();
float height = getHeight();
//將Y軸的移動距離轉變成X軸的移動距離
float swappedX = (event.getY() / height) * width;
//將X軸的移動距離轉變成Y軸的移動距離
float swappedY = (event.getX() / width) * height;
//重設event的位置
event.setLocation(swappedX, swappedY);
return event;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
mRecentTouchTime = System.currentTimeMillis();
if (getCurrentItem() == 0 && getChildCount() == 0) {
return false;
}
if (isVertical) {
boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
swapXY(ev);
// return touch coordinates to original reference frame for any child views
return intercepted;
} else {
return super.onInterceptTouchEvent(ev);
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (getCurrentItem() == 0 && getChildCount() == 0) {
return false;
}
if (isVertical) {
return super.onTouchEvent(swapXY(ev));
} else {
return super.onTouchEvent(ev);
}
}
}
複製代碼
private void initViewPager() {
List<Video> list = new ArrayList<>();
ArrayList<Fragment> fragments = new ArrayList<>();
for (int a = 0; a< DataProvider.VideoPlayerList.length ; a++){
Video video = new Video(DataProvider.VideoPlayerTitle[a],
10,"",DataProvider.VideoPlayerList[a]);
list.add(video);
fragments.add(VideoFragment.newInstant(DataProvider.VideoPlayerList[a]));
}
vp.setOffscreenPageLimit(1);
vp.setCurrentItem(0);
vp.setOrientation(DirectionalViewPager.VERTICAL);
FragmentManager supportFragmentManager = getSupportFragmentManager();
MyPagerAdapter myPagerAdapter = new MyPagerAdapter(fragments, supportFragmentManager);
vp.setAdapter(myPagerAdapter);
}
class MyPagerAdapter extends FragmentStatePagerAdapter{
private ArrayList<Fragment> list;
public MyPagerAdapter(ArrayList<Fragment> list , FragmentManager fm){
super(fm);
this.list = list;
}
@Override
public Fragment getItem(int i) {
return list.get(i);
}
@Override
public int getCount() {
return list!=null ? list.size() : 0;
}
}
複製代碼
public class VideoFragment extends Fragment{
public VideoPlayer videoPlayer;
private String url;
private int index;
@Override
public void onStop() {
super.onStop();
VideoPlayerManager.instance().releaseVideoPlayer();
}
public static Fragment newInstant(String url){
VideoFragment videoFragment = new VideoFragment();
Bundle bundle = new Bundle();
bundle.putString("url",url);
videoFragment.setArguments(bundle);
return videoFragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle arguments = getArguments();
if (arguments != null) {
url = arguments.getString("url");
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_video, container, false);
return view;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
videoPlayer = view.findViewById(R.id.video_player);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d("初始化操做","------"+index++);
VideoPlayerController controller = new VideoPlayerController(getActivity());
videoPlayer.setUp(url,null);
videoPlayer.setPlayerType(ConstantKeys.IjkPlayerType.TYPE_IJK);
videoPlayer.setController(controller);
ImageUtils.loadImgByPicasso(getActivity(),"",
R.drawable.image_default,controller.imageView());
}
}
複製代碼
private int determineTargetPage(int currentPage, float pageOffset, int velocity, int deltaX) {
int targetPage;
if (Math.abs(deltaX) > this.mFlingDistance && Math.abs(velocity) > this.mMinimumVelocity) {
targetPage = velocity > 0 ? currentPage : currentPage + 1;
} else {
float truncator = currentPage >= this.mCurItem ? 0.4F : 0.6F;
targetPage = currentPage + (int)(pageOffset + truncator);
}
if (this.mItems.size() > 0) {
ViewPager.ItemInfo firstItem = (ViewPager.ItemInfo)this.mItems.get(0);
ViewPager.ItemInfo lastItem = (ViewPager.ItemInfo)this.mItems.get(this.mItems.size() - 1);
targetPage = Math.max(firstItem.position, Math.min(targetPage, lastItem.position));
}
return targetPage;
}
複製代碼
@TargetApi(Build.VERSION_CODES.KITKAT)
public void setAnimationDuration(final int during){
try {
// viewPager平移動畫事件
Field mField = ViewPager.class.getDeclaredField("mScroller");
mField.setAccessible(true);
// 動畫效果與ViewPager的一致
Interpolator interpolator = new Interpolator() {
@Override
public float getInterpolation(float t) {
t -= 1.0f;
return t * t * t * t * t + 1.0f;
}
};
Scroller mScroller = new Scroller(getContext(),interpolator){
final int time = 2000;
@Override
public void startScroll(int x, int y, int dx, int dy, int duration) {
// 若是手工滾動,則加速滾動
if (System.currentTimeMillis() - mRecentTouchTime > time) {
duration = during;
} else {
duration /= 2;
}
super.startScroll(x, y, dx, dy, duration);
}
@Override
public void startScroll(int x, int y, int dx, int dy) {
super.startScroll(x, y, dx, dy,during);
}
};
mField.set(this, mScroller);
} catch (NoSuchFieldException | IllegalAccessException | IllegalArgumentException e) {
e.printStackTrace();
}
}
複製代碼
/** * 該方法必須調用 * @param recyclerView recyclerView */
@Override
public void onAttachedToWindow(RecyclerView recyclerView) {
if (recyclerView == null) {
throw new IllegalArgumentException("The attach RecycleView must not null!!");
}
super.onAttachedToWindow(recyclerView);
this.mRecyclerView = recyclerView;
if (mPagerSnapHelper==null){
init();
}
mPagerSnapHelper.attachToRecyclerView(mRecyclerView);
mRecyclerView.addOnChildAttachStateChangeListener(mChildAttachStateChangeListener);
}
複製代碼
public interface OnPagerListener {
/** * 初始化完成 */
void onInitComplete();
/** * 釋放的監聽 * @param isNext 是否下一個 * @param position 索引 */
void onPageRelease(boolean isNext,int position);
/*** * 選中的監聽以及判斷是否滑動到底部 * @param position 索引 * @param isBottom 是否到了底部 */
void onPageSelected(int position,boolean isBottom);
}
複製代碼
/**
* 滑動狀態的改變
* 緩慢拖拽-> SCROLL_STATE_DRAGGING
* 快速滾動-> SCROLL_STATE_SETTLING
* 空閒狀態-> SCROLL_STATE_IDLE
* @param state 狀態
*/
@Override
public void onScrollStateChanged(int state) {
switch (state) {
case RecyclerView.SCROLL_STATE_IDLE:
View viewIdle = mPagerSnapHelper.findSnapView(this);
int positionIdle = 0;
if (viewIdle != null) {
positionIdle = getPosition(viewIdle);
}
if (mOnViewPagerListener != null && getChildCount() == 1) {
mOnViewPagerListener.onPageSelected(positionIdle,
positionIdle == getItemCount() - 1);
}
break;
case RecyclerView.SCROLL_STATE_DRAGGING:
View viewDrag = mPagerSnapHelper.findSnapView(this);
if (viewDrag != null) {
int positionDrag = getPosition(viewDrag);
}
break;
case RecyclerView.SCROLL_STATE_SETTLING:
View viewSettling = mPagerSnapHelper.findSnapView(this);
if (viewSettling != null) {
int positionSettling = getPosition(viewSettling);
}
break;
default:
break;
}
}
複製代碼
/**
* 監聽豎直方向的相對偏移量
* @param dy y軸滾動值
* @param recycler recycler
* @param state state滾動狀態
* @return int值
*/
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getChildCount() == 0 || dy == 0) {
return 0;
}
this.mDrift = dy;
return super.scrollVerticallyBy(dy, recycler, state);
}
/**
* 監聽水平方向的相對偏移量
* @param dx x軸滾動值
* @param recycler recycler
* @param state state滾動狀態
* @return int值
*/
@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getChildCount() == 0 || dx == 0) {
return 0;
}
this.mDrift = dx;
return super.scrollHorizontallyBy(dx, recycler, state);
}
複製代碼
private RecyclerView.OnChildAttachStateChangeListener mChildAttachStateChangeListener =
new RecyclerView.OnChildAttachStateChangeListener() {
/**
* 第一次進入界面的監聽,能夠作初始化方面的操做
* @param view view
*/
@Override
public void onChildViewAttachedToWindow(@NonNull View view) {
if (mOnViewPagerListener != null && getChildCount() == 1) {
mOnViewPagerListener.onInitComplete();
}
}
/**
* 頁面銷燬的時候調用該方法,能夠作銷燬方面的操做
* @param view view
*/
@Override
public void onChildViewDetachedFromWindow(@NonNull View view) {
if (mDrift >= 0){
if (mOnViewPagerListener != null) {
mOnViewPagerListener.onPageRelease(true , getPosition(view));
}
}else {
if (mOnViewPagerListener != null) {
mOnViewPagerListener.onPageRelease(false , getPosition(view));
}
}
}
};
複製代碼
/**
* attach到window窗口時,該方法必須調用
* @param recyclerView recyclerView
*/
@Override
public void onAttachedToWindow(RecyclerView recyclerView) {
//這裏省略部分代碼
mRecyclerView.addOnChildAttachStateChangeListener(mChildAttachStateChangeListener);
}
/**
* 銷燬的時候調用該方法,須要移除監聽事件
* @param view view
* @param recycler recycler
*/
@Override
public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
super.onDetachedFromWindow(view, recycler);
if (mRecyclerView!=null){
mRecyclerView.removeOnChildAttachStateChangeListener(mChildAttachStateChangeListener);
}
}
複製代碼
/** * 修改滑動靈敏度 * @param flingDistance 滑動慣性,默認是75 * @param minimumVelocity 最小滑動值,默認是1200 */
public void setScrollFling(int flingDistance , int minimumVelocity){
try {
Field mFlingDistance = ViewPager.class.getDeclaredField("mFlingDistance");
mFlingDistance.setAccessible(true);
Object o = mFlingDistance.get(this);
Log.d("setScrollFling",o.toString());
//默認值75
mFlingDistance.set(this, flingDistance);
Field mMinimumVelocity = ViewPager.class.getDeclaredField("mMinimumVelocity");
mMinimumVelocity.setAccessible(true);
Object o1 = mMinimumVelocity.get(this);
Log.d("setScrollFling",o1.toString());
//默認值1200
mMinimumVelocity.set(this,minimumVelocity);
} catch (Exception e){
e.printStackTrace();
}
}
複製代碼
try {
//attachToRecyclerView源碼上的方法可能會拋出IllegalStateException異常,這裏手動捕獲一下
RecyclerView.OnFlingListener onFlingListener = mRecyclerView.getOnFlingListener();
//源碼中判斷了,若是onFlingListener已經存在的話,再次設置就直接拋出異常,那麼這裏能夠判斷一下
if (onFlingListener==null){
mPagerSnapHelper.attachToRecyclerView(mRecyclerView);
}
} catch (IllegalStateException e){
e.printStackTrace();
}
複製代碼
@Override
protected void onStop() {
super.onStop();
//從前臺切到後臺,當視頻正在播放或者正在緩衝時,調用該方法暫停視頻
VideoPlayerManager.instance().suspendVideoPlayer();
}
@Override
protected void onDestroy() {
super.onDestroy();
//銷燬頁面,釋放,內部的播放器被釋放掉,同時若是在全屏、小窗口模式下都會退出
VideoPlayerManager.instance().releaseVideoPlayer();
}
@Override
public void onBackPressed() {
//處理返回鍵邏輯;若是是全屏,則退出全屏;若是是小窗口,則退出小窗口
if (VideoPlayerManager.instance().onBackPressed()){
return;
}else {
//銷燬頁面
VideoPlayerManager.instance().releaseVideoPlayer();
}
super.onBackPressed();
}
@Override
protected void onRestart() {
super.onRestart();
//從後臺切換到前臺,當視頻暫停時或者緩衝暫停時,調用該方法從新開啓視頻播放
VideoPlayerManager.instance().resumeVideoPlayer();
}
複製代碼