Android 滑动定位和吸附悬停效果实现代码

 更新时间:2018年08月06日 09:29:09   作者:程序猿tx  
这篇文章主要介绍了Android 滑动定位和吸附悬停效果实现代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

在前两篇文章中,分别介绍了tablayout+scrollview 和 tablayout+recyclerview 实现的滑动定位的功能,文章链接:

Android 实现锚点定位

Android tabLayout+recyclerView实现锚点定位

仔细看的话,这种滑动定位的功能,还可以整体滑动,再加上顶部tablayout 吸附悬停的效果。

实现效果:

布局

这里采用的是两个 tablayout。

一个用于占位,位于原始位置,scrollview内部,随scrollview滚动;另一个则是在滑动过程中,不断滑动,滑动到顶部时吸附在屏幕顶部,用户实际操作的也是这个tablayout。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:app="http://schemas.android.com/apk/res-auto"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">

  <com.tabscroll.CustomScrollView
    android:id="@+id/scrollView"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent">

      <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <LinearLayout
          android:layout_width="match_parent"
          android:layout_height="200dp"
          android:background="#ccc"
          android:gravity="center">

          <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="这里是顶部内容区域"
            android:textSize="16sp" />

        </LinearLayout>

        <!--占位的tablayout-->
        <android.support.design.widget.TabLayout
          android:id="@+id/tablayout_holder"
          android:layout_width="match_parent"
          android:layout_height="50dp"
          android:background="#ffffff"
          app:tabIndicatorColor="@color/colorPrimary"
          app:tabMode="scrollable"
          app:tabSelectedTextColor="@color/colorPrimary" />

        <LinearLayout
          android:id="@+id/container"
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:orientation="vertical"
          android:padding="16dp" />

      </LinearLayout>


      <!--实际用户操作的tablayout-->
      <android.support.design.widget.TabLayout
        android:id="@+id/tablayout_real"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#ffffff"
        android:visibility="invisible"
        app:tabIndicatorColor="@color/colorPrimary"
        app:tabMode="scrollable"
        app:tabSelectedTextColor="@color/colorPrimary" />
    </FrameLayout>


  </com.tabscroll.CustomScrollView>

</LinearLayout>

实现

滑动定位的功能可以参考之前的文章,这里主要是进行吸附悬停的效果。

数据初始化:

/**
 * 占位tablayout,用于滑动过程中去确定实际的tablayout的位置
 */
private TabLayout holderTabLayout;
/**
 * 实际操作的tablayout,
 */
private TabLayout realTabLayout;
private CustomScrollView scrollView;
private LinearLayout container;
private String[] tabTxt = {"客厅", "卧室", "餐厅", "书房", "阳台", "儿童房"};

private List<AnchorView> anchorList = new ArrayList<>();

//判读是否是scrollview主动引起的滑动,true-是,false-否,由tablayout引起的
private boolean isScroll;
//记录上一次位置,防止在同一内容块里滑动 重复定位到tablayout
private int lastPos = 0;
//监听判断最后一个模块的高度,不满一屏时让最后一个模块撑满屏幕
private ViewTreeObserver.OnGlobalLayoutListener listener;

for (int i = 0; i < tabTxt.length; i++) {
  AnchorView anchorView = new AnchorView(this);
  anchorView.setAnchorTxt(tabTxt[i]);
  anchorView.setContentTxt(tabTxt[i]);
  anchorList.add(anchorView);
  container.addView(anchorView);
}
for (int i = 0; i < tabTxt.length; i++) {
  holderTabLayout.addTab(holderTabLayout.newTab().setText(tabTxt[i]));
  realTabLayout.addTab(realTabLayout.newTab().setText(tabTxt[i]));
}

一开始让实际的tablayout 移动到占位的tablayout 处,覆盖占位的tablayout。

listener = new ViewTreeObserver.OnGlobalLayoutListener() {
  @Override
  public void onGlobalLayout() {
    //计算让最后一个view高度撑满屏幕
    int screenH = getScreenHeight();
    int statusBarH = getStatusBarHeight(AliHomeMoreActivity.this);
    int tabH = holderTabLayout.getHeight();
    int lastH = screenH - statusBarH - tabH - 16 * 3;
    AnchorView anchorView = anchorList.get(anchorList.size() - 1);
    if (anchorView.getHeight() < lastH) {
      LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
      params.height = lastH;
      anchorView.setLayoutParams(params);
    }

    //一开始让实际的tablayout 移动到 占位的tablayout处,覆盖占位的tablayout
    realTabLayout.setTranslationY(holderTabLayout.getTop());
    realTabLayout.setVisibility(View.VISIBLE);
    container.getViewTreeObserver().removeOnGlobalLayoutListener(listener);

  }
};
container.getViewTreeObserver().addOnGlobalLayoutListener(listener);

private int getScreenHeight() {
  return getResources().getDisplayMetrics().heightPixels;
}

public int getStatusBarHeight(Context context) {
  int result = 0;
  int resourceId = context.getResources()
      .getIdentifier("status_bar_height", "dimen", "android");
  if (resourceId > 0) {
    result = context.getResources().getDimensionPixelSize(resourceId);
  }
  return result;
}

scrollview滑动

