版權聲明:本文爲HaiyuKing原創文章,轉載請註明出處!html
使用RecyclerView+ViewPager實現相似TabLayout+ViewPager效果。java
注意事項:android
一、 導入類文件後須要change包名以及從新import R文件路徑git
二、 Values目錄下的文件(strings.xml、dimens.xml、colors.xml等),若是項目中存在,則複製裏面的內容,不要整個覆蓋github
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.why.project.viewpagerwithrecyclerdemo"
minSdkVersion 16
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
//RecyclerView compile "com.android.support:recyclerview-v7:27.1.1"
}
一、建立Bean類web
package com.why.project.viewpagerwithrecyclerdemo.bean; /** * Created by HaiyuKing * Used */ public class TabItemBean { private String tabTitle; private String tabUrl; public TabItemBean(String tabTitle, String tabUrl){ this.tabTitle = tabTitle; this.tabUrl = tabUrl; } public String getTabTitle() { return tabTitle; } public void setTabTitle(String tabTitle) { this.tabTitle = tabTitle; } public String getTabUrl() { return tabUrl; } public void setTabUrl(String tabUrl) { this.tabUrl = tabUrl; } }
二、建立Adapter以及item的佈局文件,同時定義顏色、文字大小值網絡
package com.why.project.viewpagerwithrecyclerdemo.adapter; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.RelativeLayout; import android.widget.TextView; import com.why.project.viewpagerwithrecyclerdemo.R; import com.why.project.viewpagerwithrecyclerdemo.bean.TabItemBean; import java.util.ArrayList; /** * Created by HaiyuKing * Used */ public class TabAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { /**上下文*/ private Context myContext; /**集合*/ private ArrayList<TabItemBean> listitemList; private int selectedPosition = -1;//選中的列表項 /** * 構造函數 */ public TabAdapter(Context context, ArrayList<TabItemBean> itemlist) { myContext = context; listitemList = itemlist; } /** * 獲取總的條目數 */ @Override public int getItemCount() { return listitemList.size(); } /** * 建立ViewHolder */ @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(myContext).inflate(R.layout.tab_list_item, parent, false); ItemViewHolder itemViewHolder = new ItemViewHolder(view); return itemViewHolder; } /** * 聲明grid列表項ViewHolder */ static class ItemViewHolder extends RecyclerView.ViewHolder { public ItemViewHolder(View view) { super(view); listItemLayout = (RelativeLayout) view.findViewById(R.id.listitem_layout); mTabTitle = (TextView) view.findViewById(R.id.top_title); mTabUnderLine = (TextView) view.findViewById(R.id.top_underline); } RelativeLayout listItemLayout; TextView mTabTitle; TextView mTabUnderLine; } /** * 將數據綁定至ViewHolder */ @Override public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int index) { //判斷屬於列表項 if (viewHolder instanceof ItemViewHolder) { TabItemBean tabItemBean = listitemList.get(index); final ItemViewHolder itemViewHold = ((ItemViewHolder) viewHolder); itemViewHold.mTabTitle.setText(tabItemBean.getTabTitle()); //設置下劃線的寬度值==文本的寬度值 itemViewHold.mTabTitle.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); Log.w("why", "top_title.getMeasuredWidth()="+itemViewHold.mTabTitle.getMeasuredWidth()); itemViewHold.listItemLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); Log.w("why", "toptabLayout.getMeasuredWidth()="+itemViewHold.listItemLayout.getMeasuredWidth()); itemViewHold.mTabUnderLine.setWidth(itemViewHold.mTabTitle.getMeasuredWidth());//手動設置下劃線的寬度值 if(selectedPosition == index){ itemViewHold.mTabTitle.setTextColor(myContext.getResources().getColor(R.color.tab_text_selected_top)); itemViewHold.mTabUnderLine.setBackgroundColor(myContext.getResources().getColor(R.color.tab_auto_selected_top)); }else{ itemViewHold.mTabTitle.setTextColor(myContext.getResources().getColor(R.color.tab_text_normal_top)); itemViewHold.mTabUnderLine.setBackgroundColor(myContext.getResources().getColor(R.color.tab_auto_normal_top)); } //若是設置了回調,則設置點擊事件 if (mOnItemClickLitener != null) { itemViewHold.listItemLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { int position = itemViewHold.getLayoutPosition();//在增長數據或者減小數據時候,position和index就不同了 mOnItemClickLitener.onItemClick(itemViewHold.listItemLayout, position); setSelected(position); } }); } } } /**更改選中的列表項下標值*/ public void setSelected(int selected) { this.selectedPosition = selected; notifyDataSetChanged(); } /** * 添加Item--用於動畫的展示 */ public void addItem(int position, TabItemBean listitemBean) { listitemList.add(position, listitemBean); notifyItemInserted(position); } /** * 刪除Item--用於動畫的展示 */ public void removeItem(int position) { listitemList.remove(position); notifyItemRemoved(position); } /*=====================添加OnItemClickListener回調================================*/ public interface OnItemClickLitener { void onItemClick(View view, int position); } private OnItemClickLitener mOnItemClickLitener; public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener) { this.mOnItemClickLitener = mOnItemClickLitener; } }
<?xml version="1.0" encoding="utf-8"?> <!-- 帶有下劃線的頂部選項卡子項的佈局文件--> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/listitem_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:paddingTop="@dimen/tab_top_auto_padding" android:paddingLeft="@dimen/tab_top_auto_padding" android:paddingRight="@dimen/tab_top_auto_padding" > <!-- 標題 --> <TextView android:id="@+id/top_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:text="" android:textSize="@dimen/tab_top_auto_title_size" android:textColor="@color/tab_text_normal_top" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" /> <!-- 下劃線--> <!-- android:background="@color/tab_underline_selected_top" --> <TextView android:id="@+id/top_underline" android:layout_width="match_parent" android:layout_height="@dimen/tab_top_auto_height" android:background="@color/tab_auto_normal_top" android:layout_below="@id/top_title" android:layout_centerHorizontal="true" android:layout_marginTop="@dimen/tab_top_auto_padding" /> </RelativeLayout>
在colors.xml文件中添加如下代碼app
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#3F51B5</color> <color name="colorPrimaryDark">#303F9F</color> <color name="colorAccent">#FF4081</color> <!-- *********************************頂部選項卡區域********************************* --> <!-- 頂部選項卡下劃線背景色 --> <color name="tab_auto_normal_top">#00ffffff</color> <color name="tab_auto_selected_top">#3090d9</color> <!-- 頂部選項卡文本顏色 --> <color name="tab_text_normal_top">#191919</color> <color name="tab_text_selected_top">#3090d9</color> </resources>
在dimens.xml文件中添加如下代碼ide
<resources> <!-- Default screen margins, per the Android Design guidelines. --> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> <!-- *********************************頂部選項卡區域********************************* --> <!-- 選項卡的內邊距 --> <dimen name="tab_top_auto_padding">10dp</dimen> <!-- 選項卡標題的文字大小 --> <dimen name="tab_top_auto_title_size">18sp</dimen> <!-- 選項卡標題的下劃線高度 --> <dimen name="tab_top_auto_height">3dp</dimen> </resources>
三、在Activity佈局文件中引用Recyclerview控件【見下文】函數
四、在Activity類中初始化recyclerview數據【見下文】
package com.why.project.viewpagerwithrecyclerdemo.adapter; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; import android.view.ViewGroup; import java.util.List; /** * Created by HaiyuKing * Used */ public class MyTabViewPagerAdapter extends FragmentStatePagerAdapter { /**碎片集合*/ private List<Fragment> fragmentList; public MyTabViewPagerAdapter(FragmentManager fm) { super(fm); // TODO Auto-generated constructor stub } /** * 自定義構造函數:用於傳遞碎片集合過來 * 通常都寫上*/ public MyTabViewPagerAdapter(FragmentManager fm,List<Fragment> fragmentList) { super(fm); this.fragmentList = fragmentList; } @Override public Fragment getItem(int arg0) { // TODO Auto-generated method stub return fragmentList.get(arg0); } @Override public int getCount() { return fragmentList.size(); } @Override public void destroyItem(ViewGroup container, int position, Object object) { //viewpager+fragment來回滑動fragment從新加載的簡單解決辦法:http://blog.csdn.net/qq_28058443/article/details/51519663 //建議保留,由於首頁碎片界面含有6個界面切換,總不能設置setOffscreenPageLimit(6)吧,並且設置個數少的話,銷燬後還得從新加載 //super.destroyItem(container, position, object); } }
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.why.project.viewpagerwithrecyclerdemo"> <!-- ======================受權訪問網絡(HttpUtil)========================== --> <!-- 容許程序打開網絡套接字 --> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
<?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.v7.widget.RecyclerView android:id="@+id/tab_top_recycler" android:layout_width="match_parent" android:layout_height="wrap_content" /> <!-- 橫分割線 --> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#e9e9e9" /> <!-- viewpager區域,配合Fragment使用,且不能滑動 --> <com.why.project.viewpagerwithrecyclerdemo.viewpager.MyCustomViewPager android:id="@+id/vp_tab" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> </LinearLayout>
package com.why.project.viewpagerwithrecyclerdemo; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; import com.why.project.viewpagerwithrecyclerdemo.adapter.MyTabViewPagerAdapter; import com.why.project.viewpagerwithrecyclerdemo.adapter.TabAdapter; import com.why.project.viewpagerwithrecyclerdemo.bean.TabItemBean; import com.why.project.viewpagerwithrecyclerdemo.fragment.WebViewFragment; import com.why.project.viewpagerwithrecyclerdemo.viewpager.MyCustomViewPager; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); //分類列表 private RecyclerView mTabRecycleView; private ArrayList<TabItemBean> mTabItemBeanArrayList; private TabAdapter mTabAdapter; /**保存的選項卡的下標值*/ private int savdCheckedIndex = 0; /**當前的選項卡的下標值*/ private int mCurrentIndex = -1; //橫向滾動的ViewPager private MyCustomViewPager mViewPager; /**滑屏適配器*/ private MyTabViewPagerAdapter viewPagerAdapter; /**碎片集合*/ private List<Fragment> fragmentList; //碎片界面 private WebViewFragment mWebViewFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初始化控件以及設置 initView(); //初始化數據 initData(); //初始化控件的點擊事件 initEvent(); } @Override protected void onResume() { super.onResume(); Log.e(TAG,"{onResume}savdCheckedIndex="+savdCheckedIndex); //設置保存的或者初始的選項卡標紅顯示 setTabsDisplay(savdCheckedIndex); mCurrentIndex = -1;//解決按home鍵後長時間不用,再次打開顯示空白的問題 //設置保存的或者初始的選項卡展示對應的fragment setFragmentDisplay(savdCheckedIndex); } /** * 初始化控件 */ private void initView() { mTabRecycleView = findViewById(R.id.tab_top_recycler); mViewPager = (MyCustomViewPager) findViewById(R.id.vp_tab); } /** * 初始化數據 */ public void initData() { //初始化集合 mTabItemBeanArrayList = new ArrayList<TabItemBean>(); mTabItemBeanArrayList.add(new TabItemBean("百度","http://www.baidu.com")); mTabItemBeanArrayList.add(new TabItemBean("CSDN","http://blog.csdn.net")); mTabItemBeanArrayList.add(new TabItemBean("博客園","http://www.cnblogs.com")); mTabItemBeanArrayList.add(new TabItemBean("極客頭條","http://geek.csdn.net/mobile")); mTabItemBeanArrayList.add(new TabItemBean("優設","http://www.uisdc.com/")); mTabItemBeanArrayList.add(new TabItemBean("玩Android","http://www.wanandroid.com/index")); mTabItemBeanArrayList.add(new TabItemBean("掘金","https://juejin.im/")); //設置佈局管理器【表情分類列表】 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false); mTabRecycleView.setLayoutManager(linearLayoutManager); //設置適配器 if(mTabAdapter == null){ //設置適配器 mTabAdapter = new TabAdapter(this, mTabItemBeanArrayList); mTabRecycleView.setAdapter(mTabAdapter); //添加分割線 //設置添加刪除動畫 //調用ListView的setSelected(!ListView.isSelected())方法,這樣就能及時刷新佈局 mTabRecycleView.setSelected(true); }else{ mTabAdapter.notifyDataSetChanged(); } //將碎片添加到集合中 fragmentList = new ArrayList<>(); for(int i=0;i<mTabItemBeanArrayList.size();i++){ TabItemBean tabItemBean = mTabItemBeanArrayList.get(i); Bundle bundle = new Bundle(); bundle.putString("param", tabItemBean.getTabUrl()); fragmentList.add(WebViewFragment.getInstance(WebViewFragment.class,bundle)); } //給ViewPager設置適配器 viewPagerAdapter = new MyTabViewPagerAdapter(getSupportFragmentManager(),fragmentList); mViewPager.setAdapter(viewPagerAdapter); } /** * 初始化點擊事件 * */ private void initEvent() { //列表適配器的點擊監聽事件 mTabAdapter.setOnItemClickLitener(new TabAdapter.OnItemClickLitener() { @Override public void onItemClick(View view, int position) { if (mCurrentIndex == position) { return; } setFragmentDisplay(position);//獨立出來,用於OnResume的時候初始化展示相應的Fragment savdCheckedIndex = position; mCurrentIndex = position; } }); //viewpager的滑動事件監聽 mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override /*此方法是頁面跳轉完後獲得調用,arg0是你當前選中的頁面的Position(位置編號)。*/ public void onPageSelected(int arg0) { //解決滑動後,沒法點擊上一個fragment選項卡的問題 setTabsDisplay(arg0); savdCheckedIndex = arg0; mCurrentIndex = arg0; } @Override /* * 當頁面在滑動的時候會調用此方法,在滑動被中止以前,此方法回一直獲得調用。其中三個參數的含義分別爲: * arg0 :當前頁面,及你點擊滑動的頁面 * arg1:當前頁面偏移的百分比 * arg2:當前頁面偏移的像素位置 */ public void onPageScrolled(int arg0, float arg1, int arg2) { // TODO Auto-generated method stub } @Override /*此方法是在狀態改變的時候調用,其中arg0這個參數有三種狀態(0,1,2)。 * arg0==0的時候默示什麼都沒作 * arg0 ==1的時候默示正在滑動 * arg0==2的時候默示滑動完畢了*/ public void onPageScrollStateChanged(int arg0) { // TODO Auto-generated method stub } }); } /** * 設置導航欄中選項卡之間的切換 */ private void setTabsDisplay(int index){ if(mTabAdapter != null){ mTabAdapter.setSelected(index); mTabRecycleView.smoothScrollToPosition(index);//平移滑動到指定position } } /** * 設置碎片之間的切換 */ private void setFragmentDisplay(int index){ mViewPager.setCurrentItem(index, false);//smoothScroll false表示切換的時候,不通過兩個頁面的中間頁 } /** * http://blog.csdn.net/caesardadi/article/details/20382815 * */ // 本身記錄fragment的位置,防止activity被系統回收時,fragment錯亂的問題【按home鍵返回到桌面一段時間,而後在進程裏面從新打開,會發現RadioButton的圖片選中狀態在第二個,可是文字和背景顏色的選中狀態在第一個】 //onSaveInstanceState()只適合用於保存一些臨時性的狀態,而onPause()適合用於數據的持久化保存。 protected void onSaveInstanceState(Bundle outState) { //http://www.cnblogs.com/chuanstone/p/4672096.html?utm_source=tuicool&utm_medium=referral //老是執行這句代碼來調用父類去保存視圖層的狀態」。其實到這裏你們也就明白了,就是由於這句話致使了重影的出現 super.onSaveInstanceState(outState); outState.putInt("selectedCheckedIndex", savdCheckedIndex); outState.putInt("mCurrentIndex", mCurrentIndex); } @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { savdCheckedIndex = savedInstanceState.getInt("selectedCheckedIndex"); mCurrentIndex = savedInstanceState.getInt("mCurrentIndex"); super.onRestoreInstanceState(savedInstanceState); } }
無
暫時空缺