Android 实现当下最流行的吸顶效果

开始逐渐领略到ItemDecoration的美~

今天让我 使用 ItemDecoration 来完成 可推动的悬浮导航栏的效果,最终实现的效果如下图:

具体实现步骤如下:

根据我前面的文章所讲的RecyclerView的基本使用,我们先来完成基本的recyclerView

第一步:布局里写一个RecyclerView

第二步:实例化

recyclerView = (RecyclerView) findViewById(R.id.recyclerView);

第三步:获取所需的数据 (这里我们来个真实点的情景,去联网请求数据)

/**
 * 联网请求所需的url
 */
 public String url=http://api.meituan.com/mmdb/movie/v2/list/rt/order/coming.json?ci=1&limit=12&token=&__vhost=api.maoyan.com&utm_campaign=AmovieBmovieCD-1&movieBundleVersion=6801&utm_source=xiaomi&utm_medium=android&utm_term=6.8.0&utm_content=868030022327462&net=255&dModel=MI%205&uuid=0894DE03C76F6045D55977B6D4E32B7F3C6AAB02F9CEA042987B380EC5687C43&lat=40.100673&lng=116.378619&__skck=6a375bce8c66a0dc293860dfa83833ef&__skts=1463704714271&__skua=7e01cf8dd30a179800a7a93979b430b2&__skno=1a0b4a9b-44ec-42fc-b110-ead68bcc2824&__skcy=sXcDKbGi20CGXQPPZvhCU3%2FkzdE%3D;
//联网获取数据
 getDataFromNet(); 
/**
 * 使用okhttpUtils进行联网请求数据
 */
 private void getDataFromNet() {
 OkHttpUtils.
 get()
 .url(url)
 .build()
 .execute(new StringCallback() {
  @Override
  public void onError(okhttp3.Call call, Exception e, int id) {
  Log.e("TAG", "联网失败" + e.getMessage());
  } 

  @Override
  public void onResponse(String response, int id) {
  Log.e("TAG", "联网成功==" + response); 

  //联网成功后使用fastjson解析
  processData(response);
  }
 });
 }
/**
 * 使用fastjson进行解析
 *
 * @param json
 */
 private void processData(String json) {
 //这里使用GsonFormat生成对应的bean类
 JSONObject jsonObject = parseObject(json); 

 String data = jsonObject.getString("data");
 JSONObject dataObj = JSON.parseObject(data); 

 String coming = dataObj.getString("coming");
 List<WaitMVBean.DataBean.ComingBean> comingslist = parseArray(coming, WaitMVBean.DataBean.ComingBean.class); 

 //测试是否解析数据成功
// String strTest = comingslist.get(0).getCat();
// Log.e("TAG", strTest + "222"); 

 //解析数据成功,设置适配器--> 

 }
 }

第四步:解析数据成功后,创建并设置适配器,并传递相关数据

//解析数据成功,设置适配器
 MyRecyclerAdapter adapter = new MyRecyclerAdapter( mContext,comingslist);
 recyclerView.setAdapter(adapter);

适配器:

