Source code: https://github.com/Way123Ne/android/tree/master/SlideFragment
Preface
Wechat's sliding switching has won unanimous praise. In the process of our development, we often imitate the navigation effect of Wechat.
- First look at the rendering.
The effect is fairly good, you can slide switch and click switch, the Wechat interface shows data with listview, the address book interface shows data with recycler view, in the next analysis with you one by one.
- activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/blue"> <TextView android:id="@+id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="WeChat" android:textColor="@android:color/white" android:textSize="20sp"/> </RelativeLayout> <android.support.v4.view.ViewPager android:id="@+id/mainViewPager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <LinearLayout android:layout_width="match_parent" android:layout_height="40dp" android:layout_marginTop="1dp" android:background="@android:color/white" android:baselineAligned="false" android:gravity="center_vertical" android:orientation="horizontal" android:paddingBottom="5dp" android:paddingTop="5dp"> <TextView android:id="@+id/item_weixin" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center_horizontal|center_vertical" android:text="WeChat" android:textColor="@drawable/main_tab_text_color" android:textSize="15dp"/> <TextView android:id="@+id/item_tongxunlu" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center_horizontal|center_vertical" android:text="Mail list" android:textColor="@drawable/main_tab_text_color" android:textSize="15dp"/> <TextView android:id="@+id/item_faxian" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center_horizontal|center_vertical" android:text="find" android:textColor="@drawable/main_tab_text_color" android:textSize="15dp"/> <TextView android:id="@+id/item_me" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center_horizontal|center_vertical" android:text="I" android:textColor="@drawable/main_tab_text_color" android:textSize="15dp"/> </LinearLayout> </LinearLayout>
The main layout is clear, with a vertical Linear Layout on the outermost layer, which is lined with Title bars, ViewPager, and navigation bars in turn.
- MainActivity.class
package com.cc.testdemo; import android.graphics.Color; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.TextView; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity implements View.OnClickListener { private TextView title, item_weixin, item_tongxunlu, item_faxian, item_me; private ViewPager vp; private OneFragment oneFragment; private TwoFragment twoFragment; private ThreeFragment threeFragment; private FouthFragment fouthFragmen; private List<Fragment> mFragmentList = new ArrayList<Fragment>(); private FragmentAdapter mFragmentAdapter; String[] titles = new String[]{"WeChat", "Mail list", "find", "I"}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //Remove toolbars getSupportActionBar().hide(); setContentView(R.layout.activity_main); initViews(); mFragmentAdapter = new FragmentAdapter(this.getSupportFragmentManager(), mFragmentList); vp.setOffscreenPageLimit(4);//ViewPager cache is 4 frames vp.setAdapter(mFragmentAdapter); vp.setCurrentItem(0);//Initially set ViewPager to select the first frame item_weixin.setTextColor(Color.parseColor("#66CDAA")); //ViewPager's listening events vp.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { /*This method is called when the page is selected*/ title.setText(titles[position]); changeTextColor(position); } @Override public void onPageScrollStateChanged(int state) { /*This method is called when the state changes, where arg0 has three states (0, 1, 2). arg0 ==1 The time is slipping. arg0==2 The time implies that the slide is over. arg0==0 Time implies that nothing has been done.*/ } }); } /** * Initialize Layout View */ private void initViews() { title = (TextView) findViewById(R.id.title); item_weixin = (TextView) findViewById(R.id.item_weixin); item_tongxunlu = (TextView) findViewById(R.id.item_tongxunlu); item_faxian = (TextView) findViewById(R.id.item_faxian); item_me = (TextView) findViewById(R.id.item_me); item_weixin.setOnClickListener(this); item_tongxunlu.setOnClickListener(this); item_faxian.setOnClickListener(this); item_me.setOnClickListener(this); vp = (ViewPager) findViewById(R.id.mainViewPager); oneFragment = new OneFragment(); twoFragment = new TwoFragment(); threeFragment = new ThreeFragment(); fouthFragmen = new FouthFragment(); //Add data to FragmentList mFragmentList.add(oneFragment); mFragmentList.add(twoFragment); mFragmentList.add(threeFragment); mFragmentList.add(fouthFragmen); } /** * Click on the bottom Text to dynamically modify the contents of the ViewPager */ @Override public void onClick(View v) { switch (v.getId()) { case R.id.item_weixin: vp.setCurrentItem(0, true); break; case R.id.item_tongxunlu: vp.setCurrentItem(1, true); break; case R.id.item_faxian: vp.setCurrentItem(2, true); break; case R.id.item_me: vp.setCurrentItem(3, true); break; } } public class FragmentAdapter extends FragmentPagerAdapter { List<Fragment> fragmentList = new ArrayList<Fragment>(); public FragmentAdapter(FragmentManager fm, List<Fragment> fragmentList) { super(fm); this.fragmentList = fragmentList; } @Override public Fragment getItem(int position) { return fragmentList.get(position); } @Override public int getCount() { return fragmentList.size(); } } /* *Modify the color of the bottom navigation Text by sliding ViewPager */ private void changeTextColor(int position) { if (position == 0) { item_weixin.setTextColor(Color.parseColor("#66CDAA")); item_tongxunlu.setTextColor(Color.parseColor("#000000")); item_faxian.setTextColor(Color.parseColor("#000000")); item_me.setTextColor(Color.parseColor("#000000")); } else if (position == 1) { item_tongxunlu.setTextColor(Color.parseColor("#66CDAA")); item_weixin.setTextColor(Color.parseColor("#000000")); item_faxian.setTextColor(Color.parseColor("#000000")); item_me.setTextColor(Color.parseColor("#000000")); } else if (position == 2) { item_faxian.setTextColor(Color.parseColor("#66CDAA")); item_weixin.setTextColor(Color.parseColor("#000000")); item_tongxunlu.setTextColor(Color.parseColor("#000000")); item_me.setTextColor(Color.parseColor("#000000")); } else if (position == 3) { item_me.setTextColor(Color.parseColor("#66CDAA")); item_weixin.setTextColor(Color.parseColor("#000000")); item_tongxunlu.setTextColor(Color.parseColor("#000000")); item_faxian.setTextColor(Color.parseColor("#000000")); } } }
MainActivity.class mainly deals with the logical processing of sliding switching. After switching, the font color of navigation menu is switched. The annotations on the code are clear, so there is no more explanation.
- Fragement
package com.cc.testdemo; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class FouthFragment extends Fragment { public FouthFragment() { // Required empty public constructor } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_fouth, container, false); } }
- fragment.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".FouthFragment"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="'I'Interface" android:textSize="25sp"/> </FrameLayout>
There are four fragments in it. Like the code, there is only one TextView in fragment. The above code can realize sliding switch and click switch.
- The effect of the above code is as follows:
Okay, now let's add data to the list view and recycler view, respectively. Recycyler view is a control that Google pushes instead of listview.
- The Onefragment page is displayed with Listview:
Modified Onefragment.xml code:
package com.cc.testdemo; import android.os.AsyncTask; import android.os.Bundle; import android.os.SystemClock; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Toast; import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class OneFragment extends Fragment { @BindView(R.id.lv) ListView lv; @BindView(R.id.srl) SwipeRefreshLayout mSwipeRefreshLayout; private List<String> stringList; private ArrayAdapter lvAdapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_one, container, false); ButterKnife.bind(this, view); initData(); return view; } private void initData() { stringList = new ArrayList<String>(); for (int i = 0; i < 20; i++) { stringList.add(String.valueOf(i)); } lvAdapter = new ArrayAdapter(getActivity(), android.R.layout.simple_list_item_1, stringList); lv.setAdapter(lvAdapter); lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { Toast.makeText(getActivity(), stringList.get(i).toString(), Toast.LENGTH_SHORT).show(); } }); lv.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) { Toast.makeText(getActivity(), "long click:" + stringList.get(i).toString(), Toast.LENGTH_SHORT).show(); return true; } }); //Initialize drop-down control color mSwipeRefreshLayout.setColorSchemeResources(android.R.color.holo_blue_bright, android.R.color.holo_green_light, android.R.color.holo_orange_light, android.R.color.holo_red_light); mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... voids) { SystemClock.sleep(2000); return null; } @Override protected void onPostExecute(Void aVoid) { Toast.makeText(getActivity(), "Drop-down Refresh Success", Toast.LENGTH_SHORT).show(); mSwipeRefreshLayout.setRefreshing(false); } }.execute(); } }); } }
The code in One Fragment is to show the simulated data with Listview, which has a swipeRefreshLayout drop-down refresh control on the outer layer.
- fragment_one.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.cc.testdemo.OneFragment"> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/srl" android:layout_width="match_parent" android:layout_height="match_parent"> <ListView android:id="@+id/lv" android:layout_width="match_parent" android:layout_height="match_parent"></ListView> </android.support.v4.widget.SwipeRefreshLayout> </FrameLayout>
The effect diagram of One Fragment:
Now let's look at the key recycler view instead of listview to display data.
Use of RecyclerView
RecyclerView has been around for some time. I believe you are no stranger to it. You can use it by importing support-v7.
According to the official introduction, the control is used to display a large number of data sets in a limited window. In fact, we are not unfamiliar with the control of this function, such as ListView, GridView.
So why do you need controls like RecyclerView with ListView and GridView? Overall, RecyclerView architecture provides a plug-in experience, highly decoupled, exceptionally flexible, and achieves amazing results by setting up different Layout Managers, ItemDecoration, and ItemAnimator it provides.
If you want to control how it is displayed, use Layout Manager
If you want to control the interval between Items (which can be plotted), please use ItemDecoration.
If you want to control the animation of adding or deleting Item, please use ItemAnimator.
For detailed use, please refer to: http://blog.csdn.net/lmj623565791/article/details/45059587
Now let's use the TwoFragment page to display the data using recyclerview:
TwoFragment.class code:
package com.cc.testdemo; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import java.util.ArrayList; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; public class TwoFragment extends Fragment implements MyRecyclerViewOnclickInterface { @BindView(R.id.id_recyclerview) RecyclerView mRecyclerview; private MyRecyclerViewAdapter mAdapter; private List<String> stringList; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment View view = inflater.inflate(R.layout.fragment_two, container, false); ButterKnife.bind(this, view); initData(); return view; } private void initData() { stringList = new ArrayList<String>(); for (int i = 0; i < 20; i++) { stringList.add(String.valueOf(i)); } mAdapter = new MyRecyclerViewAdapter(getActivity(), stringList); //Setting up Layout Manager mRecyclerview.setLayoutManager(new LinearLayoutManager(getActivity())); //Setting up adapter mRecyclerview.setAdapter(mAdapter); //Adding partition lines mRecyclerview.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST)); mAdapter.setOnItemClickLitener(this); } @Override public void onItemClick(View view, int position) { Toast.makeText(getActivity(), stringList.get(position), Toast.LENGTH_SHORT).show(); } @Override public void onItemLongClick(View view, int position) { Toast.makeText(getActivity(), "onItemLongClick" + stringList.get(position), Toast.LENGTH_SHORT).show(); } }
- fragment_two.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.cc.testdemo.TwoFragment"> <!-- TODO: Update blank fragment layout --> <android.support.v7.widget.RecyclerView android:id="@+id/id_recyclerview" android:layout_width="match_parent" android:layout_height="match_parent"/> </FrameLayout>
- MyRecyclerViewAdapter
package com.cc.testdemo; 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.TextView; import java.util.List; /** * Created by CC on 2016/12/27. */ public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.MyViewHolder> { private Context context; private List<String> mDatas; private MyRecyclerViewOnclickInterface mOnItemClickLitener; public void setOnItemClickLitener(MyRecyclerViewOnclickInterface mOnItemClickLitener) { this.mOnItemClickLitener = mOnItemClickLitener; } public MyRecyclerViewAdapter(Context context, List<String> mDatas) { this.context = context; this.mDatas = mDatas; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { MyViewHolder holder = new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.recyclerview_item, parent, false)); return holder; } @Override public void onBindViewHolder(final MyViewHolder holder, int position) { holder.tv.setText(mDatas.get(position)); // If a callback is set, click events are set if (mOnItemClickLitener != null) { //Click monitor holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int pos = holder.getLayoutPosition(); mOnItemClickLitener.onItemClick(holder.itemView, pos); } }); //Long press monitoring holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { int pos = holder.getLayoutPosition(); mOnItemClickLitener.onItemLongClick(holder.itemView, pos); //Returning true allows long press events to be consumed and avoids starting clicks return true; } }); } } @Override public int getItemCount() { return mDatas.size(); } class MyViewHolder extends RecyclerView.ViewHolder { TextView tv; public MyViewHolder(View view) { super(view); tv = (TextView) view.findViewById(R.id.tv); } } }
- MyRecyclerViewOnclickInterface
package com.cc.testdemo; import android.view.View; /** * Created by CC on 2016/12/27. */ public interface MyRecyclerViewOnclickInterface { void onItemClick(View view, int position); void onItemLongClick(View view, int position); }
MyRecyclerViewOnclickInterface initializes the interface method. Since recyclerview does not implement click processing for the time being, it can only add callbacks manually.
- DividerItemDecoration
package com.cc.testdemo; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.View; /** * This class is from the v7 samples of the Android SDK. It's not by me! * <p> * See the license above for details. */ public class DividerItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; private Drawable mDivider; private int mOrientation; public DividerItemDecoration(Context context, int orientation) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); setOrientation(orientation); } public void setOrientation(int orientation) { if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { throw new IllegalArgumentException("invalid orientation"); } mOrientation = orientation; } @Override public void onDraw(Canvas c, RecyclerView parent) { // Log.v("recyclerview - itemdecoration", "onDraw()"); if (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } else { drawHorizontal(c, parent); } } public void drawVertical(Canvas c, RecyclerView parent) { final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext()); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } public void drawHorizontal(Canvas c, RecyclerView parent) { final int top = parent.getPaddingTop(); final int bottom = parent.getHeight() - parent.getPaddingBottom(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { if (mOrientation == VERTICAL_LIST) { outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } } }
Divider ItemDecoration is a good implementation of Recycler View adding splitters (when using Layout Manager as Linear Layout Manager).