Android 高仿腾讯新闻频道定制页面

栏目: IOS · Android · 发布时间: 5年前

内容简介:移除频道的动画效果模仿得不是很像,如果有更好的实现方法可以在下面留言告诉我。既然它是一个列表,可以拖动,又需要动画,那这里就使用recyclerView+ItemTouchHelper来实现整个页面的效果这里需要新建一个类继承ItemTouchHelper.Callback,并重写其中的几个方法
Android 高仿腾讯新闻频道定制页面
腾讯效果
Android 高仿腾讯新闻频道定制页面
高仿效果

移除频道的动画效果模仿得不是很像,如果有更好的实现方法可以在下面留言告诉我。

页面效果拆解

  • 部分已选频道位置固定,不能拖动
  • 已选频道可以长按拖拽改变顺序,长按后背景色改变,删除按钮隐藏,原本的位置会出现一个虚线的矩形
  • 点击已选频道或删除按钮会移除该频道,这里会分两种情况,若频道属于下方显示的频道,则移动到下方第一个,隐藏删除按钮;不属于则出现一个动画进行移除
  • 点击推荐频道或地方新闻下方内容会进行切换
  • 点击推荐频道或地方新闻下的频道,频道会移动到已选频道的最后一个,同时出现删除按钮

既然它是一个列表,可以拖动,又需要动画,那这里就使用recyclerView+ItemTouchHelper来实现整个页面的效果

拖拽实现

这里需要新建一个类继承ItemTouchHelper.Callback,并重写其中的几个方法

  • public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) 这个方法返回的是拖拽和滑动的方向。一般使用makeMovementFlags(int,int)或者makeFlag(int,int)构造返回值。我们需要的所有方向的拖拽,不需要滑动,所以可以这么写:
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
        int swipeFlags = 0;
        return makeMovementFlags(dragFlags, swipeFlags);
    }
复制代码

但已选频道这里是有一个或多个固定频道的,而且我们是一个recyclerView去实现整个页面,tab及tab下面的item都是不能拖动的,所以还需要处理一下:

public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        //固定位置及tab下面的channel不能拖动
        if (viewHolder.getLayoutPosition() < mAdapter.getFixSize() + 1 || viewHolder.getLayoutPosition() > mAdapter.getSelectedSize()) {
            return makeMovementFlags(0, 0);
        }
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
        int swipeFlags = 0;
        return makeMovementFlags(dragFlags, swipeFlags);
    }
复制代码
  • public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) 当用户拖动item进行移动时会回调这个方法,如果item移动到新的位置,返回true;否则返回false。我们可以在这里实现item的位置交换。要注意的是,某些item是不能改变位置的,所以也要进行处理:
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        int fromPosition = viewHolder.getAdapterPosition();   //拖动的position
        int toPosition = target.getAdapterPosition();     //释放的position
        //固定位置及tab下面的channel不能拖动
        if (toPosition < mAdapter.getFixSize() + 1 || toPosition > mAdapter.getSelectedSize())
            return false;
        mAdapter.itemMove(fromPosition, toPosition);
        return true;
    }
复制代码
  • public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) 当用户滑动item的时候会回调此方法,这里我们不需要滑动,不需要重写这个方法 重写完以上两个方法就可以实现拖拽滑动了,但距离我们想要的效果还是有点差距的。
    Android 高仿腾讯新闻频道定制页面
    长按拖拽的时候item的颜色会改变,出现阴影,删除按钮会隐藏,原本的位置还会出现一个虚线的方框。
    Android 高仿腾讯新闻频道定制页面
    吐槽完了还得继续做啊...... emmmmm...看一下ItemTouchHelper.Callback还有哪些方法能用得上吧
    Android 高仿腾讯新闻频道定制页面
  • public void onSelectedChanged(ViewHolder viewHolder, int actionState) 当viewHolder被拖拽或滑动时回调(感觉这么翻译有点怪...)。这里有个actionState参数,它的值共有3个:ACTION_STATE_IDLE、ACTION_STATE_SWIPE、ACTION_STATE_DRAG。这里可以根据actionState改变item的样式。
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        super.onSelectedChanged(viewHolder, actionState);
        if(actionState==ACTION_STATE_DRAG){
            //长按时调用
            ChannelAdapter.ChannelHolder holder= (ChannelAdapter.ChannelHolder) viewHolder;
            holder.name.setBackgroundColor(Color.parseColor("#FDFDFE"));
            holder.delete.setVisibility(View.GONE);
            holder.name.setElevation(5f);
        }
    }
复制代码