public class MyRecyclerAdapter extends RecyclerView.Adapter {
 private final List<WaitMVBean.DataBean.ComingBean> comingslist;
 private final Context mContext;
 private final LayoutInflater mLayoutInflater;
 public MyRecyclerAdapter(Context mContext, List<WaitMVBean.DataBean.ComingBean> comingslist) {
 this.mContext = mContext;
 this.comingslist = comingslist;
 mLayoutInflater = LayoutInflater.from(mContext);
 }
 @Override
 public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 return new MyViewHolder(mLayoutInflater.inflate(R.layout.date_item, null));
 }
 @Override
 public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
 MyViewHolder myholder = (MyViewHolder) holder;
 myholder.setData(position);
 }
 @Override
 public int getItemCount() {
 return comingslist.size();
 }
 class MyViewHolder extends RecyclerView.ViewHolder {
 private TextView mv_name;
 private TextView mv_dec;
 private TextView mv_date;
 private ImageView imageView;
 public MyViewHolder(View itemView) {
 super(itemView);
 mv_name = (TextView) itemView.findViewById(R.id.mv_name);
 mv_dec = (TextView) itemView.findViewById(R.id.mv_dec);
 mv_date = (TextView) itemView.findViewById(R.id.mv_date);
 imageView = (ImageView) itemView.findViewById(R.id.image);
 }
 public void setData(int position) {
 WaitMVBean.DataBean.ComingBean coming = comingslist.get(position);
 String name = coming.getNm();
 mv_name.setText(name);
 String date = coming.getShowInfo();
 mv_date.setText(date);
 String dec = coming.getScm();
 mv_dec.setText(dec);
 //注:当你发下图片无法打开是,做个字符串替换即可
 String imagUrl = coming.getImg();
 String newImagUrl = imagUrl.replaceAll("w.h", "50.80"); 

 //使用Glide加载图片
 Glide.with(mContext)
  .load(newImagUrl)
  .into(imageView);
 }
 }
}

item的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:background="#ffffff"
 android:gravity="center_vertical"
 android:orientation="horizontal">
 <ImageView
 android:id="@+id/image"
 android:layout_width="70dp"
 android:layout_height="110dp"
 android:layout_marginBottom="5dp"
 android:layout_marginLeft="10dp"
 android:layout_marginRight="8dp"
 android:layout_marginTop="5dp" />
 <LinearLayout
 android:layout_width="0dp"
 android:layout_height="wrap_content"
 android:layout_marginLeft="6dp"
 android:layout_weight="1"
 android:orientation="vertical">
 <TextView
 android:id="@+id/mv_name"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="神奇動物在哪裏"
 android:textColor="#000000"
 android:textSize="15sp" />
 <LinearLayout
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:orientation="horizontal">
 <TextView
 android:layout_width="wrap_content"
android:layout_height="wrap_content"
 android:text="观众"
 android:textColor="#55000000"
 android:textSize="14sp" />
 <TextView
 android:id="@+id/tv_people"
 android:layout_width="wrap_content"
android:layout_height="wrap_content"
 android:text="9.0 "
 android:textColor="#FFCE42"
 android:textSize="18sp" />
 <TextView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text=" | 专业"
 android:textColor="#55000000"
 android:textSize="14sp" />
 <TextView
 android:id="@+id/tv_professional"
 android:layout_width="wrap_content"
android:layout_height="wrap_content"
 android:text="6.7"
 android:textColor="#FFCE42"
 android:textSize="18sp" />
 </LinearLayout>
 <TextView
 android:id="@+id/mv_dec"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginTop="8dp"
 android:text="神奇動物城,法師顯超能"
 android:textColor="#99000000"
 android:textSize="11sp" />
 <TextView
 android:id="@+id/mv_date"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginTop="10dp"
 android:text="今天165家影院放映2088场"
 android:textColor="#99000000"
 android:textSize="11sp" />
 </LinearLayout>
</LinearLayout>

第五步:一定不能忘!!!

recycleView不仅要设置适配器还要设置布局管理者,否则图片不显示

GridLayoutManager manager = new GridLayoutManager(this, 1);
 recyclerView.setLayoutManager(manager);

此时RecyclerView简单的完成效果如下:

下面开始做 可推动的 悬浮导航栏:

第一步:首先我们来写一个类,它起标记的作用,来放每一个item的对应的悬浮栏的字符串

public class NameBean {
 String name;
 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }
}

第二步:自定义一个SectionDecoration 类 继承 RecyclerView的ItemDecoration

