Android悬浮按钮锚点位置,Android 滑动定位+吸附悬停效果实现

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

Android 实现锚点定位

Android tabLayout+recyclerView实现锚点定位

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

实现效果:

AAffA0nNPuCLAAAAAElFTkSuQmCC

布局

这里采用的是两个 tablayout。

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

xmlns:app="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

android:id="@+id/scrollView"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:layout_width="match_parent"

android:layout_height="match_parent">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="vertical">

android:layout_width="match_parent"

android:layout_height="200dp"

android:background="#ccc"

android:gravity="center">

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:text="这里是顶部内容区域"

android:textSize="16sp" />

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" />

android:id="@+id/container"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="vertical"

android:padding="16dp" />

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" />

实现

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

数据初始化:

/**

* 占位tablayout,用于滑动过程中去确定实际的tablayout的位置

*/

private TabLayout holderTabLayout;

/**

* 实际操作的tablayout,

*/

private TabLayout realTabLayout;

private CustomScrollView scrollView;

private LinearLayout container;

private String[] tabTxt = {"客厅", "卧室", "餐厅", "书房", "阳台", "儿童房"};

private List 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地址里。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现Vue的吸顶、锚点和滚动高亮按钮效果,可以按照以下步骤进行。 1. 首先,在Vue的组件中引入所需的样式和脚本文件,例如引入Vue的滚动监听插件。 2. 在Vue组件的模板中创建一个父容器,用于包括吸顶和滚动高亮按钮等元素。 3. 在父容器中创建一个吸顶元素,通过添加样式或Vue的动态类绑定来实现吸顶效果。可以使用Vue的computed属性来监听滚动事件,当满足一定条件时,为吸顶元素添加固定定位的样式。 4. 在父容器中创建一个包含多个锚点按钮的元素列表,通过v-for指令循环生成。每个按钮都可以连接到页面中的相应锚点位置,通过给锚点按钮添加点击事件,使用Vue的$refs和scrollIntoView()方法实现平滑滚动到目标锚点位置。 5. 在Vue的data中设置一个用于存储当前高亮按钮索引的变量。通过监听滚动事件,计算滚动位置与每个锚点位置的距离,根据一定的逻辑判断哪个按钮应该被高亮,然后更新当前高亮按钮的索引。 6. 在父容器中使用v-bind:class指令来绑定按钮的样式类,根据当前高亮按钮索引的变化,动态切换高亮样式类。 7. 最后,在Vue的mounted钩子函数中,可以初始化一些数据、监听滚动事件和其他需要的操作,确保这些效果在组件渲染完成后正常运行。 通过以上步骤,就可以实现Vue的吸顶、锚点和滚动高亮按钮效果。利用Vue的动态绑定和事件监听,可以使得这些效果与数据的变化相结合,达到更好的用户体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值