您的位置:首页 > 移动开发 > Android开发

某宅的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 fragment