public class SectionDecoration extends RecyclerView.ItemDecoration {
 private static final String TAG = "SectionDecoration";
 private List<NameBean> dataList;
 private DecorationCallback callback;
 private TextPaint textPaint;
 private Paint paint;
 private int topGap;
 private int alignBottom;
 private Paint.FontMetrics fontMetrics;
 public SectionDecoration(List<NameBean> dataList, Context context, DecorationCallback decorationCallback) {
 Resources res = context.getResources();
 this.dataList = dataList;
 this.callback = decorationCallback;
 //设置悬浮栏的画笔---paint
 paint = new Paint();
 paint.setColor(res.getColor(R.color.colorGray));
 //设置悬浮栏中文本的画笔
 textPaint = new TextPaint();
 textPaint.setAntiAlias(true);
 textPaint.setTextSize(DensityUtil.dip2px(context, 14));
 textPaint.setColor(Color.DKGRAY);
 textPaint.setTextAlign(Paint.Align.LEFT);
 fontMetrics = new Paint.FontMetrics();
 //决定悬浮栏的高度等
 topGap = res.getDimensionPixelSize(R.dimen.sectioned_top);
 //决定文本的显示位置等
 alignBottom = res.getDimensionPixelSize(R.dimen.sectioned_alignBottom);
 }
 @Override
 public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
 super.getItemOffsets(outRect, view, parent, state);
 int pos = parent.getChildAdapterPosition(view);
 Log.i(TAG, "getItemOffsets:" + pos);
 String groupId = callback.getGroupId(pos);
 if (groupId.equals("-1")) return;
 //只有是同一组的第一个才显示悬浮栏
 if (pos == 0 || isFirstInGroup(pos)) {
 outRect.top = topGap;
 if (dataList.get(pos).getName() == "") {
 outRect.top = 0;
 }
 } else {
 outRect.top = 0;
 }
 }
 @Override
 public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
 super.onDraw(c, parent, state);
 int left = parent.getPaddingLeft();
 int right = parent.getWidth() - parent.getPaddingRight();
 int childCount = parent.getChildCount();
 for (int i = 0; i < childCount; i++) {
 View view = parent.getChildAt(i);
 int position = parent.getChildAdapterPosition(view);
 String groupId = callback.getGroupId(position);
 if (groupId.equals("-1")) return;
 String textLine = callback.getGroupFirstLine(position).toUpperCase();
 if (textLine == "") {
 float top = view.getTop();
 float bottom = view.getTop();
 c.drawRect(left, top, right, bottom, paint);
 return;
 } else {
 if (position == 0 || isFirstInGroup(position)) {
  float top = view.getTop() - topGap;
  float bottom = view.getTop();
  //绘制悬浮栏
  c.drawRect(left, top - topGap, right, bottom, paint);
  //绘制文本
  c.drawText(textLine, left, bottom, textPaint);
 }
 }
 }
 }
 @Override
 public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
 super.onDrawOver(c, parent, state);
 int itemCount = state.getItemCount();
 int childCount = parent.getChildCount();
 int left = parent.getPaddingLeft();
 int right = parent.getWidth() - parent.getPaddingRight();
 float lineHeight = textPaint.getTextSize() + fontMetrics.descent;
 String preGroupId = "";
 String groupId = "-1";
 for (int i = 0; i < childCount; i++) {
 View view = parent.getChildAt(i);
 int position = parent.getChildAdapterPosition(view);
 preGroupId = groupId;
 groupId = callback.getGroupId(position);
 if (groupId.equals("-1") || groupId.equals(preGroupId)) continue;
 String textLine = callback.getGroupFirstLine(position).toUpperCase();
 if (TextUtils.isEmpty(textLine)) continue;
 int viewBottom = view.getBottom();
 float textY = Math.max(topGap, view.getTop());
 //下一个和当前不一样移动当前
 if (position + 1 < itemCount) {
 String nextGroupId = callback.getGroupId(position + 1);
 //组内最后一个view进入了header
 if (nextGroupId != groupId && viewBottom < textY) {
  textY = viewBottom;
 }
 }
 //textY - topGap决定了悬浮栏绘制的高度和位置
 c.drawRect(left, textY - topGap, right, textY, paint);
 //left+2*alignBottom 决定了文本往左偏移的多少(加-->向左移)
 //textY-alignBottom 决定了文本往右偏移的多少 (减-->向上移)
 c.drawText(textLine, left + 2 * alignBottom, textY - alignBottom, textPaint);
 }
 }
 /**
 * 判断是不是组中的第一个位置
 *
 * @param pos
 * @return
 */
 private boolean isFirstInGroup(int pos) {
 if (pos == 0) {
 return true;
 } else {
 // 因为是根据 字符串内容的相同与否 来判断是不是同意组的,所以此处的标记id 要是String类型
 // 如果你只是做联系人列表,悬浮框里显示的只是一个字母,则标记id直接用 int 类型就行了
 String prevGroupId = callback.getGroupId(pos - 1);
 String groupId = callback.getGroupId(pos);
 //判断前一个字符串 与 当前字符串 是否相同
 if (prevGroupId.equals(groupId)) {
 return false;
 } else {
 return true;
 }
 }
 }
 //定义一个借口方便外界的调用
 interface DecorationCallback {
 String getGroupId(int position);
 String getGroupFirstLine(int position);
 }
}

