Material Design 实现之 RecyclerView基本特性

在上一篇文章中介绍了RecyclerView的基本使用,这节课我们继续介绍RecyclerView的一些高级特性。

轻量化的通知

前面提到RecyclerView的Adapter对数据变动的通知作了优化,更加的精准与轻量。现在我们就来介绍怎么使用。

Adapter的通知分为单体通知和群体通知。在底层的实现中,实际上是最终调用的群体通知。

public final void notifyItemInserted(int position) {
            mObservable.notifyItemRangeInserted(position, 1);
        }
public final void notifyItemMoved(int fromPosition, int toPosition) {
            mObservable.notifyItemMoved(fromPosition, toPosition);
        }
public final void notifyItemRangeInserted(int positionStart, int itemCount) {
            mObservable.notifyItemRangeInserted(positionStart, itemCount);
        }

现在我们就来一个个的进行操作。
比如增加一项数据:

packageInfoList.add(0, packageInfo);
 adapter.notifyItemInserted(0);
 recyclerView.scrollToPosition(0); \\可选,主要作用是让recyclerview滚动至新增加的一行

删除一项数据

packageInfoList.remove(0);
adapter.notifyItemRemoved(0);

更新一项数据,

adapter.notifyItemChanged(0);

对于批量的修改也很简单,只要在以上notify系列的第二个参数加上批量的个数即可。
adapter.notifyItemInserted(0, 100); //从0开始,插入100个数据。

ItemAnimator

由于Adapter的通知非常精准,因此,在对数据删除增加时出动画是非常方便的。只要继承RecyclerView.ItemAnimator这个类。

PS:有点麻烦的是这个类在23.1的版本作了修改,与之前的版本不兼容,Google为了解决这个问题,提供了一个android.support.v7.widget.SimpleItemAnimator来向下兼容,当你的项目升级到23.1而报错的话,只需要把你的基类RecyclerView.ItemAnimator改为SimpleItemAnimator即可。

当然,实现这个类还是比较复杂的,要实现多个方法,指定在不同场景,如添加,删除等动画效果,幸运的是有大牛已经为我们写好一些实现方式,可以满足大多数的需要,使用时只要引用这个库就好。

compile 'jp.wasabeef:recyclerview-animators:2.0.0'

对于23.1以下的编译环境,要使用。原因就是上面我说的不兼容问题导致的。

compile 'jp.wasabeef:recyclerview-animators:1.3.0'

引入这个库后,我们就可以使用代码:

recyclerView.setItemAnimator(new SlideInLeftAnimator());
recyclerView.getItemAnimator().setAddDuration(500);
recyclerView.getItemAnimator().setRemoveDuration(500);
recyclerView.getItemAnimator().setMoveDuration(500);
recyclerView.getItemAnimator().setChangeDuration(500);

ItemDecoration

ListView中有个属性叫divider,用于定义Item之间的分隔线。RecyclerView把这个divider的概念进行了扩展,改为ItemDecoration。这样,我们可以实现的效果就更加灵活,不必从上到下都使用统一的divider效果,完全可以根据不同的item定制不同的特殊效果。当然,灵活带了的问题就是实现上会比之前要复杂一点。

这里用一个例子来讲它的一个实现。

/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
public class DividerItemDecoration extends RecyclerView.ItemDecoration {

    private static final int[] ATTRS = new int[]{
            android.R.attr.listDivider
    };

    public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;

    public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;

    private Drawable mDivider;

    private int mOrientation;

    public DividerItemDecoration(Context context, int orientation) {
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mDivider = a.getDrawable(0);
        a.recycle();
        setOrientation(orientation);
    }

    public void setOrientation(int orientation) {
        if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
            throw new IllegalArgumentException("invalid orientation");
        }
        mOrientation = orientation;
    }
    //这个是重点方法,用于真正绘制所需要的装饰效果,这里分为水平列表和垂直列表,通常情况我们都使用垂直列表,所以这里以垂直列表为例
    @Override
    public void onDraw(Canvas c, RecyclerView parent,RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            drawVertical(c, parent);
        } else {
            drawHorizontal(c, parent);
        }
    }

    public void drawVertical(Canvas c, RecyclerView parent) {
        //首先,我们获取parent的padding,我们的画线不能画到padding外面去吧。
        final int left = parent.getPaddingLeft();
        final int right = parent.getWidth() - parent.getPaddingRight();

        final int childCount = parent.getChildCount();
        //这里,对每一个ChildView都要进行计算和绘制,如果有些ChildView有不一样的地方,可以在这里进行处理。
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int top = child.getBottom() + params.bottomMargin;
            final int bottom = top + mDivider.getIntrinsicHeight();
            //确定divider的位置,这里是画在每一个childView的下面,当然,你可以画在上面画,根据你的需要。
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    public void drawHorizontal(Canvas c, RecyclerView parent) {
        final int top = parent.getPaddingTop();
        final int bottom = parent.getHeight() - parent.getPaddingBottom();

        final int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            final View child = parent.getChildAt(i);
            final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
                    .getLayoutParams();
            final int left = child.getRight() + params.rightMargin;
            final int right = left + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    //这个类主要是返回两个View之间的间距,返回值设置在outRect中,如果你的divider不占空间,则需要把outRect的大小设置为0。
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        if (mOrientation == VERTICAL_LIST) {
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        } else {
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        }
    }
}

遗留问题

由于ItemDecoration不是一个View,因此在动画的时候,不能随着ItemAnimator进行。这样整个效果看起来就比较奇怪。我设想的一种解决方法是不使用这个ItemDecoration机制,把相关的效果直接写在ViewHolder中,不知大家有没有更好的办法。

示例代码:https://github.com/mutsinghua/RecyclerViewDemo.git

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
智慧校园整体解决方案是响应国家教育信息化政策,结合教育改革和技术创新的产物。该方案以物联网、大数据、人工智能和移动互联技术为基础,旨在打造一个安全、高效、互动且环保的教育环境。方案强调从数字化校园向智慧校园的转变,通过自动数据采集、智能分析和按需服务,实现校园业务的智能化管理。 方案的总体设计原则包括应用至上、分层设计和互联互通,确保系统能够满足不同用户角色的需求,并实现数据和资源的整合与共享。框架设计涵盖了校园安全、管理、教学、环境等多个方面,构建了一个全面的校园应用生态系统。这包括智慧安全系统、校园身份识别、智能排课及选课系统、智慧学习系统、精品录播教室方案等,以支持个性化学习和教学评估。 建设内容突出了智慧安全和智慧管理的重要性。智慧安全管理通过分布式录播系统和紧急预案一键启动功能,增强校园安全预警和事件响应能力。智慧管理系统则利用物联网技术,实现人员和设备的智能管理,提高校园运营效率。 智慧教学部分,方案提供了智慧学习系统和精品录播教室方案,支持专业级学习硬件和智能化网络管理,促进个性化学习和教学资源的高效利用。同时,教学质量评估中心和资源应用平台的建设,旨在提升教学评估的科学性和教育资源的共享性。 智慧环境建设则侧重于基于物联网的设备管理,通过智慧教室管理系统实现教室环境的智能控制和能效管理,打造绿色、节能的校园环境。电子班牌和校园信息发布系统的建设,将作为智慧校园的核心和入口,提供教务、一卡通、图书馆等系统的集成信息。 总体而言,智慧校园整体解决方案通过集成先进技术,不仅提升了校园的信息化水平,而且优化了教学和管理流程,为学生、教师和家长提供了更加便捷、个性化的教育体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值