Android快速實現美團、餓了麼首頁分頁導航選單功能
前段時間公司移動端App新增一個模組,類似美團團購的功能,首頁有個類似美團的分頁選單的功能,用過美團和餓了麼的app的童鞋應該清楚這一功能。首頁選單可以分頁切換,類似我們的banner廣告切換效果,只不過只能手動切換。所以整個分頁效果,我們可以採用Viewpager實現,裡面的選單項我們則可以採用RecyclerView實現,動態改變裡面的選單項,以後產品汪要改需求也是一兩行程式碼能搞定的事,是不是很機智。所以今天我們這個首頁分頁選單效果,可以採用ViewPager+RecyclerView實現,思路既然已經有了,那我們就開整吧。首先我們先看下實現的效果圖。

image.png

image.png

image.png
首頁佈局檔案,分頁指示器是單獨封裝的一個控制元件,後面會把程式碼貼出來
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/home_entrance" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <android.support.v4.view.ViewPager android:id="@+id/main_home_entrance_vp" android:layout_width="match_parent" android:layout_height="wrap_content"/> <com.stx.xhb.meituancategorydemo.widget.IndicatorView android:id="@+id/main_home_entrance_indicator" android:layout_width="match_parent" android:layout_height="32dp" android:layout_marginLeft="16dp" android:layout_gravity="bottom" android:layout_marginRight="16dp" app:gravity="0" app:indicatorColor="#668b8989" app:indicatorColorSelected="#FF5722" app:indicatorWidth="6"/> </LinearLayout>
ViewPager中的子控制元件RecyclerView
item_home_entrance_vp.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"/>
接下來就是RecyclerView的選單項的佈局檔案
item_home_entrance.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="vertical" android:padding="6dp"> <ImageView android:id="@+id/entrance_image" android:layout_width="wrap_content" android:layout_height="0dp" android:layout_margin="2dp" android:layout_weight="1" android:scaleType="fitCenter"/> <TextView android:id="@+id/entrance_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="2dp" android:singleLine="true" android:textColor="#80000000" android:textSize="12dp"/> </LinearLayout> <View android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/selector_trans_divider"/> </FrameLayout>
佈局都建立好了,接下來我們一起來看看裡面的具體實現程式碼了。由於我們的選單項有一個icon和名稱name,為了方便管理,我們可以建立一個選單項實體類ModelHomeEntrance.class
/** * Author: Mr.xiao on 2017/5/23 * * @mail:[email protected] * @github:https://github.com/xiaohaibin * @describe:選單項實體類 */ public class ModelHomeEntrance { private String name = ""; private int image; public ModelHomeEntrance(String name, int image) { this.image = image; this.name = name; } public int getImage() { return image; } public String getName() { return name; } }
由於我們分頁效果是以ViewPager實現的,所以我們要建立一個ViewPager的介面卡,CagegoryViewPagerAdapter.Class
package com.stx.xhb.meituancategorydemo.adapter; import android.support.v4.view.PagerAdapter; import android.view.View; import android.view.ViewGroup; import java.util.List; /** * Created by jxnk25 on 2016/9/21. * * @link https://xiaohaibin.github.io/ * @email: [email protected] * @github: https://github.com/xiaohaibin * @description:首頁分類ViewPager介面卡 */ public class CagegoryViewPagerAdapter extends PagerAdapter { private List<View> mViewList; public CagegoryViewPagerAdapter(List<View> mViewList) { this.mViewList = mViewList; } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(mViewList.get(position)); } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(mViewList.get(position)); return (mViewList.get(position)); } @Override public int getCount() { if (mViewList == null) return 0; return mViewList.size(); } @Override public boolean isViewFromObject(View view, Object object) { return view == object; } }
ViewPager的介面卡有了,我們還得再建立一個RecyclerView的選單項列表介面卡,EntranceAdapter.Class
package com.stx.xhb.meituancategorydemo.adapter; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.stx.xhb.meituancategorydemo.R; import com.stx.xhb.meituancategorydemo.model.ModelHomeEntrance; import com.stx.xhb.meituancategorydemo.utils.ScreenUtil; import java.util.List; /** * Author: Mr.xiao on 2017/5/23 * * @mail:[email protected] * @github:https://github.com/xiaohaibin * @describe: 首頁分頁選單項列表介面卡 */ public class EntranceAdapter extends RecyclerView.Adapter<EntranceAdapter.EntranceViewHolder> { private List<ModelHomeEntrance> mDatas; /** * 頁數下標,從0開始(通俗講第幾頁) */ private int mIndex; /** * 每頁顯示最大條目個數 */ private int mPageSize; private Context mContext; private final LayoutInflater mLayoutInflater; private List<ModelHomeEntrance> homeEntrances; public EntranceAdapter(Context context, List<ModelHomeEntrance> datas, int index, int pageSize) { this.mContext = context; this.homeEntrances = datas; mPageSize = pageSize; mDatas = datas; mIndex = index; mLayoutInflater = LayoutInflater.from(context); } @Override public EntranceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new EntranceViewHolder(mLayoutInflater.inflate(R.layout.item_home_entrance, null)); } @Override public void onBindViewHolder(EntranceViewHolder holder, final int position) { /** * 在給View繫結顯示的資料時,計算正確的position = position + mIndex * mPageSize, */ final int pos = position + mIndex * mPageSize; holder.entranceNameTextView.setText(homeEntrances.get(pos).getName()); holder.entranceIconImageView.setImageResource(homeEntrances.get(pos).getImage()); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ModelHomeEntrance entrance = homeEntrances.get(pos); // TODO: 2017/5/24 點選事件處理 } }); } @Override public int getItemCount() { return mDatas.size() > (mIndex + 1) * mPageSize ? mPageSize : (mDatas.size() - mIndex * mPageSize); } @Override public long getItemId(int position) { return position + mIndex * mPageSize; } class EntranceViewHolder extends RecyclerView.ViewHolder { private TextView entranceNameTextView; private ImageView entranceIconImageView; public EntranceViewHolder(View itemView) { super(itemView); entranceIconImageView = (ImageView) itemView.findViewById(R.id.entrance_image); entranceNameTextView = (TextView) itemView.findViewById(R.id.entrance_name); LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, (int) ((float) ScreenUtil.getScreenWidth() / 4.0f)); itemView.setLayoutParams(layoutParams); } } }
最後就是我們的MainActivity的程式碼實現了,我們整體的思路其實就是需要根據首頁選單項的資料來源進行分頁顯示,首頁確定單頁選單顯示數量,總數除以單頁顯示數量取整就是顯示頁數,我們再根據頁數來建立RecyclerView將其新增到ViewPager的介面卡中,下面就讓我們一起來看看具體是如何的。
package com.stx.xhb.meituancategorydemo; import android.os.Bundle; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.widget.FrameLayout; import android.widget.LinearLayout; import com.stx.xhb.meituancategorydemo.adapter.CagegoryViewPagerAdapter; import com.stx.xhb.meituancategorydemo.adapter.EntranceAdapter; import com.stx.xhb.meituancategorydemo.model.ModelHomeEntrance; import com.stx.xhb.meituancategorydemo.utils.ScreenUtil; import com.stx.xhb.meituancategorydemo.widget.IndicatorView; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { public static final int HOME_ENTRANCE_PAGE_SIZE = 10;//首頁選單單頁顯示數量 private ViewPager entranceViewPager; private LinearLayout homeEntranceLayout; private List<ModelHomeEntrance> homeEntrances; private IndicatorView entranceIndicatorView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); initView(); init(); } private void initView() { homeEntranceLayout = (LinearLayout) findViewById(R.id.home_entrance); entranceViewPager = (ViewPager) findViewById(R.id.main_home_entrance_vp); entranceIndicatorView = (IndicatorView) findViewById(R.id.main_home_entrance_indicator); } private void initData() { homeEntrances = new ArrayList<>(); homeEntrances.add(new ModelHomeEntrance("美食", R.mipmap.ic_category_0)); homeEntrances.add(new ModelHomeEntrance("電影", R.mipmap.ic_category_1)); homeEntrances.add(new ModelHomeEntrance("酒店住宿", R.mipmap.ic_category_2)); homeEntrances.add(new ModelHomeEntrance("生活服務", R.mipmap.ic_category_3)); homeEntrances.add(new ModelHomeEntrance("KTV", R.mipmap.ic_category_4)); homeEntrances.add(new ModelHomeEntrance("旅遊", R.mipmap.ic_category_5)); homeEntrances.add(new ModelHomeEntrance("學習培訓", R.mipmap.ic_category_6)); homeEntrances.add(new ModelHomeEntrance("汽車服務", R.mipmap.ic_category_7)); homeEntrances.add(new ModelHomeEntrance("攝影寫真", R.mipmap.ic_category_8)); homeEntrances.add(new ModelHomeEntrance("休閒娛樂", R.mipmap.ic_category_10)); homeEntrances.add(new ModelHomeEntrance("麗人", R.mipmap.ic_category_11)); homeEntrances.add(new ModelHomeEntrance("運動健身", R.mipmap.ic_category_12)); homeEntrances.add(new ModelHomeEntrance("大保健", R.mipmap.ic_category_13)); homeEntrances.add(new ModelHomeEntrance("團購", R.mipmap.ic_category_14)); homeEntrances.add(new ModelHomeEntrance("景點", R.mipmap.ic_category_16)); homeEntrances.add(new ModelHomeEntrance("全部分類", R.mipmap.ic_category_15)); } private void init() { LinearLayout.LayoutParams layoutParams12 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, (int) ((float) ScreenUtil.getScreenWidth() / 2.0f)); //首頁選單分頁 FrameLayout.LayoutParams entrancelayoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, (int) ((float) ScreenUtil.getScreenWidth() / 2.0f + 70)); homeEntranceLayout.setLayoutParams(entrancelayoutParams); entranceViewPager.setLayoutParams(layoutParams12); LayoutInflater inflater = LayoutInflater.from(this); //將RecyclerView放至ViewPager中: int pageSize = HOME_ENTRANCE_PAGE_SIZE; //一共的頁數等於 總數/每頁數量,並取整。 int pageCount = (int) Math.ceil(homeEntrances.size() * 1.0 / pageSize); List<View> viewList = new ArrayList<View>(); for (int index = 0; index < pageCount; index++) { //每個頁面都是inflate出一個新例項 RecyclerView recyclerView = (RecyclerView) inflater.inflate(R.layout.item_home_entrance_vp, entranceViewPager, false); recyclerView.setLayoutParams(layoutParams12); recyclerView.setLayoutManager(new GridLayoutManager(MainActivity.this, 5)); EntranceAdapter entranceAdapter = new EntranceAdapter(MainActivity.this, homeEntrances, index, HOME_ENTRANCE_PAGE_SIZE); recyclerView.setAdapter(entranceAdapter); viewList.add(recyclerView); } CagegoryViewPagerAdapter adapter = new CagegoryViewPagerAdapter(viewList); entranceViewPager.setAdapter(adapter); entranceIndicatorView.setIndicatorCount(entranceViewPager.getAdapter().getCount()); entranceIndicatorView.setCurrentIndicator(entranceViewPager.getCurrentItem()); entranceViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { entranceIndicatorView.setCurrentIndicator(position); } }); } }
以上就是實現首頁分頁選單效果的主要實現程式碼,這種分頁選單效果在我們的應用中也比較常見,說不定啥時候公司產品汪就拿手機過來讓你照著美團之類實現這種效果。

大綱與資料.png

高清視訊資料.jpg