第三步:在向list集合中先把每一个item的 起“标记”作用的字符串都加进去

setPullAction(comingslist);

private void setPullAction(List<WaitMVBean.DataBean.ComingBean> comingslist) {
 dataList = new ArrayList<>();
 for (int i = 0; i < comingslist.size(); i++) {
 NameBean nameBean = new NameBean();
 String name0 = comingslist.get(i).getComingTitle();
 nameBean.setName(name0);
 dataList.add(nameBean);
 }
 }

第四步:在setAdapter() 前,为RecyclerView添加ItemDecoration:

recyclerView.addItemDecoration(new SectionDecoration(dataList,mContext, new SectionDecoration.DecorationCallback() {
 //返回标记id (即每一项对应的标志性的字符串)
 @Override
 public String getGroupId(int position) {
  if(dataList.get(position).getName()!=null) {
  return dataList.get(position).getName();
  }
  return "-1";
 }
  //获取同组中的第一个内容
 @Override
 public String getGroupFirstLine(int position) {
  if(dataList.get(position).getName()!=null) {
  return dataList.get(position).getName();
  }
  return "";
 }
 }));

这样就完成了~

再看一眼最终效果感受一下:

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持我们!

(0)

相关推荐

  • android中RecyclerView悬浮吸顶效果

    MultiType-Adapter打造悬浮吸顶效果 注:当前版本只适合配合RecyclerView快速打造一款 展示UI 悬浮吸顶效果,如 通讯录效果,由于实现机制的原因,暂时不支持触摸事件. MultiType-Adapter介绍地址:MultiType-Adapter 是一款轻量级支持多数据类型的 RecyclerView 适配器; 使用简单,完全解耦; 悬浮吸顶效果 ```groovy // root build.gradle repositories { jcenter() maven

  • Android 实现当下最流行的吸顶效果

    开始逐渐领略到ItemDecoration的美~ 今天让我 使用 ItemDecoration 来完成 可推动的悬浮导航栏的效果,最终实现的效果如下图: 具体实现步骤如下: 根据我前面的文章所讲的RecyclerView的基本使用,我们先来完成基本的recyclerView: 第一步:布局里写一个RecyclerView 第二步:实例化 recyclerView = (RecyclerView) findViewById(R.id.recyclerView); 第三步:获取所需的数据 (这里我们

  • Android进阶CoordinatorLayout协调者布局实现吸顶效果

    目录 引言 1 CoordinatorLayout功能介绍 1.1 CoordinatorLayout的依赖交互原理 1.2 CoordinatorLayout的嵌套滑动原理 2 CoordinatorLayout源码分析 2.1 CoordinatorLayout的依赖交互实现 2.2 CoordinatorLayout交互依赖的源码分析 2.3 CoordinatorLayout子控件拦截事件源码分析 2.4 CoordinatorLayout嵌套滑动原理分析 引言 在上一节Android进

  • Android自定义RecyclerView Item头部悬浮吸顶

    本文实例为大家分享了Android自定义RecyclerView Item头部悬浮吸顶的具体代码,供大家参考,具体内容如下 概述 1.自定义了一个FrameLayout,引入条目的头部布局加入到自定义FrameLayout中. 2.将RecyclerView加入FrameLayout 3.条目头部View的Alpha动画以及设置透明和不透明这个时机大多是通过打log来确定的,硬推理还是有些难. 4.当屏幕显示区域的第二条Item距离控件顶端的距离小于条目头部View高度时,就开始移动条目头部Vi

  • Android实现上拉吸顶效果

    本文实例为大家分享了Android实现上拉吸顶效果的具体代码,供大家参考,具体内容如下 效果图 1.home_layout.xml 此布局即可实现上拉标题固定在顶部 <?xml version="1.0" encoding="UTF-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:app="

  • Android Jetpack Compose实现列表吸顶效果

    目录 stickyHeader 实体类 加载假数据 吸顶标题 二级条目 完整代码 效果图 安卓传统的 Recyclerview 打造悬浮头部StickyHeader的吸顶效果,十分麻烦,而在Compose中就简单多了 stickyHeader Compose设计的时候考虑得很周到,他们提供了stickyHeader 作用就是添加一个粘性标题项,即使在它后面滚动时也会保持固定.标头将保持固定,直到下一个标头取而代之. 参数key - 表示唯一的密钥键. 它不允许对列表出现使用相同的键.密钥的类型应

  • Android进阶NestedScroll嵌套滑动机制实现吸顶效果详解

    目录 引言 1 自定义滑动布局,实现吸顶效果 1.1 滑动容器实现 1.2 嵌套滑动机制完成交互优化 1.2.1 NestedScrollingParent接口和NestedScrollingChild接口 1.2.2 预滚动阶段实现 1.2.3 滚动阶段实现 1.2.4 滚动结束 引言 在上一篇文章Android进阶宝典 -- 事件冲突怎么解决?先从Android事件分发机制开始说起中,我们详细地介绍了Android事件分发机制,其实只要页面结构复杂,联动众多就会产生事件冲突,处理不得当就是b

  • 浅谈react.js中实现tab吸顶效果的问题

    在react项目开发中有一个需求是,页面滚动到tab所在位置时,tab要固定在顶部. 实现的思路其实很简单,就是判断当滚动距离scrollTop大于tab距离页面顶部距离offsetTop时,将tab的position变为fixed. 在react中,我在state中设置一个navTop属性,切换这个属性的值为true或者false,然后tab标签使用classnames()这个方法来利用navTop的值添加类名fixed. 一开始我是这样写的: import cs from 'classnam

  • react-native滑动吸顶效果的实现过程

    前言 最近公司开发方向偏向移动端,于是就被调去做RN(react-native),体验还不错,当前有个需求是首页中间吸顶的效果,虽然已经很久没写样式了,不过这种常见样式应该是so-easy,没成想翻车了,网上搜索换了几个方案都不行,最后去github上复制封装好的库来实现,现在把翻车过程记录下来. 需求效果 翻车过程 第一种方案 失败 一开始的思路是这样的,大众思路,我们需要监听页面的滚动状态,当页面滚动到要吸顶元素所处的位置的时候,我们设置它为固定定位,不过很遗憾,RN对于position属性

  • 微信小程序实现吸顶效果

    最开始的时候,在小程序中实现吸顶效果,开发工具看起来还挺好的,但是在真机上就会有问题了. 原因是我不停的去 setData 会导致操作反馈延迟严重,无法及时将操作处理结果及时传递到视图层. 后面就对代码进行了调整,避免不停的去setData 效果图 吸顶前 吸顶后 代码部分 wxml <view style="width: 90%; height: 300rpx; background: #f0f0f0; margin: 30rpx auto;"></view>

随机推荐