用android仿写一个可视化语音信箱界面且保证点击item动画展开可以完全显示

3 篇文章 0 订阅
3 篇文章 0 订阅

    ios 9.2 之后推出了可视化VoiceMail,从开发的角度看问题,发现点击voiceMail 的某一条item的时候,item展开了,并且背景虚化变灰,那么心里面想,如果用android的RecyclerView来做这个界面,点击item之后展开倒不是一个问题,问题在点击之后怎么触发背景变灰而当前item颜色正常呢?这便是我这边博客要解决的问题,这是我第一次写博客,作为一名毕业不到一年的开发者,可能代码设计存在缺陷,如果你看了这篇博客,还劳烦你能批评指正,谢谢!

我需要解决以下问题:

    1,使用RecyclerView动画展开Item。

    2,展开Item之后item的高度改变了,要确保展开后点击的Item完全可见(展开的时候计算滑动距离)。

    3,展开item之后需要将背景变灰,这里并没有盖上一层蒙版也不是去通知每一个item。


首先看一下效果图:




1,使用动画展开Item

      RecyclerView设置为支持动画,并且设置动画时间,来实现展开动画,展开新添View部分可以自己用addView来添加,也可以直接包含在Item的布局里,通过调用可见课隐藏来操作展开和合上,具体代码如下:

     初始化界面设置动画支持:

    /**
     * 界面初始化方法
     */
    private void initView() {
        // 实例化控件
        mRecyclerView = (RecyclerView) findViewById(R.id.recycleview);

        // 设置动画时长
        mRecyclerView.getItemAnimator().setChangeDuration(300);
        mRecyclerView.getItemAnimator().setMoveDuration(300);

        // 初始化界面管理类
        layoutManager  = new LinearLayoutManager(this);

        // 给RecycleView 绑定Manager
        mRecyclerView.setLayoutManager(layoutManager);

        // 实例化数据适配器并绑定在控件上
        mAdapter = new DataAdapter (this,mDatas,this);
        mRecyclerView.setAdapter(mAdapter);
    }

在绘制item里操作显示和隐藏

            title.setText(info.getTitle());
            // opened 纪录当前点开的item position ,未点开为-1.
            if (pos == opened){
                context.setText(info.getDesc());
                context.setVisibility(View.VISIBLE);
            } else{
                context.setVisibility(View.GONE);
            }
            // 判断是否更改背景,模仿出一个item展开后背景黑色的表象
            if(pos == opened){
                total.setBackgroundColor(mContext.getResources().getColor(R.color.white,mContext.getTheme()));
            }else{
                total.setBackgroundColor(mContext.getResources().getColor(R.color.transparent,mContext.getTheme()));
            }

到这里第一步就实现了,下面我们开始来做第二步。


2,展开Item确保其完全可见

    展开Item的时候,Item的高度随着展开而改变,目前我写的demo是通过dp值来固定展开和未展开的item高度值,而非通过计算,这部分是可以通过计算的,具体计算步骤如下:

1,recyclerView.getLayoutManager().getChildAt(position).getHeight()来得到item展开后的值,在调用getScrollY的时候
2,然后判断position-1 或者 position + 1 来得到未展开的值进行计算
3,这里是用position-1 还是 position + 1 通过判断position + 1(或者position - 1)item是否可见来限定时+1 还是 -1,这样之后你可以完全使用像素值进行计算。

但是dp值理论上在手机上是不会改变的,所以我这里就不算了,那是通过打印得到这两个值,这个算法也很简单:

1,判断是否是第一个条目被点击,如果是,返回RecyclerView的滚动距离,这个距离就是当前item的不可见距离,展开之后RecyclerView向下滑动该距离。

2,如果不是第一个item被点击,那么判断RecyclerView滑动距离除以(position*未展开item的高度)为0,且这两者取余不等于0,那么点击的item为可见区域的第一条,且第一条未完全显示,应该向下滑动这个余数的距离。

3,如果不是第一条item被点击,那么判断下RecyclerView滑动距离+RecyclerView的高度 - (position*未展开item的高度)< (position*展开item的高度),那么点击的item展开之后一定为最后一条,且应该向上滑动,让其完全可见,滑动距离为“<”号左右两边的差值。

4,均不满足这上面条件则不需要滑动。


基于上面的流程,写了一个工具类来计算滑动距离,重点算法如下:

    private static int itemHeight = 42;  // 未展开item的高度
    private static int openItemHeight = 158;  // 展开的item的高度

/**
 * 计算滑动的距离
 * @param mLayoutManager  RecyclerView 的管理类
 * @param height    RecyclerView高度
 * @param mContext  上下文
 * @param position  点击的position
 * @return
 */
public static int getScrollY(LinearLayoutManager mLayoutManager, int height, Context mContext, int position) {
    int scrollDistancePx = getScollYDistance(mLayoutManager);
    int scrollDistance = px2dip(mContext,scrollDistancePx);
    height = px2dip(mContext,height);
    // 确定是否为第一条
    if(position == 0){
        return 0 - scrollDistancePx;
    }
    // 判断是否为第一条未显示完全
    if(scrollDistance/(position*itemHeight) == 1 &&
            scrollDistance%(position*itemHeight) != 0){
        // 向下滑动 暂时定义为正数
        return 0 - dip2px(mContext,scrollDistance%(position*itemHeight));
    }
    // 判断是否为最后一条未显示完全
    if((scrollDistance+height) - position*itemHeight < openItemHeight){
        return dip2px(mContext,openItemHeight - (scrollDistance+height) + position*itemHeight);
    }

    return 0;
}


3,更改背景色

    这里将item的背景设置为透明,那么item显示的颜色就是RecycerView的颜色,以至于点击之后更改一下RecyclerView的背景就能达到一个高亮显示当前展开item。这部分目前想到的方法最简单且只刷新点击Item的方法是这样,如果您有好的方法还请告诉我。

在OnBindViewHolder里设置当前点击item为高亮背景,然后在Activity里设置RecyclerView背景为灰色。

            // 判断是否更改背景,模仿出一个item展开后背景黑色的表象
            if(pos == opened){
                total.setBackgroundColor(mContext.getResources().getColor(R.color.white,mContext.getTheme()));
            }else{
                total.setBackgroundColor(mContext.getResources().getColor(R.color.transparent,mContext.getTheme()));
            }

    /**
     * 设置RecycleView的背景,动画时间和voiceMail展开时间一样
     *
     * @param start
     * @param end
     */
    public void setBg(int start , int end){
        ValueAnimator colorAnim = ObjectAnimator.ofInt(mRecyclerView,"backgroundColor", start, end);
        colorAnim.setDuration(300);
        colorAnim.setEvaluator(new ArgbEvaluator());
        colorAnim.setRepeatCount(0);
        colorAnim.setRepeatMode(ValueAnimator.REVERSE);
        colorAnim.start();
    }

到现在就实现了这个效果图的样子,希望批评指正,小弟不胜感激。


demo地址:https://github.com/JakeRed/Demo



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值