某宅的Android学习笔记(三)——用ViewPager与FragmentPagerAdapter实现可以滑动的Tab
2016-08-24 21:24
671 查看
用ViewPager与FragmentPagerAdapter实现可以滑动的Tab
自学三个月的Android,磕磕碰碰写了一个小项目“看知乎”,数据源来自大神的看知乎API。这里记录一下自己在coding中收获的一些知识点。ViewPager是很常用的一种控件,在我的项目里就用到了她来展示不同的页面。
要实现这种效果其实并不难,首先要创建一个适配器,然后将不同的页面用Fragment实现,最后在Activity中关联他们就可以了。
1.实现ViewPager
1.布局文件
父布局其实很简单,TitleLayout是我自定义的标题栏,下面是人物头像、姓名、签名等信息;再往下是自定义的Tab,用来标识当前处于那个页面;最后就是ViewPager了。<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.zhai.kanzhihu.view.TitleLayout android:layout_width="match_parent" android:layout_height="wrap_content"></com.zhai.kanzhihu.view.TitleLayout> <ImageView android:id="@+id/author_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="10dp" android:src="@mipmap/ic_launcher" /> <TextView android:id="@+id/author_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginBottom="5dp" android:layout_marginTop="5dp" android:textSize="20sp" android:textStyle="bold" /> <TextView android:id="@+id/author_sig" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginBottom="5dp" android:layout_marginTop="5dp" android:hint="@string/hint_no_sig" android:maxLines="2" android:textSize="15sp" /> <TextView android:id="@+id/author_des" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginBottom="20dp" android:layout_marginTop="5dp" android:hint="@string/hint_no_des" android:maxLines="3" android:textSize="15sp" /> <include layout="@layout/author_tab" /> <android.support.v4.view.ViewPager android:id="@+id/author_viewpager" android:layout_width="match_parent" android:layout_height="wrap_content"> </android.support.v4.view.ViewPager> </LinearLayout>
ViewPager的Tab:
<?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="50dp" android:background="#bdb76b" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="49dp" android:layout_gravity="center" android:gravity="center"> <TextView android:id="@+id/tab_detail" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="@string/tab_detail" android:textColor="#265cab" android:textSize="20sp" /> <TextView android:id="@+id/tab_star" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="@string/tab_star" android:textColor="#000000" android:textSize="20sp" /> <TextView android:id="@+id/tab_trend" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="@string/tab_trend" android:textColor="#000000" android:textSize="20sp" /> <TextView android:id="@+id/tab_topanswer" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:text="@string/tab_topanswer" android:textColor="#000000" android:textSize="20sp" /> </LinearLayout> <ImageView android:id="@+id/tab_line" android:layout_width="100dp" android:layout_height="1dp" android:background="#265cab" /> </LinearLayout>
当然如果要让Tab可以点击跳转、跟随页面滑动变色等等,要在Activity中实现相应的方法。
2.Fragment
页面要用Fragment来实现,就相当于适配器的数据源。这里拿我其中一个的页面来做例子,首先是布局文件:<?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" android:padding="10dp"> <ListView android:id="@+id/author_trend_listview" android:layout_width="match_parent" android:layout_height="wrap_content"></ListView> </LinearLayout>
很简单地放了一个ListView进去,ListView里则是几个TextView来展示信息,因为太丑就不放具体布局上来了。然后在Fragment里,用Bundle传递网络数据进来并解析,在onCreateView ()中实例化控件,并返回view对象。
package com.zhai.kanzhihu.fragment; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; import com.zhai.kanzhihu.R; import com.zhai.kanzhihu.model.AuthorTrend; import com.zhai.kanzhihu.util.HttpUtil; import java.util.List; /** * Created by 某宅 on 2016/8/12. */ public class AuthorTrendFragment extends Fragment { private String response; private List<AuthorTrend> authorTrendList; private ListView listView; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle bundle = getArguments(); if (bundle != null) { response = bundle.getString("response"); } authorTrendList = HttpUtil.parseAuthorTrendJson(response); } public static AuthorTrendFragment newInstance(String response) { AuthorTrendFragment authorTrendFragment = new AuthorTrendFragment(); Bundle bundle = new Bundle(); bundle.putString("response", response); authorTrendFragment.setArguments(bundle); return authorTrendFragment; } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.author_trend_layout, null); listView = (ListView) view.findViewById(R.id.author_trend_listview); AuthorTrendListViewAdapter adapter = new AuthorTrendListViewAdapter(view.getContext(), authorTrendList); listView.setAdapter(adapter); return view; } }
ListView 的 Adapter 主要是将解析完成的数据赋给各控件。
package com.zhai.kanzhihu.fragment; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.zhai.kanzhihu.R; import com.zhai.kanzhihu.model.AuthorTrend; import java.util.List; /** * Created by 某宅 on 2016/8/12. */ public class AuthorTrendListViewAdapter extends BaseAdapter { private List<AuthorTrend> authorTrendList; private LayoutInflater inflater; public AuthorTrendListViewAdapter(Context context, List<AuthorTrend> data) { authorTrendList = data; inflater = LayoutInflater.from(context); } @Override public int getCount() { return authorTrendList.size(); } @Override public Object getItem(int position) { return authorTrendList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; if (convertView == null) { viewHolder = new ViewHolder(); convertView = inflater.inflate(R.layout.author_trend_item, parent, false); viewHolder.date = (TextView) convertView.findViewById(R.id.author_trend_date); viewHolder.answer = (TextView) convertView.findViewById(R.id.author_trend_answer); viewHolder.agree = (TextView) convertView.findViewById(R.id.author_trend_agree); viewHolder.follower = (TextView) convertView.findViewById(R.id.author_trend_follower); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.ge d5dd tTag(); } viewHolder.date.setText(authorTrendList.get(position).getDate()); viewHolder.answer.setText("回答数+专栏文章数: " + authorTrendList.get(position).getAnswer()); viewHolder.agree.setText("赞同数: " + authorTrendList.get(position).getAgree()); viewHolder.follower.setText("被关注数: " + authorTrendList.get(position).getFollower()); return convertView; } private class ViewHolder { TextView date, answer, agree, follower; } }
其余的Fragment其实都类似,就不写上来骗字数了。当然实际项目中的Fragment应该会比我的更加复杂,可能还会涉及到内存的管理,这些都是今后要学习的地方。
3.FragmentPagerAdapter
自定义一个类继承自FragmentPagerAdapter,并将fragmentList传入构造方法。——fragmentList是所有Fragment的集合,要在Activity中获取。package com.zhai.kanzhihu.activity; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import java.util.List; /** * Created by 某宅 on 2016/8/12. */ public class AuthorFragmentAdapter extends FragmentPagerAdapter { private List<Fragment> fragmentList; public AuthorFragmentAdapter(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(); } }
4.Activity
关联 Fragment、适配器、Activity 的方式很简单,将 Fragment 对象集合到 List 中,再将 fragmentList 作为作为参数来 new 一个自定义的 FragmentPagerAdapter 即可,如下:MyFragment1 myFragment1 = new MyFragment1(); MyFragment2 myFragment2 = new MyFragment2(); MyFragment3 myFragment3 = new MyFragment3(); List fragmentList = new ArrayList(); fragmentList.add(myFragment1); fragmentList.add(myFragment2); fragmentList.add(myFragment3); MyFragmentAdapter myFragmentAdapter = new MyFragmentAdapter(getSupportFragmentManager(), fragmentList); myViewPager.setAdapter(myFragmentAdapter);
最后附上我的 Activity 的完整代码:
package com.zhai.kanzhihu.activity; import android.animation.ObjectAnimator; import android.app.ProgressDialog; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.view.ViewPager; import android.util.DisplayMetrics; import android.view.Display; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.zhai.kanzhihu.R; import com.zhai.kanzhihu.fragment.AuthorDetailFragment; import com.zhai.kanzhihu.fragment.AuthorStarFragment; import com.zhai.kanzhihu.fragment.AuthorTopAnswerFragment; import com.zhai.kanzhihu.fragment.AuthorTrendFragment; import com.zhai.kanzhihu.model.Author; import com.zhai.kanzhihu.model.AuthorDetail; import com.zhai.kanzhihu.model.AuthorStar; import com.zhai.kanzhihu.model.AuthorTopAnswers; import com.zhai.kanzhihu.model.AuthorTrend; import com.zhai.kanzhihu.util.HttpCallbackListener; import com.zhai.kanzhihu.util.HttpUtil; import java.io.IOException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; /** * Created by 某宅 on 2016/8/11. */ public class AuthorActivity extends FragmentActivity implements View.OnClickListener, ViewPager.OnPageChangeListener { private List<Author> authorList; private List<Fragment> fragmentList; private AuthorDetailFragment authorDetailFragment; private AuthorStarFragment authorStarFragment; private AuthorTrendFragment authorTrendFragment; private AuthorTopAnswerFragment authorTopAnswerFragment; private TextView titleText; private ImageView authorImg; private TextView authorName, authorSig, authorDes; private Bitmap bitmap; private ProgressDialog progressDialog; private ViewPager viewPager; private TextView tabDetail, tabStar, tabTrend, tabTopanswer; private ImageView tabLine; private float moveDis;//下划线移动距离 private Boolean isScrolling = false, isBackScrolling = false;//记录下划线移动状态 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.author_layout); progressDialog = new ProgressDialog(AuthorActivity.this); progressDialog.setMessage("加载中......"); progressDialog.setCancelable(true); progressDialog.show(); Intent intent = getIntent(); String address = intent.getStringExtra("author_add"); sendRequest(address); initView(); initLine(); } /** * 初始化控件 */ private void initView() { titleText = (TextView) findViewById(R.id.title_text); authorImg = (ImageView) findViewById(R.id.author_img); authorName = (TextView) findViewById(R.id.author_name); authorSig = (TextView) findViewById(R.id.author_sig); authorDes = (TextView) findViewById(R.id.author_des); viewPager = (ViewPager) findViewById(R.id.author_viewpager); tabDetail = (TextView) findViewById(R.id.tab_detail); tabStar = (TextView) findViewById(R.id.tab_star); tabTrend = (TextView) findViewById(R.id.tab_trend); tabTopanswer = (TextView) findViewById(R.id.tab_topanswer); tabLine = (ImageView) findViewById(R.id.tab_line); tabDetail.setOnClickListener(this); tabStar.setOnClickListener(this); tabTrend.setOnClickListener(this); tabTopanswer.setOnClickListener(this); viewPager.addOnPageChangeListener(this); titleText.setText("用户详情"); } /** * 获取网络数据 * * @param address 请求网址 */ private void sendRequest(final String address) { HttpUtil.sendHttpRequest(address, new HttpCallbackListener() { @Override public void onFinish(final String response) { authorList = HttpUtil.parseAuthorJson(response); authorDetailFragment = AuthorDetailFragment.newInstance(response); authorStarFragment = AuthorStarFragment.newInstance(response); authorTrendFragment = AuthorTrendFragment.newInstance(response); authorTopAnswerFragment = AuthorTopAnswerFragment.newInstance(response); //下载头像 HttpURLConnection connection = null; try { URL mUrl = new URL(authorList.get(0).getAuthorImg()); connection = (HttpURLConnection) mUrl.openConnection(); bitmap = BitmapFactory.decodeStream(connection.getInputStream()); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (connection != null) { connection.disconnect(); } } runOnUiThread(new Runnable() { @Override public void run() { //设置基本信息 String name = authorList.get(0).getAuthorName(); String sig = authorList.get(0).getAuthorSig(); String des = authorList.get(0).getAuthorDes(); authorName.setText(name); authorSig.setText(sig); authorDes.setText(des); authorImg.setImageBitmap(bitmap); //添加fragment fragmentList = new ArrayList<>(); fragmentList.add(authorDetailFragment); fragmentList.add(authorStarFragment); fragmentList.add(authorTrendFragment); fragmentList.add(authorTopAnswerFragment); AuthorFragmentAdapter authorFragmentAdapter = new AuthorFragmentAdapter( getSupportFragmentManager(), fragmentList); viewPager.setAdapter(authorFragmentAdapter); progressDialog.dismiss(); } }); } @Override public void onError(Exception e) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(AuthorActivity.this, "Error", Toast.LENGTH_SHORT).show(); } }); } }); } /** * 点击选项卡跳转到相应的page */ @Override public void onClick(View v) { switch (v.getId()) { case R.id.tab_detail: viewPager.setCurrentItem(0); break; case R.id.tab_star: viewPager.setCurrentItem(1); break; case R.id.tab_trend: viewPager.setCurrentItem(2); break; case R.id.tab_topanswer: viewPager.setCurrentItem(3); break; } } /** * 监听viewpager的滑动事件 */ //手指滑动时,下划线跟随手指移动 @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { if (isScrolling) { movePositionX(position, moveDis * positionOffset); } if (isBackScrolling) { movePositionX(position); } } // 滑动page时改变tab的颜色 @Override public void onPageSelected(int position) { switch (position) { case 0: tabDetail.setTextColor(Color.BLUE); tabStar.setTextColor(Color.BLACK); tabTrend.setTextColor(Color.BLACK); tabTopanswer.setTextColor(Color.BLACK); movePositionX(0); break; case 1: tabDetail.setTextColor(Color.BLACK); tabStar.setTextColor(Color.BLUE); tabTrend.setTextColor(Color.BLACK); tabTopanswer.setTextColor(Color.BLACK); movePositionX(1); break; case 2: tabDetail.setTextColor(Color.BLACK); tabStar.setTextColor(Color.BLACK); tabTrend.setTextColor(Color.BLUE); tabTopanswer.setTextColor(Color.BLACK); movePositionX(2); break; case 3: tabDetail.setTextColor(Color.BLACK); tabStar.setTextColor(Color.BLACK); tabTrend.setTextColor(Color.BLACK); tabTopanswer.setTextColor(Color.BLUE); movePositionX(3); break; default: break; } } //手指滑动时,下划线跟随手指移动 @Override public void onPageScrollStateChanged(int state) { switch (state) { case 1: isScrolling = true; isBackScrolling = false; break; case 2: isScrolling = false; isBackScrolling = true; break; default: isScrolling = false; isBackScrolling = false; break; } } /** * 初始化下划线 */ private void initLine() { //获取屏幕宽度 DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); int screenWidth = metrics.widthPixels; //将tabLine的宽度设定为屏幕的1/4 ViewGroup.LayoutParams layoutParams = tabLine.getLayoutParams(); layoutParams.width = screenWidth / 4; tabLine.setLayoutParams(layoutParams); moveDis = layoutParams.width; } /** * 设置下划线滑动动画 * 下划线滑动到新的选项卡 * * @param toPosition 下个page的下标 */ private void movePositionX(int toPosition) { movePositionX(toPosition, 0); } /** * 设置下划线滑动动画 * 下划线跟随手指滑动 */ private void movePositionX(int toPosition, float positionOffsetPixels) { float curTranslationX = tabLine.getTranslationX(); float toPositionX = moveDis * toPosition + positionOffsetPixels; ObjectAnimator animator = ObjectAnimator.ofFloat(tabLine, "translationX", curTranslationX, toPositionX); animator.setDuration(100); animator.start(); } }
之所以那么长,是因为还要实现 Tab 的点击事件,使得可以通过点击某一项来跳转到相应的 View;同时要监听 OnPageChangeListener(),在滑动 View 的同时改变 Tab 的颜色。同时为了增加交互感,添加了下划线的动画,让下划线跟随 Tab 移动。这样,我们的功能就实现啦。
最后附上自己项目的地址:https://github.com/Zhai-Wang/KanZhiHu,欢迎各路大神指正!
相关文章推荐
- Android实战简易教程<三十四>(基于ViewPager和FragmentPagerAdapter实现滑动通用Tab)
- ViewPager+Fragment实现TabHost,Fragment动态添加、删除,Tab选项卡跟随滑动
- ViewPager与FragmentPagerAdapter实现Tab
- 【FastDev4Android框架开发】HorizontalScrollView,Fragment,FragmentStatePagerAdapter打造网易新闻Tab及滑动页面效果(三十六)
- HorizontalScrollView,Fragment,FragmentStatePagerAdapter打造网易新闻Tab及滑动页面效果(三十六)
- FragmentPagerAdapter+ViewPager实现Tab切换效果
- viewpager+FragmentAdapter实现App主界面Tab
- 68、 FragmentPagerAdapter+ViewPager实现Tab
- Android开发之ViewPager+ActionBar+Fragment实现响应式可滑动Tab
- 自学android笔记之TabLayout结合ViewPager和Fragment实现多页面滑动
- Tablayout+Viewpager+Fragment实现滑动Tab及cannot convert from Fragment1 to Fragment之解决
- Android UI 详解之ActionBar+ViewPager+Fragment 实现滑动Tab
- TabPageIndicator + ViewPager + FragmentPagerAdapter + Fragment分析APP主框架实现
- FragmentPagerAdapter+ViewPager实现Tab切换效果
- 使用TabLayout、ViewPager和Fragment实现顶部菜单可滑动切换
- Android:Fragment+ViewPager实现Tab滑动
- Android学习笔记 - ViewPager + Fragment实现滑动标签页
- 安卓开发_慕课网_ViewPager与FragmentPagerAdapter实现Tab实现Tab(App主界面)