本帖最后由 小鲁哥哥 于 2017-5-21 10:38 编辑
【济南中心】Android课程同步笔记智慧北京:Day04(上)
通过效果图分析这是一个列表结构的视图,因此,我们可以采用RecycleView来实现。 第一步:在NewsCenterContentTabPager中初始化RecycleView
第二步:RecycView的NewsListAdapter实现:
布局结构
[XML] 纯文本查看 复制代码 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:padding="5dp"
android:layout_height="wrap_content">
<ImageView
android:layout_width="100dp"
android:layout_height="70dp"
android:src="@drawable/pic_item_list_default"
android:scaleType="fitXY"
android:id="@+id/iv_icon"
android:padding="1dp"
android:background="@android:color/darker_gray"
/>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="#000"
android:minLines="2"
android:maxLines="2"
android:text="标题"/>
<TextView
android:id="@+id/tv_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="@android:color/darker_gray"
android:text="2016-12-23"/>
</LinearLayout>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:src="@drawable/icon_news_comment_num"/>
</LinearLayout>
第三步:初始化NewsListAdapter:
[Java] 纯文本查看 复制代码 public class NewsListAdapter extends RecyclerView.Adapter {
private Context context;
private List<NewsCenterTabBean.NewsBean> newsBeanList;
public NewsListAdapter(Context context, List<NewsCenterTabBean.NewsBean> newsBeanList) {
this.context = context;
this.newsBeanList = newsBeanList;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.item_news, parent, false);
ViewHolder viewHolder = new ViewHolder(view);
return viewHolder;
}
//绑定数据
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final NewsCenterTabBean.NewsBean newsBean = newsBeanList.get(position);
final ViewHolder viewHolder = (ViewHolder) holder;
Picasso.with(context).load(newsBean.listimage).into(viewHolder.ivIcon);
viewHolder.tvTitle.setText(newsBean.title);
viewHolder.tvTime.setText(newsBean.pubdate);
}
@Override
public int getItemCount() {
return newsBeanList != null ? newsBeanList.size() : 0;
}
static class ViewHolder extends RecyclerView.ViewHolder{
@BindView(R.id.iv_icon)
ImageView ivIcon;
@BindView(R.id.tv_title)
TextView tvTitle;
@BindView(R.id.tv_time)
TextView tvTime;
ViewHolder(View view) {
super(view);
ButterKnife.bind(this, view);
}
}
}
RecyclerView分割线的颜色修改
实现步骤打开【RecycleViewDivider】文件,查看源码 第一步:默认的分割线构造方法实现
第二步:自定义分割线构造方法可以设置分割线的: 方向 分割线的高度 分割线的颜色 第三步:替换自定义分割线构造方法
RecyclerView上拉和下拉加载数据的架构
功能分析
通过分析:RecycleView并没有提供相应的方法,来实现添加头布局和添加脚布局类实现刷新和加载更多的方法。要想使用RecycleView实现下拉刷新和加载更多功能,需要根据RecycleView的adapter,返回条目的类型,来创建头布局和脚布局了。 因此,需要继承RecycleView,自定义RecycleView。 架构设计自定义RecycleView 由Adapter来维护头和脚条目我们知道RecycleView加载显示条目时,是通过Adapter适配器来创建的条目的。 我们可以把头和脚作为RecycleView的条目,由adapter进行维护。 判断头布局和脚布局判断条目是,头还是脚,我们通过一个包装器Adapter,通过getItemViewType,来判断当前是头布局还是脚布局,从而增强Adapter功能。 包装器Adapter的切入点实现RecycleView的setAdapter方法,在该方法中,进行包装适配器 XWrapAdapter的getItemViewType方法的处理
实现步骤第一步:自定义包装适配器
第二步:判断条目的返回类型重写包装器的getItemViewType方法,在该方法中处理条目类型: Position = 0:视为头布局类型 Postion-1 < adapterCount:视为正常数据类型 否则:视为脚布局类型 根据XWrapAdapter的返回类型创建View和绑定View实现步骤第一步:根据返回类型, 创建View第二步:根据返回类型,绑定View 第三步:头布局ViewHolder的创建
第四步:脚布局ViewHolder的创建 第五步:条目个数的返回值设置
注意:这里进行加2的操作,是因为多个一个头布局和脚布局。
在RecylerView中初始化头布局和脚布局并添加到RecylerView上
实现步骤第一步:自定义RecycleView在构造方法中初始化头布局和脚布局 第二步:加载头布局和脚布局
第三步:将头布局和脚布局添加到RecycleView上 重写RecyclerView的setAdapter方法,在该方法中通过,包装适配器XWrapAdapter中,将头和脚布局添加到RecycleView上 将轮播图添加到RefreshRecyclerView的头
成功给RefreshRecyclerView添加了头布局和脚布局。通过观察下面的效果图:我们发现头布局不仅包含下拉刷新的布局,还包含我们的轮播图。因此,我们可以动态的加载轮播图的布局,并添加到头布局中。 实现步骤第一步:提取轮播图控件,作为一个独立布局。由于我们的轮播图控件,写在了【newscenter_content_tab.xml】布局中,和我们新闻中心的子tab界面放在一起的。为了动态加载轮播图布局,因此,需要从【newscenter_content_tab.xml】布局中,提取一个独立布局,去加载布局。轮播图独立布局【switch_imageview.xml】的结构: 布局代码实现: [XML] 纯文本查看 复制代码 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="160dp">
<com.itheima.zhbj.view.SwitchImageViewViewPager
android:id="@+id/vp_switch_image"
android:layout_width="match_parent"
android:layout_height="160dp"></com.itheima.zhbj.view.SwitchImageViewViewPager>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#bf0d0202">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:textColor="#fff"
android:layout_margin="5dp"
android:text="标题"
/>
<LinearLayout
android:id="@+id/ll_point_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:orientation="horizontal"></LinearLayout>
</RelativeLayout>
</RelativeLayout> 第二步:动态加载轮播图布局在新闻中心子tab页面,动态加载轮播图布局,并把轮播图添加给RecyclrView 第三步:将轮播图添加到RefreshRecyclerView中RefreshRecyclerView提供添加轮播图的方法: 动态添加轮播图到头布局中
创建头布局中的下拉刷新布局
功能分析
从下拉刷新的效果图分析: 最外层布局是,线性布局。包含四个子控件 左边是:ImageButton和 ProgressBar 右边是:2 个 TextView
实现步骤第一步:创建头布局文件
[XML] 纯文本查看 复制代码 <?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="wrap_content">
<LinearLayout
android:id="@+id/default_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp">
<ImageView
android:id="@+id/iv_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/common_listview_headview_red_arrow"/>
<ProgressBar
android:id="@+id/pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateDrawable="@drawable/pb_bg"/>
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center_vertical">
<TextView
android:id="@+id/tv_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="#f00"
android:gravity="center"
android:text="下拉刷新"/>
<TextView
android:id="@+id/tv_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="#f00"
android:gravity="center"
android:text="16/10/1 下午:3:50"/>
</LinearLayout>
</LinearLayout>
</LinearLayout> 给进度条设置红色的环形更改圆环进度条默认的样式可通过shape来绘制一个红色圆环,然后通过rotate给红色圆环指定旋转动画将定义好的资源文件,通过progressbar的indeterminateDrawable属性引用。 实现步骤第一步:使用shape绘制红色圆环创建红色圆环资源文件【pb_bg.xml】 [XML] 纯文本查看 复制代码 <?xml version="1.0" encoding="utf-8"?>
<rotate android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
xmlns:android="http://schemas.android.com/apk/res/android">
<shape
android:shape="ring"
android:useLevel="false"
android:innerRadiusRatio="3"
android:thicknessRatio="20">
<gradient
android:startColor="#fff"
android:centerColor="#f19898"
android:endColor="#f00"
android:type="sweep"
/>
</shape>
</rotate> 第二步:给shape添加旋转动画
[XML] 纯文本查看 复制代码 <?xml version="1.0" encoding="utf-8"?>
<rotate android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
xmlns:android="http://schemas.android.com/apk/res/android">
<shape
android:shape="ring"
android:useLevel="false"
android:innerRadiusRatio="3"
android:thicknessRatio="20">
<gradient
android:startColor="#fff"
android:centerColor="#f19898"
android:endColor="#f00"
android:type="sweep"
/>
</shape>
</rotate>
第三步:使用progressbar的indeterminateDrawable属性引用
[XML] 纯文本查看 复制代码 <?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="wrap_content">
<LinearLayout
android:id="@+id/default_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:paddingBottom="5dp">
<ImageView
android:id="@+id/iv_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/common_listview_headview_red_arrow"/>
<ProgressBar
android:id="@+id/pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminateDrawable="@drawable/pb_bg"/>
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center_vertical">
<TextView
android:id="@+id/tv_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textColor="#f00"
android:gravity="center"
android:text="下拉刷新"/>
<TextView
android:id="@+id/tv_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textColor="#f00"
android:gravity="center"
android:text="16/10/1 下午:3:50"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
默认隐藏RefreshRecyclerView的头和脚布局通过给头布局设置它的paddingTop为布局的 – height 高度使RefreshRecyclerView隐藏头布局。 实现步骤第一步:隐藏头布局测量头布局的高度,设置头布局的paddingTop 为 –heigh,修改【RefreshRecyclerView】文件 [XML] 纯文本查看 复制代码 //初始化头
private void initHeaderView() {
mHeaderView = (ViewGroup) inflate(getContext(), R.layout.header, null);
ButterKnife.bind(this, mHeaderView);
//隐藏进度条
pb.setVisibility(View.INVISIBLE);
//测量默认头的高度
defaultHeader.measure(0,0);
//获取测量后的高度
mHeaderMeasuredHeight = defaultHeader.getMeasuredHeight();
//隐藏头
defaultHeader.setPadding(0,-mHeaderMeasuredHeight,0,0);
} 第二步:隐藏脚本布局测量脚布局的高度,设置脚布局的paddingTop 为 –height,修改【RefreshRecyclerView】文件 [XML] 纯文本查看 复制代码 //初始化脚
private void initFooterView() {
mFooterView = inflate(getContext(), R.layout.footer, null);
//测量
mFooterView.measure(0,0);
mFooterMeasuredHeight = mFooterView.getMeasuredHeight();
//隐藏
mFooterView.setPadding(0,-mFooterMeasuredHeight,0,0);
} 处理dispatchTouchEvent方法拖滑出头布局实现思路这里我们可以重写RefreshRecyclerView的dispatchTouchEvent方法 在dispatchTouchEvent监听down , move , up事件 当down:记录按下的downY坐标 当move:记录移动的moveY坐标 计算移动之后的距离: disY = moveY – downY 根据移动的距离计算头布局显示的高度: Top = - headerHeight + disY 设置头布局的paddingTop 实现步骤头布局的滑出实现逻辑: l 重写RefreshRecyclerView的dispatchTouchEvent方法 l 在dispatchTouchEvent监听down , move , up事件 l 当down:记录按下的downY坐标 l 当move:记录移动的moveY坐标 l 计算移动之后的距离: disY = moveY – downY l 根据移动的距离计算头布局显示的高度: l Top = - headerHeight + disY l 判断当前显示的下标是否为0并且disY > 0 l 设置头布局的paddingTop 在【RefreshRecyclerView】文件中重写dispatchTouchEvent方法 [Java] 纯文本查看 复制代码 //分发事件
//原因:没有使用onTouchEvent()是因为dispatchTouchEvent()方法回调的频率高一些
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN://按下
//MyLogger.i(TAG,"按下");
downY = (int) ev.getY();
break;
case MotionEvent.ACTION_MOVE://移动
//MyLogger.i(TAG,"移动");
int moveY = (int) ev.getY();
//条件 RecyclerView的第一个条目的下标是0 && 往下拽的行为
disY = moveY - downY;
int firstVisibleItemPosition = lm.findFirstVisibleItemPosition();
int top = -mHeaderMeasuredHeight + disY;
if(firstVisibleItemPosition == 0 && disY > 0){
//执行头的显示和隐藏操作
defaultHeader.setPadding(0,top,0,0);
}
break;
case MotionEvent.ACTION_UP://弹起
break;
}
return super.dispatchTouchEvent(ev);
} 定义头的三种状态
实现步骤在【RefreshRecyclerView.java】文件中,定义下header的三种状态: 下拉刷新状态 释放刷新状态 正在刷新状态
头布局状态切换以及动画实现实现思路当头布局为下拉刷新并且top>=0(头布局完全显示出来) 更改头布局状为:释放刷新状态 执行动画,逆时针(0, -180)旋转箭头 头布局为释放刷新并且top < 0(头布局开始隐藏) 更改头布局状为:下拉刷新状态 执行动画,逆时针(-180, -360)旋转箭头 实现步骤:第一步:创建动画1:在【RefreshRecyclerView.java】文件中,创建从下拉刷新切换到释放刷新的动画 [Java] 纯文本查看 复制代码 //从下拉刷新切换到释放刷新的动画
private Animation createAnimation1() {
Animation animation = new RotateAnimation(0,-180,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
animation.setDuration(200);
animation.setFillAfter(true);
return animation;
} 第二步:创建动画2:在【RefreshRecyclerView.java】文件中,创建从释放刷新切换到下拉刷新的动画 [Java] 纯文本查看 复制代码 //从释放刷新切换到下拉刷新的动画
private Animation createAnimation2() {
Animation animation = new RotateAnimation(-180,-360,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
animation.setDuration(200);
animation.setFillAfter(true);
return animation;
} 第三步:初始化两种动画
第四步:根据滑动切换状态,并执行动画:
|