实现类似抖音的的全屏上下滑动翻页效果,方案有两种:
1.ViewPage
ViewPager来实现的时候,手机内存不够用的情况就会显现出来
2.RecyclerView
RecyclerView可以帮我们处理内存的回收和利用
实现过程:
1.自定义LayoutManager,并且继承LinearLayoutManager,这样就得到一个可以水平排向或者竖向排向的布局
PagerSnapHelper可以做到一次滑动翻一页,并且居中的viewpage效果
public void onAttachedToWindow(RecyclerView view) {
super.onAttachedToWindow(view);
this.mPagerSnapHelper.attachToRecyclerView(view);
this.mRecyclerView = view;
this.mRecyclerView.addOnChildAttachStateChangeListener(this.mChildAttachStateChangeListener);
}
2.开始播放和释放播放器的时机
重写onScrollStateChanged()函数,这里面有三种状态:
SCROLL_STATE_IDLE(空闲)
SCROLL_STATE_DRAGGING(拖动)
SCROLL_STATE_SETTLING(要移动到最后位置时)
我们需要的就是RecyclerView停止时的状态,我们就可以拿到这个View的Position.注意这里还有一个问题,当你通过这个position去拿Item会报错。打印Log,你会发现RecyclerView.getChildCount()一直为1或者会出现为2的情况。好了,我们自己来实现一个接口然后通过接口把状态传递出去。
翻页状态监听器:
public interface OnViewPagerListener {
void onInitComplete();
void onPageRelease(boolean var1, int var2);
void onPageSelected(int var1, boolean var2);
}
重写LinearLayoutManager的onScrollStateChanged方法:
public void onScrollStateChanged(int state) {
switch(state) {
case 0:
View viewIdle = this.mPagerSnapHelper.findSnapView(this);
int positionIdle = this.getPosition(viewIdle);
if (this.mOnViewPagerListener != null && this.getChildCount() == 1) {
this.mOnViewPagerListener.onPageSelected(positionIdle, positionIdle == this.getItemCount() - 1);
}
break;
case 1:
View viewDrag = this.mPagerSnapHelper.findSnapView(this);
this.getPosition(viewDrag);
break;
case 2:
View viewSettling = this.mPagerSnapHelper.findSnapView(this);
this.getPosition(viewSettling);
}
}
3. 区分上一页还是下一页
列表的选中监听好了,我们就看看什么时候释放视频的资源,第二步中的三种状态,去打印getChildCount()的日志,你会发现getChildCount()在:
SCROLL_STATE_DRAGGING会为1
SCROLL_STATE_SETTLING为2
SCROLL_STATE_IDLE有时为1,有时为2
我们要做的是要知道在什么时候去做释放视频的操作,还要分清是释放上一页还是下一页,因为适配器adapter的position在这里不好使嘛,这里有两个方法scrollHorizontallyBy()和scrollVerticallyBy()可以拿到滑动偏移量,可以判断滑动方向
public int scrollVerticallyBy(int dy, Recycler recycler, State state) {
this.mDrift = dy;
return super.scrollVerticallyBy(dy, recycler, state);
}
public int scrollHorizontallyBy(int dx, Recycler recycler, State state) {
this.mDrift = dx;
return super.scrollHorizontallyBy(dx, recycler, state);
}
private OnChildAttachStateChangeListener mChildAttachStateChangeListener = new OnChildAttachStateChangeListener() {
public void onChildViewAttachedToWindow(View view) {
if (ViewPagerLayoutManager.this.mOnViewPagerListener != null && ViewPagerLayoutManager.this.getChildCount() == 1) {
ViewPagerLayoutManager.this.mOnViewPagerListener.onInitComplete();
}
}
public void onChildViewDetachedFromWindow(View view) {
if (ViewPagerLayoutManager.this.mDrift >= 0) {
if (ViewPagerLayoutManager.this.mOnViewPagerListener != null) {
ViewPagerLayoutManager.this.mOnViewPagerListener.onPageRelease(true, ViewPagerLayoutManager.this.getPosition(view));
}
} else if (ViewPagerLayoutManager.this.mOnViewPagerListener != null) {
ViewPagerLayoutManager.this.mOnViewPagerListener.onPageRelease(false, ViewPagerLayoutManager.this.getPosition(view));
}
}
};
完整代码:
ViewPageLayoutManager:
public class ViewPagerLayoutManager extends LinearLayoutManager {
private static final String TAG = "ViewPagerLayoutManager";
private PagerSnapHelper mPagerSnapHelper;
private OnViewPagerListener mOnViewPagerListener;
private RecyclerView mRecyclerView;
private int mDrift;
private OnChildAttachStateChangeListener mChildAttachStateChangeListener = new OnChildAttachStateChangeListener() {
public void onChildViewAttachedToWindow(View view) {
if (ViewPagerLayoutManager.this.mOnViewPagerListener != null && ViewPagerLayoutManager.this.getChildCount() == 1) {
ViewPagerLayoutManager.this.mOnViewPagerListener.onInitComplete();
}
}
public void onChildViewDetachedFromWindow(View view) {
if (ViewPagerLayoutManager.this.mDrift >= 0) {
if (ViewPagerLayoutManager.this.mOnViewPagerListener != null) {
ViewPagerLayoutManager.this.mOnViewPagerListener.onPageRelease(true, ViewPagerLayoutManager.this.getPosition(view));
}
} else if (ViewPagerLayoutManager.this.mOnViewPagerListener != null) {
ViewPagerLayoutManager.this.mOnViewPagerListener.onPageRelease(false, ViewPagerLayoutManager.this.getPosition(view));
}
}
};
public ViewPagerLayoutManager(Context context, int orientation) {
super(context, orientation, false);
this.init();
}
public ViewPagerLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
this.init();
}
private void init() {
this.mPagerSnapHelper = new PagerSnapHelper();
}
public void onAttachedToWindow(RecyclerView view) {
super.onAttachedToWindow(view);
this.mPagerSnapHelper.attachToRecyclerView(view);
this.mRecyclerView = view;
this.mRecyclerView.addOnChildAttachStateChangeListener(this.mChildAttachStateChangeListener);
}
public void onLayoutChildren(Recycler recycler, State state) {
super.onLayoutChildren(recycler, state);
}
public void onScrollStateChanged(int state) {
switch(state) {
case 0:
View viewIdle = this.mPagerSnapHelper.findSnapView(this);
int positionIdle = this.getPosition(viewIdle);
if (this.mOnViewPagerListener != null && this.getChildCount() == 1) {
this.mOnViewPagerListener.onPageSelected(positionIdle, positionIdle == this.getItemCount() - 1);
}
break;
case 1:
View viewDrag = this.mPagerSnapHelper.findSnapView(this);
this.getPosition(viewDrag);
break;
case 2:
View viewSettling = this.mPagerSnapHelper.findSnapView(this);
this.getPosition(viewSettling);
}
}
public int scrollVerticallyBy(int dy, Recycler recycler, State state) {
this.mDrift = dy;
return super.scrollVerticallyBy(dy, recycler, state);
}
public int scrollHorizontallyBy(int dx, Recycler recycler, State state) {
this.mDrift = dx;
return super.scrollHorizontallyBy(dx, recycler, state);
}
public void setOnViewPagerListener(OnViewPagerListener listener) {
this.mOnViewPagerListener = listener;
}
}
主Activity:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "ViewPagerActivity";
private RecyclerView mRecyclerView;
private MyAdapter mAdapter;
private ViewPagerLayoutManager mLayoutManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initListener();
}
private void initView() {
mRecyclerView = findViewById(R.id.recycler);
mLayoutManager = new ViewPagerLayoutManager(this, OrientationHelper.VERTICAL);
mAdapter = new MyAdapter();
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(mAdapter);
}
private void initListener(){
mLayoutManager.setOnViewPagerListener(new OnViewPagerListener() {
@Override
public void onInitComplete() {
}
@Override
public void onPageRelease(boolean isNext,int position) {
Log.e(TAG,"释放位置:"+position +" 下一页:"+isNext);
int index = 0;
if (isNext){
index = 0;
}else {
index = 1;
}
releaseVideo(index);
}
@Override
public void onPageSelected(int position,boolean isBottom) {
Log.e(TAG,"选中位置:"+position+" 是否是滑动到底部:"+isBottom);
playVideo(0);
}
public void onLayoutComplete() {
playVideo(0);
}
});
}
private void playVideo(int position) {
View itemView = mRecyclerView.getChildAt(0);
final VideoView videoView = itemView.findViewById(R.id.video_view);
final ImageView imgPlay = itemView.findViewById(R.id.img_play);
final ImageView imgThumb = itemView.findViewById(R.id.img_thumb);
final RelativeLayout rootView = itemView.findViewById(R.id.root_view);
final MediaPlayer[] mediaPlayer = new MediaPlayer[1];
videoView.start();
videoView.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer mp, int what, int extra) {
mediaPlayer[0] = mp;
Log.e(TAG,"onInfo");
mp.setLooping(true);
imgThumb.animate().alpha(0).setDuration(200).start();
return false;
}
});
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
Log.e(TAG,"onPrepared");
}
});
imgPlay.setOnClickListener(new View.OnClickListener() {
boolean isPlaying = true;
@Override
public void onClick(View v) {
if (videoView.isPlaying()){
Log.e(TAG,"isPlaying:"+videoView.isPlaying());
imgPlay.animate().alpha(1f).start();
videoView.pause();
isPlaying = false;
}else {
Log.e(TAG,"isPlaying:"+videoView.isPlaying());
imgPlay.animate().alpha(0f).start();
videoView.start();
isPlaying = true;
}
}
});
}
private void releaseVideo(int index){
View itemView = mRecyclerView.getChildAt(index);
final VideoView videoView = itemView.findViewById(R.id.video_view);
final ImageView imgThumb = itemView.findViewById(R.id.img_thumb);
final ImageView imgPlay = itemView.findViewById(R.id.img_play);
videoView.stopPlayback();
imgThumb.animate().alpha(1).start();
imgPlay.animate().alpha(0f).start();
}
class MyAdapter extends RecyclerView.Adapter{
private int[] imgs = {R.mipmap.video11,R.mipmap.video12,R.mipmap.video13,R.mipmap.video14,R.mipmap.img_video_2};
private int[] videos = {R.raw.video11,R.raw.video12,R.raw.video13,R.raw.video14,R.raw.video_2};
public MyAdapter(){
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view_pager,parent,false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.img_thumb.setImageResource(imgs[position%5]);
holder.videoView.setVideoURI(Uri.parse("android.resource://"+getPackageName()+"/"+ videos[position%5]));
}
@Override
public int getItemCount() {
return 50;
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView img_thumb;
VideoView videoView;
ImageView img_play;
RelativeLayout rootView;
public ViewHolder(View itemView) {
super(itemView);
img_thumb = itemView.findViewById(R.id.img_thumb);
videoView = itemView.findViewById(R.id.video_view);
img_play = itemView.findViewById(R.id.img_play);
rootView = itemView.findViewById(R.id.root_view);
}
}
}
}