RecyclerView嵌套ViewPager实现原理:
RecyclerView嵌套ViewPager实际上就是RecyclerView复杂布局的实现,给其中一个item设置为ViewPager来实现广告轮播图。既然知道原理 那么我们实现起来也就非常的方便。使用SwipeRefreshLayout对其RecyclerView实现下拉刷新。
首先我们来看一下运行效果:
- ListView嵌套 ViewPager链接如下:
- RecyclerView复杂布局的实现:
接下来我们看具体代码的实现:
RecyclerView嵌套ViewPager肯定会出现滑动冲突的问题,对于滑动冲突的解决我们通常采用以下两种
内部拦截
外不拦截我们采用内部拦截,重写ViewPager来进行事件的拦截。具体代码如下:
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewGroup;
/**
* Created by wenpengli on 2017/3/13.
*/
public class MyViewPager extends ViewPager {
private ViewGroup parent;
public MyViewPager(Context context) {
super(context);
}
public MyViewPager(Context context, AttributeSet attributeSet) {
super(context,attributeSet);
}
public void setNestedpParent(ViewGroup parent) {
this.parent = parent;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
return super.dispatchTouchEvent(ev);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
return super.onInterceptTouchEvent(arg0);
}
@Override
public boolean onTouchEvent(MotionEvent arg0) {
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
return super.onTouchEvent(arg0);
}
}
RecyclerView和ListView一样比不可少的就是适配器,在适配器中我们定义了多种Item并且根据item的类型来判定该位置放置那种item,把我们刚重写好的ViewPager写在一种item中,在适配器中 我们加入了ViewPager的初始化和一些数据的加载,也就是对每个item进行初始化。具体适配器的代码如下:
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.RecyclerView;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.xyliwp.news.R;
import com.xyliwp.news.bean.TuiJianMessage;
import com.xyliwp.news.view.myview.MyViewPager;
import com.xyliwp.news.view.viewpageranim.LRZheDie;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Created by wenpengli on 2017/3/12.
*/
public class TuiJianRecyclerViewAdapter extends RecyclerView.Adapter{
private ArrayList<TuiJianMessage> addPinDaos;
private Context context;
private ViewHolderOne viewHolderOne;
private int currentItem = 0; // 当前图片的索引号
private List<View> views; // 滑动原点的view
// 切换当前图片
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// 显示当前图片
viewHolderOne.myViewPager.setCurrentItem(currentItem);
}
};
public TuiJianRecyclerViewAdapter(Context context,ArrayList<TuiJianMessage> addPinDaos){
super();
this.addPinDaos = addPinDaos;
this.context = context;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = null;
RecyclerView.ViewHolder viewHolder = null;
switch (viewType){
case 0:
view = LayoutInflater.from(context).inflate(R.layout.item_recyclerview_tuijian_tou
,parent,false);
viewHolder = new ViewHolderOne(view);
break;
case 1:
view = LayoutInflater.from(context).inflate(R.layout.item_recyclerview_tuijian
,parent,false);
viewHolder = new ViewHolderMy(view);
break;
}
return viewHolder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
TuiJianMessage addPinDao = addPinDaos.get(position);
switch (getItemViewType(position)){
case 0:
viewHolderOne = (ViewHolderOne)holder;
viewHolderOne.textview_Viewpager.setText(addPinDaos.get(0).getTitle());
viewpagerecommendAdapter adapter = new viewpagerecommendAdapter(context);
viewHolderOne.myViewPager.setPageTransformer(true,new LRZheDie());
viewHolderOne.myViewPager.setAdapter(adapter);
viewHolderOne.myViewPager.setOnPageChangeListener(new viewpagerRecommendPageChangeListener());
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
scheduledExecutorService.scheduleAtFixedRate(new YuanDianRun(), 3, 6,
TimeUnit.SECONDS);
break;
case 1:
final ViewHolderMy viewHolderMy = (ViewHolderMy)holder;
Glide.with(context).load(addPinDao.getPicUrl()).
override(100, 60).centerCrop().into(viewHolderMy.imageView_my);
viewHolderMy.textView_my.setText(addPinDao.getTitle());
break;
}
}
@Override
public int getItemCount() {
return addPinDaos.size();
}
@Override
public int getItemViewType(int position) {
if(position == 0){
return 0;
}else{
return 1;
}
}
class ViewHolderMy extends RecyclerView.ViewHolder{
private TextView textView_my;
private ImageView imageView_my;
public ViewHolderMy(View itemView) {
super(itemView);
imageView_my = (ImageView)itemView.findViewById(R.id.android_image);
textView_my = (TextView)itemView.findViewById(R.id.android_version);
}
}
class ViewHolderOne extends RecyclerView.ViewHolder{
private MyViewPager myViewPager;
private TextView textview_Viewpager;
private View textview_tuijian_tou1;
private View textview_tuijian_tou2;
private View textview_tuijian_tou3;
private View textview_tuijian_tou4;
private View textview_tuijian_tou5;
public ViewHolderOne(View itemView) {
super(itemView);
myViewPager = (MyViewPager) itemView.findViewById(R.id.myViewPage_tuijian_tou);
textview_Viewpager = (TextView)itemView.findViewById(R.id.textview_Viewpager);
textview_tuijian_tou1 = (View)itemView.findViewById(R.id.textview_tuijian_tou1);
textview_tuijian_tou2 = (View)itemView.findViewById(R.id.textview_tuijian_tou2);
textview_tuijian_tou3 = (View)itemView.findViewById(R.id.textview_tuijian_tou3);
textview_tuijian_tou4 = (View)itemView.findViewById(R.id.textview_tuijian_tou4);
textview_tuijian_tou5 = (View)itemView.findViewById(R.id.textview_tuijian_tou5);
//初始化原点
views = new ArrayList<View>();
views.add(textview_tuijian_tou1);
views.add(textview_tuijian_tou2);
views.add(textview_tuijian_tou3);
views.add(textview_tuijian_tou4);
views.add(textview_tuijian_tou5);
}
}
public int getWidth(){
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
int width = dm.widthPixels;// 屏幕宽度(像素)
float density = dm.density;//屏幕密度(0.75 / 1.0 / 1.5)
//屏幕宽度算法:屏幕宽度(像素)/屏幕密度
return (int) (width/density);//屏幕宽度(dp)
}
//viewpagger的PageChangeListener
private class viewpagerRecommendPageChangeListener implements ViewPager.OnPageChangeListener {
private int oldposition = 0;
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
currentItem = position;
viewHolderOne.textview_Viewpager.setText(addPinDaos.get(position).getTitle());
views.get(oldposition).setBackgroundResource(R.drawable.dot_normal);
views.get(position).setBackgroundResource(R.drawable.dot_focused);
oldposition = position;
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
//viewpager的aderpter
private class viewpagerecommendAdapter extends PagerAdapter {
private Context mContext;
public viewpagerecommendAdapter(Context mContext) {
this.mContext = mContext;
}
@Override
public int getCount() {
return 5;
}
@Override
public Object instantiateItem(View container, int position) {
ImageView imageview = new ImageView(context);
Glide.with(mContext).load(addPinDaos.get(position).getPicUrl()).
override(getWidth(), 150).centerCrop().into(imageview);
((ViewPager) container).addView(imageview);
return imageview;
}
@Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void restoreState(Parcelable arg0, ClassLoader arg1) {
}
@Override
public Parcelable saveState() {
return null;
}
@Override
public void startUpdate(View arg0) {
}
@Override
public void finishUpdate(View arg0) {
}
}
private class YuanDianRun implements Runnable {
@Override
public void run() {
synchronized (viewHolderOne.myViewPager) {
currentItem = (currentItem + 1) % 5;
// handler切换图片
handler.obtainMessage().sendToTarget();
}
}
}
在适配器中我们对ViewPager的进行了动画的设置。//此动画可以注释不用
mport android.support.v4.view.ViewPager;
import android.view.View;
import com.nineoldandroids.view.ViewHelper;
/**
* viewpager的左右折叠动画
* Created by lwp940118 on 2016/11/26.
*/
public class LRZheDie implements ViewPager.PageTransformer{
@Override
public void transformPage(View page, float position) {
if (position < -1){
ViewHelper.setPivotX(page,page.getMeasuredWidth() * 0.5f);
ViewHelper.setPivotY(page,page.getMeasuredHeight() * 0.5f);
ViewHelper.setScaleX(page,1);
}else if (position <= 0){
ViewHelper.setPivotX(page,page.getMeasuredWidth());
ViewHelper.setPivotY(page,0);
ViewHelper.setScaleX(page,1+position);
}else if(position <= 1){
ViewHelper.setPivotX(page,0);
ViewHelper.setPivotY(page,0);
ViewHelper.setScaleX(page,1 - position);
}else {
ViewHelper.setPivotX(page,page.getMeasuredWidth() * 0.5f);
ViewHelper.setPivotY(page,page.getMeasuredHeight() * 0.5f);
ViewHelper.setScaleX(page,1);
}
}
}
我们自定义item的布局介绍如下:
- item_recyclerview_tuijian_tou.xml的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="@color/baise">
<com.xyliwp.news.view.myview.MyViewPager
android:id="@+id/myViewPage_tuijian_tou"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.xyliwp.news.view.myview.MyViewPager>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="35dip"
android:layout_gravity="bottom"
android:background="#33000000"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/textview_Viewpager"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ipet"
android:textColor="#ffffff" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dip"
android:gravity="center">
<View
android:id="@+id/textview_tuijian_tou1"
style="@style/dot_style"
android:background="@drawable/dot_focused" />
<View
android:id="@+id/textview_tuijian_tou2"
style="@style/dot_style" />
<View
android:id="@+id/textview_tuijian_tou3"
style="@style/dot_style" />
<View
android:id="@+id/textview_tuijian_tou4"
style="@style/dot_style" />
<View
android:id="@+id/textview_tuijian_tou5"
style="@style/dot_style" />
</LinearLayout>
</LinearLayout>
</FrameLayout>
</LinearLayout>
- item_recyclerview_tuijian.xml的布局
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginLeft="5dp"
android:layout_marginBottom="5dp"
android:layout_marginRight="5dp"
>
<ImageView
android:id="@+id/android_image"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_marginRight="20dp"/>
<TextView
android:id="@+id/android_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textStyle="bold"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/android_image" />
</RelativeLayout>
</android.support.v7.widget.CardView>
- 在轮播图的item中dot_style的布局如下:
<style name="dot_style">
<item name="android:layout_width">5dp</item>
<item name="android:layout_height">5dp</item>
<item name="android:background">@drawable/dot_normal</item>
<item name="android:layout_marginLeft">1.5dp</item>
<item name="android:layout_marginRight">1.5dp</item>
</style>
- drawable中dot_focused.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<solid android:color="#aaFFFFFF" />
<corners android:radius="5dip" />
</shape>
- drawable中dot_normal.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<solid android:color="#33000000" />
<corners android:radius="5dip" />
</shape>
数据类型的保存类定义如下:
/**
* Created by wenpengli on 2017/3/12.
*/
public class TuiJianMessage {
private String ctime;
private String title;
private String description;
private String picUrl;
private String url;
public String getCtime() {
return ctime;
}
public void setCtime(String ctime) {
this.ctime = ctime;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getPicUrl() {
return picUrl;
}
public void setPicUrl(String picUrl) {
this.picUrl = picUrl;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
@Override
public String toString() {
return "TuiJianMessage{" +
"ctime='" + ctime + '\'' +
", title='" + title + '\'' +
", description='" + description + '\'' +
", picUrl='" + picUrl + '\'' +
", url='" + url + '\'' +
'}';
}
}
对于 主界面的实现 ,由于这是项目中的一段,我也没有写demo,所以 它实现的是在Fragment中编写的,因此 如果要编写demo的话,自行处理即可,具体代码如下:
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.xyliwp.news.R;
import com.xyliwp.news.bean.TuiJianMessage;
import com.xyliwp.news.view.fragment.fragmentshouye.adapter.TuiJianRecyclerViewAdapter;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/**
* Created by lwp940118 on 2016/12/1.
*/
public class FragmentTuiJian extends Fragment{
public static final String TAG = "FragmentTuiJian ------- ";
private View rootView;
private RecyclerView recyclerView_shouye_tuijian;
private SwipeRefreshLayout swipeRefreshLayout_shouye_tuijian;
private ArrayList<TuiJianMessage> tuiJianMessages = new ArrayList<>();
public static final String api = "https://api.tianapi.com/world/?" +
"key=你自己去天行申请的key &num=50";
private TuiJianRecyclerViewAdapter tuiJianRecyclerViewAdapter;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what == 1){
Log.e(TAG,tuiJianMessages.size()+"===tuiJianMessages");
Log.e(TAG,tuiJianRecyclerViewAdapter.getItemCount()+"===tuiJianMessages");
tuiJianRecyclerViewAdapter.notifyDataSetChanged();
}
}
};
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initData();
}
/**
* 进行数据页面加载
*/
private void initData(){
new Thread(new Runnable() {
@Override
public void run() {
try {
jiaZai();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
rootView = (View)inflater.inflate(R.layout.fragmentshouye_tuijian,container,false);
initView();
initOnClick();
return rootView;
}
private void initOnClick() {
//添加数据封信
swipeRefreshLayout_shouye_tuijian.setOnRefreshListener(new SwipeRefreshLayout.
OnRefreshListener(){
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
tuiJianRecyclerViewAdapter.notifyDataSetChanged();
swipeRefreshLayout_shouye_tuijian.setRefreshing(false);
}
}, 2000);
}
});
}
private void initView(){
recyclerView_shouye_tuijian = (RecyclerView)rootView.
findViewById(R.id.recyclerview_shouye_tuijian);
swipeRefreshLayout_shouye_tuijian = (SwipeRefreshLayout)rootView.
findViewById(R.id.swipeRefreshlayout_shouye_tuijian);
recyclerView_shouye_tuijian.setHasFixedSize(true);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext());
GridLayoutManager gridLayoutManager = new
GridLayoutManager(getContext(),2);
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return 1;
}
});
recyclerView_shouye_tuijian.setLayoutManager(layoutManager);
tuiJianRecyclerViewAdapter = new TuiJianRecyclerViewAdapter(getContext(),tuiJianMessages);
recyclerView_shouye_tuijian.setAdapter(tuiJianRecyclerViewAdapter);
}
private void jiaZai() throws IOException {
OkHttpClient okHttpClient = new OkHttpClient();
FormBody.Builder builder = new FormBody.Builder();
builder.add("json", "true");
RequestBody body = builder.build();
Request request = new Request.Builder()
.url(api)
.post(body)
.build();
try {
Response response = okHttpClient.newCall(request).execute();
if (response.isSuccessful()) {
getNewsData(response.body().string());
} else {
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void getNewsData(String s){
tuiJianMessages.clear();
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(s);
JSONArray jsonArray = jsonObject.getJSONArray("newslist");
for (int i = 0; i < jsonArray.length();i++){
JSONObject jsonObject1 = jsonArray.getJSONObject(i);
TuiJianMessage tuiJianMessage = new TuiJianMessage();
tuiJianMessage.setCtime(jsonObject1.getString("ctime"));
tuiJianMessage.setTitle(jsonObject1.getString("title"));
String sq = jsonObject1.getString("picUrl".replace("\\",""));
tuiJianMessage.setPicUrl(sq.replaceAll("ss","").replace('_',(char)32).replace(" ",""));
tuiJianMessage.setUrl(jsonObject1.getString("url".replace("\\","")));
Log.e(TAG,tuiJianMessage.toString());
tuiJianMessages.add(tuiJianMessage);
}
} catch (JSONException e) {
e.printStackTrace();
}
handler.sendEmptyMessage(1);
}
}
对于主界面的XML如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:id="@+id/swipeRefreshlayout_shouye_tuijian">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview_shouye_tuijian"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/dibu">
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
</LinearLayout>
整个过程就此结束,然后我们就成功完成了RecyclerView嵌套ViewPager。实现了RecyclerView的复杂布局。