1. 程式人生 > >RecyclerView巢狀ViewPager實現淘寶搜狐主頁廣告輪播圖

RecyclerView巢狀ViewPager實現淘寶搜狐主頁廣告輪播圖

RecyclerView巢狀ViewPager實現原理:

RecyclerView巢狀ViewPager實際上就是RecyclerView複雜佈局的實現,給其中一個item設定為ViewPager來實現廣告輪播圖。既然知道原理 那麼我們實現起來也就非常的方便。使用SwipeRefreshLayout對其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的複雜佈局。