我们都习惯用ViewPager加Fragment来做出一个滑动显示不同页面的效果,最近做项目想实现一个竖直显示不同页面的内容的效果(具体来说是竖直显示不同的会议详情,并且要可以进行滑动,上下滑实现页面的切换,还要能够与左侧的议程列表进行同步),一开始没有加入滑动效果显得很丑,为了加入滑动效果用了很长时间来考虑,动画也试过了还是不够自然,想到了ViewPager,可是又是竖直的,不能够直接用,只能自己想办法实现(开源的竖直Viewpager我没试过,也许更好)
自己想的办法是用RecyclerView来进行显示,只要每次只能够显示一个项,就可以像ViewPager一样的效果,具体实现并不复杂
先来看看界面布局
<LinearLayout 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">
<android.support.v7.widget.RecyclerView
android:id="@+id/id_rev_agenda"
android:layout_width="200dp"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
<LinearLayout
android:visibility="gone"
android:id="@+id/id_agenda_detail_layout"
android:background="#afbfff"
android:layout_marginLeft="100dp"
android:layout_marginRight="100dp"
android:layout_marginTop="100dp"
android:layout_marginBottom="150dp"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent">
<LinearLayout
android:background="#FFFFFF"
android:orientation="vertical"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/id_text_view_agenda_title"
android:gravity="center"
android:textSize="30sp"
android:text="议程标题"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<TextView
android:id="@+id/id_text_view_agenda_speaker"
android:gravity="center"
android:textSize="20sp"
android:text="主讲人:"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<TextView
android:id="@+id/id_text_view_agenda_time"
android:gravity="center"
android:textSize="20sp"
android:text="议程时长:5:00"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<Button
android:id="@+id/id_btn_show_agenda_file"
android:text="查看文件"
android:layout_centerInParent="true"
android:layout_width="100dp"
android:layout_height="50dp" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/id_rev_agenda_detail"
android:layout_marginBottom="50dp"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</LinearLayout>
布局很简单,左边一个RecyclerView是用来显示会议议程列表的,右边才是真正显示具体信息的部分,也是我们用来模拟出Viewpager效果的地方
RecyclerView项的布局如下
<?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">
<View
android:layout_width="match_parent"
android:layout_height="50dp">
</View>
<LinearLayout
android:orientation="vertical"
android:id="@+id/id_agenda_detail_layout"
android:background="#afbfff"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:background="#FFFFFF"
android:orientation="vertical"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/id_text_view_agenda_title"
android:gravity="center"
android:textSize="30sp"
android:text="议程标题"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<TextView
android:id="@+id/id_text_view_agenda_speaker"
android:gravity="center"
android:textSize="20sp"
android:text="主讲人:"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<TextView
android:id="@+id/id_text_view_agenda_time"
android:gravity="center"
android:textSize="20sp"
android:text="议程时长:5:00"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<Button
android:id="@+id/id_btn_show_agenda_file"
android:text="查看文件"
android:layout_centerInParent="true"
android:layout_width="100dp"
android:layout_height="50dp" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="50dp">
</View>
</LinearLayout>
这里要关注的地方就是
android:layout_width="match_parent"
android:layout_height="match_parent"
让你的一个项的布局占满整个RecyclerView,才能实现像ViewPager那样的效果,即一个Fragment占一个页面
RecyclerView的Adapter大家都应该很熟悉,我也只是贴一下代码,内容都是与你的具体要求有关的
package com.gzz100.Z100_HuiYi.meeting.agenda;
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.Button;
import android.widget.TextView;
import com.gzz100.Z100_HuiYi.R;
import com.gzz100.Z100_HuiYi.data.Agenda;
import java.util.List;
import java.util.zip.Inflater;
import butterknife.BindView;
import butterknife.ButterKnife;
/**
* Created by Lee on 2016/9/12.
*/
public class AgendaDetailListAdapter extends RecyclerView.Adapter<AgendaDetailHolder>{
private OnFileDetailClickListener mOnFileDetailClickListener;
public void setOnFileDetailClickListener(OnFileDetailClickListener listener){
this.mOnFileDetailClickListener = listener;
}
private Context mContext;
private List<Agenda> mAgendaList;
private LayoutInflater mInflater;
public AgendaDetailListAdapter(Context context, List<Agenda> list){
mContext = context;
mAgendaList = list;
mInflater = LayoutInflater.from(context);
}
@Override
public AgendaDetailHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.item_agenda_detail, parent, false);
AgendaDetailHolder holder = new AgendaDetailHolder(view);
return holder;
}
@Override
public void onBindViewHolder(AgendaDetailHolder holder, final int position) {
holder.mAgendaTitleTextView.setText(mAgendaList.get(position).getAgendaName());
holder.mAgendaSperkerTextView.setText(mAgendaList.get(position).getAgendaSpeaker());
holder.mAgendaTimeTextView.setText(mAgendaList.get(position).getAgendaDuration());
holder.mAgendaFileButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(mOnFileDetailClickListener != null){
mOnFileDetailClickListener.onFileDetailClickListener(position);
}
}
});
}
@Override
public int getItemCount() {
return mAgendaList.size();
}
}
class AgendaDetailHolder extends RecyclerView.ViewHolder{
@BindView(R.id.id_text_view_agenda_title)
TextView mAgendaTitleTextView;
@BindView(R.id.id_text_view_agenda_speaker)
TextView mAgendaSperkerTextView;
@BindView(R.id.id_text_view_agenda_time)
TextView mAgendaTimeTextView;
@BindView(R.id.id_btn_show_agenda_file)
Button mAgendaFileButton;
public AgendaDetailHolder(View itemView){
super(itemView);
ButterKnife.bind(this, itemView);
}
}
关键来了
@Override
public void showAgendasList(List<Agenda> agendas) {
mAgendasList = agendas;
mAgendaListAdapter = new AgendaListAdapter(getContext(), mAgendasList);
mAgendaRecyclerView.setLayoutManager(
new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
mAgendaRecyclerView.setAdapter(mAgendaListAdapter);
mAgendaListAdapter.setOnItemClickListener(this);
mPresenter.showAgendaDetail(agendas.get(0));
mAgendaDetailAdapter = new AgendaDetailListAdapter(getContext(), mAgendasList);
mAgendaDetailAdapter.setOnFileDetailClickListener(this);
mAgendaDetailRecyclerView.setLayoutManager(
new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
mAgendaDetailRecyclerView.setAdapter(mAgendaDetailAdapter);
mAgendaDetailRecyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(event.getAction() == MotionEvent.ACTION_DOWN){
mX = event.getX();
mY = event.getY();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
if (event.getY() - mY > 50) {
Log.d("test", "Scroll to" + currentAgendaPositon);
onAgendaItemClick(currentAgendaPositon - 1 >= 0 ? --currentAgendaPositon
: 0);
} else if (mY - event.getY() > 50) {
onAgendaItemClick(currentAgendaPositon + 1 < mAgendasList.size() ? ++currentAgendaPositon
: currentAgendaPositon);
Log.d("test", "Scroll to" + currentAgendaPositon);
}
}
return false;
}
});
}
最关键的部分就是setOnTouchListener
在这里我们要对触摸进行监听,当手势是上下滑动时,调用
onAgendaItemClick(currentAgendaPositon - 1 >= 0 ? --currentAgendaPositon
: 0);
而实现在这里
@Override
public void onAgendaItemClick(int position) {
int childCount = mAgendaRecyclerView.getChildCount();
setBackgroundColor(childCount, position);
currentAgendaPositon = position;
Log.d("test", "Click:" + currentAgendaPositon);
mPresenter.showAgendaDetail(mAgendasList.get(position));
}
最终调用
@Override
public void showAgendaDetail(Agenda agenda) {
mAgendaDetailRecyclerView.smoothScrollToPosition(currentAgendaPositon);
}
这个API是至关重要的:smoothScrollToPosition
它让你能够实现你滑动一段具体就翻页的效果,而不是像原来的RecyclerView一样只能来回滑动,不能自己翻页
通过这个简单的实现我们就可以实现翻页的效果了!
虽然还有一些问题要解决,比如你翻页了左边的列表也要变到选择的项,左边点击了列表项你也要能翻页,不过同步问题非常简单,很容易就实现了。
这个实现比别的实现要简单许多,只不过对触摸的监测我也是才写的,可能有些BUG,还需要一点一点解决,不过大体的思路是可以实现的。