这里需要注意一下,不能当actionState为ACTION_STATE_IDLE时重置item的状态,viewHolder有可能为空指针

  • public void clearView(RecyclerView recyclerView, ViewHolder viewHolder) 当交互完成后会回调此方法。重写这个方法重置item的样式。
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        ChannelAdapter.ChannelHolder holder= (ChannelAdapter.ChannelHolder) viewHolder;
        holder.name.setBackgroundColor(Color.parseColor("#f0f0f0"));
        holder.name.setElevation(0f);
        holder.delete.setVisibility(View.VISIBLE);
    }
复制代码

虚线方框需要绘制,只能找跟draw相关的方法罗

  • onChildDraw
  • onChildDrawOver 区别想必大家都懂的,这里不多说,重写一下onChildDrawOver方法绘制虚线方框。
public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        if (dX != 0 && dY != 0 || isCurrentlyActive) {
            //长按拖拽时底部绘制一个虚线矩形
            c.drawRect(viewHolder.itemView.getLeft(),viewHolder.itemView.getTop()-mPadding,viewHolder.itemView.getRight(),viewHolder.itemView.getBottom(),mPaint);
        }
    }
复制代码
Android 高仿腾讯新闻频道定制页面

适配器

多布局什么的我想大家都懂的,就不细说了。tab这里为了方便直接使用了两个textView实现。 着重说一下要注意的几个地方吧:

  • 频道的长按事件需要返回true,否则长按频道触发拖动但却不移动的话会触发后面的点击事件
  • 如果使用的ItemDecoration,频道添加和删除后需要调用recyclerView.invalidateItemDecorations()刷新ItemDecoration
  • 频道的移除分两种:移除的频道属于当前下方显示的频道,直接移动item,利用系统动画完成;不属于则移动到tab的位置并逐渐消失。 这里我的做法是用ObjectAnimator同时实现平移和透明度动画。但是会出现下面的问题...
    Android 高仿腾讯新闻频道定制页面
    这里(应该是吧,其实我也不太清楚啊...)recyclerView的复用引起的问题,所以在动画结束后需要重置view的属性 emmmm...... 贴一下部分代码吧
private void setChannel(final ChannelHolder holder, ChannelBean bean) {
        final int position = holder.getLayoutPosition();
        holder.name.setText(bean.getName());
        holder.name.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (holder.getLayoutPosition() < selectedSize + 1) {
                    //tab上面的 点击移除
                    removeFromSelected(holder);
                } else {
                    //tab下面的 点击添加到已选频道
                    selectedSize++;
                    itemMove(holder.getLayoutPosition(), selectedSize);
                    notifyItemChanged(selectedSize);
                    if (onItemRangeChangeListener != null) {
                        onItemRangeChangeListener.refreshItemDecoration();
                    }
                }
            }
        });
        holder.name.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                //返回true 防止长按拖拽事件跟点击事件冲突
                return true;
            }
        });
        holder.delete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                removeFromSelected(holder);
            }
        });
    }

    private void removeFromSelected(ChannelHolder holder) {
        int position = holder.getLayoutPosition();
        holder.delete.setVisibility(View.GONE);
        ChannelBean bean = mList.get(position);
        if ((isRecommend && bean.isRecommend()) || (!isRecommend && !bean.isRecommend())) {
            //移除的频道属于当前tab显示的频道,直接调用系统的移除动画
            itemMove(position, selectedSize + 1);
            notifyItemRangeChanged(selectedSize + 1, 1);
            if (onItemRangeChangeListener != null) {
                //如果设置了itemDecoration,必须调用recyclerView.invalidateItemDecorations(),否则间距会不对
                onItemRangeChangeListener.refreshItemDecoration();
            }
        } else {
            //不属于当前tab显示的频道
            removeAnimation(holder.itemView, isRecommend ? mRight : mLeft, mTabY, position);
        }
        selectedSize--;
    }

    void itemMove(int fromPosition, int toPosition) {
        if (fromPosition < toPosition) {
            for (int i = fromPosition; i < toPosition; i++) {
                Collections.swap(mList, i, i + 1);
            }
        } else {
            for (int i = fromPosition; i > toPosition; i--) {
                Collections.swap(mList, i, i - 1);
            }
        }
        notifyItemMoved(fromPosition, toPosition);
    }

}
复制代码

由于使用了textView代替tab,所以会有一些计算用于蓝色线条的位置改变。

Android 高仿腾讯新闻频道定制页面

上面只是我个人的实现方式,如果有更好的方式,可以在下方留言。 最后,奉上源码

java版

kotlin版

kotlin版本的语法可能有点问题,毕竟

Android 高仿腾讯新闻频道定制页面

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Linux Command Line

The Linux Command Line

William E. Shotts Jr. / No Starch Press, Incorporated / 2012-1-17 / USD 39.95

You've experienced the shiny, point-and-click surface of your Linux computer-now dive below and explore its depths with the power of the command line. The Linux Command Line takes you from your very ......一起来看看 《The Linux Command Line》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

html转js在线工具
html转js在线工具

html转js在线工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具