主要在滑动过程这不断监听滑动的距离,再移动实际的tablayout ,当在屏幕内时,让其一直覆盖在占位的tablayout 上,看上去是跟着scrollview 一起滑动的;当滑出屏幕时,实际的tablayout 不断移动 使其相对屏幕静止,看上去是吸附在屏幕顶部。

scrollView.setOnTouchListener(new View.OnTouchListener() {
  @Override
  public boolean onTouch(View v, MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
      isScroll = true;
    }
    return false;
  }
});

//监听scrollview滑动
scrollView.setCallbacks(new CustomScrollView.Callbacks() {
  @Override
  public void onScrollChanged(int x, int y, int oldx, int oldy) {
    //根据滑动的距离y(不断变化的) 和 holderTabLayout距离父布局顶部的距离(这个距离是固定的)对比,
    //当y < holderTabLayout.getTop()时,holderTabLayout 仍在屏幕内,realTabLayout不断移动holderTabLayout.getTop()距离,覆盖holderTabLayout
    //当y > holderTabLayout.getTop()时,holderTabLayout 移出,realTabLayout不断移动y,相对的停留在顶部,看上去是静止的
    int translation = Math.max(y, holderTabLayout.getTop());
    realTabLayout.setTranslationY(translation);

    if (isScroll) {
      for (int i = tabTxt.length - 1; i >= 0; i--) {
        //需要y减去顶部内容区域的高度(具体看项目的高度,这里demo写死的200dp)
        if (y - 200 * 3 > anchorList.get(i).getTop() - 10) {
          setScrollPos(i);
          break;
        }
      }
    }

  }
});

private void setScrollPos(int newPos) {
  if (lastPos != newPos) {
    realTabLayout.setScrollPosition(newPos, 0, true);
  }
  lastPos = newPos;
}

tablayout点击切换

由于实际操作的是realtablayout ,所以这里只需要一直监听该tablayout。

//实际的tablayout的点击切换
realTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
  @Override
  public void onTabSelected(TabLayout.Tab tab) {
    isScroll = false;
    int pos = tab.getPosition();
    int top = anchorList.get(pos).getTop();
    //同样这里滑动要加上顶部内容区域的高度(这里写死的高度)
    scrollView.smoothScrollTo(0, top + 200 * 3);
  }

  @Override
  public void onTabUnselected(TabLayout.Tab tab) {

  }

  @Override
  public void onTabReselected(TabLayout.Tab tab) {

  }
});

至此,滑动定位+顶部吸附悬停 的效果结束了。做完之后,再看这个效果,其实和 支付宝-首页 更多 那个页面里的滑动效果一样。

代码与之前文章的在同一个git地址里。

详细代码见

github地址: https://github.com/taixiang/tabScroll

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

相关文章

  • Android架构组件Room指南

    Android架构组件Room指南

    Room是Google推出的Android架构组件库中的数据持久化组件库, 也可以说是在SQLite上实现的一套ORM解决方案。下面通过本文给大家介绍Android架构组件Room指南,需要的朋友参考下吧
    2017-12-12
  • Android实现滑动到顶部悬停的效果

    Android实现滑动到顶部悬停的效果

    这篇文章给大家介绍一种不常见的实现Android滑动到顶部悬停效果的方式,对大家开发Android具有一定的参考借鉴价值,有需要的朋友们可以来一起看看。
    2016-09-09
  • Android回调与观察者模式的实现原理

    Android回调与观察者模式的实现原理

    这篇文章主要为大家详细介绍了Android回调与观察者模式的实现原理,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • Android adb安装apk时提示Invalid APK file的问题

    Android adb安装apk时提示Invalid APK file的问题

    这篇文章主要介绍了Android adb安装apk时提示Invalid APK file的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • Android图片实现压缩处理的实例代码

    Android图片实现压缩处理的实例代码

    本篇文章主要介绍了Android图片实现压缩处理的实例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • Android实现捕获TextView超链接的方法

    Android实现捕获TextView超链接的方法

    这篇文章主要介绍了Android实现捕获TextView超链接的方法,涉及Android查找TextView中超链接的相关实现技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-10-10
  • Android手机卫士之绑定sim卡序列号

    Android手机卫士之绑定sim卡序列号

    这篇文章主要介绍了Android手机卫士之绑定sim卡序列号的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • Android 实现锚点定位思路详解

    Android 实现锚点定位思路详解

    本篇文章就使用tablayout、scrollview来实现android锚点定位的功能。通过<a href="#head" rel="external nofollow" > 去设置页面内锚点定位跳转。具体实现思路大家跟随脚本之家小编一起通过本文看下吧
    2018-07-07
  • Android实现自定义飘雪效果

    Android实现自定义飘雪效果

    随着冬季的脚步越来越远,南方的我今年就看了一场雪,下一场雪遥遥无期,那我们来实现一个自定义的 View,它能模拟雪花飘落的景象,所以本文给大家介绍了基于Android实现自定义飘雪效果,感兴趣的朋友可以参考下
    2024-01-01
  • Android开发事件处理的代码如何写手摸手教程

    Android开发事件处理的代码如何写手摸手教程

    这篇文章主要为大家介绍了Android开发事件处理的代码如何写手摸手教程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02

最新评论