A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 小鲁哥哥 于 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;
}
第三步初始化两种动画
第四步根据滑动切换状态并执行动画

2 个回复

倒序浏览
回复 使用道具 举报
多谢分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马