当在布局中,当上下滑动,需要某个标题一直显示的情况下:
package com.example.test; import java.util.ArrayList; import android.content.Context; import android.graphics.Canvas; import android.os.Build; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.AlphaAnimation; import android.widget.ScrollView; public class StickyScrollView extends ScrollView { /** * Tag for views that should stick and have constant drawing. e.g. TextViews, ImageViews etc */ public static final String STICKY_TAG = "sticky"; /** * Flag for views that should stick and have non-constant drawing. e.g. Buttons, ProgressBars etc */ public static final String FLAG_NONCONSTANT = "-nonconstant"; /** * Flag for views that have aren't fully opaque */ public static final String FLAG_HASTRANSPARANCY = "-hastransparancy"; private ArrayList<View> stickyViews; private View currentlyStickingView; private float stickyViewTopOffset; private boolean redirectTouchesToStickyView; private boolean clippingToPadding; private boolean clipToPaddingHasBeenSet; private final Runnable invalidateRunnable = new Runnable() { @Override public void run() { if(currentlyStickingView!=null){ int l = getLeftForViewRelativeOnlyChild(currentlyStickingView); int t = getBottomForViewRelativeOnlyChild(currentlyStickingView); int r = getRightForViewRelativeOnlyChild(currentlyStickingView); int b = (int) (getScrollY() + (currentlyStickingView.getHeight() + stickyViewTopOffset)); invalidate(l,t,r,b); } postDelayed(this, 16); } }; public StickyScrollView(Context context) { this(context, null); } public StickyScrollView(Context context, AttributeSet attrs) { this(context, attrs, android.R.attr.scrollViewStyle); } public StickyScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); setup(); } public void setup(){ stickyViews = new ArrayList<View>(); } private int getLeftForViewRelativeOnlyChild(View v){ int left = v.getLeft(); while(v.getParent() != getChildAt(0)){ v = (View) v.getParent(); left += v.getLeft(); } return left; } private int getTopForViewRelativeOnlyChild(View v){ int top = v.getTop(); while(v.getParent() != getChildAt(0)){ v = (View) v.getParent(); top += v.getTop(); } return top; } private int getRightForViewRelativeOnlyChild(View v){ int right = v.getRight(); while(v.getParent() != getChildAt(0)){ v = (View) v.getParent(); right += v.getRight(); } return right; } private int getBottomForViewRelativeOnlyChild(View v){ int bottom = v.getBottom(); while(v.getParent() != getChildAt(0)){ v = (View) v.getParent(); bottom += v.getBottom(); } return bottom; } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if(!clipToPaddingHasBeenSet){ clippingToPadding = true; } notifyHierarchyChanged(); } @Override public void setClipToPadding(boolean clipToPadding) { super.setClipToPadding(clipToPadding); clippingToPadding = clipToPadding; clipToPaddingHasBeenSet = true; } @Override public void addView(View child) { super.addView(child); findStickyViews(child); } @Override public void addView(View child, int index) { super.addView(child, index); findStickyViews(child); } @Override public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) { super.addView(child, index, params); findStickyViews(child); } @Override public void addView(View child, int width, int height) { super.addView(child, width, height); findStickyViews(child); } @Override public void addView(View child, android.view.ViewGroup.LayoutParams params) { super.addView(child, params); findStickyViews(child); } @Override protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); if(currentlyStickingView != null){ canvas.save(); canvas.translate(getPaddingLeft(), getScrollY() + stickyViewTopOffset + (clippingToPadding ? getPaddingTop() : 0)); canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0), getWidth(), currentlyStickingView.getHeight()); if(getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)){ showView(currentlyStickingView); currentlyStickingView.draw(canvas); hideView(currentlyStickingView); }else{ currentlyStickingView.draw(canvas); } canvas.restore(); } } @Override public boolean dispatchTouchEvent(MotionEvent ev) { if(ev.getAction()==MotionEvent.ACTION_DOWN){ redirectTouchesToStickyView = true; } if(redirectTouchesToStickyView){ redirectTouchesToStickyView = currentlyStickingView != null; if(redirectTouchesToStickyView){ redirectTouchesToStickyView = ev.getY()<=(currentlyStickingView.getHeight()+stickyViewTopOffset) && ev.getX() >= getLeftForViewRelativeOnlyChild(currentlyStickingView) && ev.getX() <= getRightForViewRelativeOnlyChild(currentlyStickingView); } }else if(currentlyStickingView == null){ redirectTouchesToStickyView = false; } if(redirectTouchesToStickyView){ ev.offsetLocation(0, -1*((getScrollY() + stickyViewTopOffset) - getTopForViewRelativeOnlyChild(currentlyStickingView))); } return super.dispatchTouchEvent(ev); } private boolean hasNotDoneActionDown = true; @Override public boolean onTouchEvent(MotionEvent ev) { if(redirectTouchesToStickyView){ ev.offsetLocation(0, ((getScrollY() + stickyViewTopOffset) - getTopForViewRelativeOnlyChild(currentlyStickingView))); } if(ev.getAction()==MotionEvent.ACTION_DOWN){ hasNotDoneActionDown = false; } if(hasNotDoneActionDown){ MotionEvent down = MotionEvent.obtain(ev); down.setAction(MotionEvent.ACTION_DOWN); super.onTouchEvent(down); hasNotDoneActionDown = false; } if(ev.getAction()==MotionEvent.ACTION_UP || ev.getAction()==MotionEvent.ACTION_CANCEL){ hasNotDoneActionDown = true; } return super.onTouchEvent(ev); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); doTheStickyThing(); } private void doTheStickyThing() { View viewThatShouldStick = null; View approachingView = null; for(View v : stickyViews){ int viewTop = getTopForViewRelativeOnlyChild(v) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()); if(viewTop<=0){ if(viewThatShouldStick==null || viewTop>(getTopForViewRelativeOnlyChild(viewThatShouldStick) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()))){ viewThatShouldStick = v; } }else{ if(approachingView == null || viewTop<(getTopForViewRelativeOnlyChild(approachingView) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()))){ approachingView = v; } } } if(viewThatShouldStick!=null){ stickyViewTopOffset = approachingView == null ? 0 : Math.min(0, getTopForViewRelativeOnlyChild(approachingView) - getScrollY() + (clippingToPadding ? 0 : getPaddingTop()) - viewThatShouldStick.getHeight()); if(viewThatShouldStick != currentlyStickingView){ if(currentlyStickingView!=null){ stopStickingCurrentlyStickingView(); } startStickingView(viewThatShouldStick); } }else if(currentlyStickingView!=null){ stopStickingCurrentlyStickingView(); } } private void startStickingView(View viewThatShouldStick) { currentlyStickingView = viewThatShouldStick; if(getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)){ hideView(currentlyStickingView); } if(((String)currentlyStickingView.getTag()).contains(FLAG_NONCONSTANT)){ post(invalidateRunnable); } } private void stopStickingCurrentlyStickingView() { if(getStringTagForView(currentlyStickingView).contains(FLAG_HASTRANSPARANCY)){ showView(currentlyStickingView); } currentlyStickingView = null; removeCallbacks(invalidateRunnable); } /** * Notify that the sticky attribute has been added or removed from one or more views in the View hierarchy */ public void notifyStickyAttributeChanged(){ notifyHierarchyChanged(); } private void notifyHierarchyChanged(){ if(currentlyStickingView!=null){ stopStickingCurrentlyStickingView(); } stickyViews.clear(); findStickyViews(getChildAt(0)); doTheStickyThing(); invalidate(); } private void findStickyViews(View v) { if(v instanceof ViewGroup){ ViewGroup vg = (ViewGroup)v; for(int i = 0 ; i<vg.getChildCount() ; i++){ String tag = getStringTagForView(vg.getChildAt(i)); if(tag!=null && tag.contains(STICKY_TAG)){ stickyViews.add(vg.getChildAt(i)); }else if(vg.getChildAt(i) instanceof ViewGroup){ findStickyViews(vg.getChildAt(i)); } } }else{ String tag = (String) v.getTag(); if(tag!=null && tag.contains(STICKY_TAG)){ stickyViews.add(v); } } } private String getStringTagForView(View v){ Object tagObject = v.getTag(); return String.valueOf(tagObject); } private void hideView(View v) { if(Build.VERSION.SDK_INT>=11){ // v.setAlpha(0); }else{ AlphaAnimation anim = new AlphaAnimation(1, 0); anim.setDuration(0); anim.setFillAfter(true); v.startAnimation(anim); } } private void showView(View v) { if(Build.VERSION.SDK_INT>=11){ // v.setAlpha(1); }else{ AlphaAnimation anim = new AlphaAnimation(0, 1); anim.setDuration(0); anim.setFillAfter(true); v.startAnimation(anim); } } }
然后在布局中,把滑动放进去
<com.example.test.StickyScrollView android:layout_width="fill_parent" android:layout_height="wrap_content" xmlns:android="http://schemas.android.com/apk/res/android"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <ImageView android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="center" android:src="@drawable/ic_launcher" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> </FrameLayout> <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:background="#ffffffff" android:padding="5.0dip" android:tag="sticky-nonconstant-hastransparancy" > <TextView android:id="@+id/price" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_vertical" android:text="1111111111111111111111111111111" android:textSize="30.0dip" /> </RelativeLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dip" android:layout_gravity="center_horizontal|bottom" android:padding="12dip" android:background="#AA000000" android:textColor="#ffffffff" android:text="Golden Gate" /> </LinearLayout> <!-- <ViewStub android:id="@+id/stub_import" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout="@layout/title" /> --> </LinearLayout> </com.example.test.StickyScrollView>
相关推荐
本知识点主要探讨如何实现“滑动ListView时标题置顶”和“ListView吸顶效果”,以及如何使安卓系统状态栏透明化。这些功能可以为用户带来更流畅、更具吸引力的交互体验。 首先,滑动ListView时标题置顶的效果通常被...
在开发中,有时我们需要实现一个功能,当用户上滑ListView时,某些特定的条目能够“漂浮”在顶部,即使列表继续滚动,这些条目依然保持可见,这就是所谓的"滑动置顶漂浮"效果。这个功能在很多应用中都有所应用,例如...
在Android开发中,滑动置顶标题是一种常见的交互设计,它通常用于新闻列表、论坛帖子等场景,使得用户可以方便地查看和切换不同主题的内容。本文将深入探讨如何实现这样的功能,主要涉及Android布局设计、触摸事件...
【标题】:“一个Android桌面滑动切换屏幕的控件(二)” 在Android开发中,为用户提供流畅且直观的界面交互至关重要,而滑动切换屏幕是实现这一目标的关键技术之一。这个博客“一个Android桌面滑动切换屏幕的控件(二...
在许多应用中,我们可能需要实现一个功能,当ScrollView滚动到顶部时,某个视图(比如一个标题或者搜索栏)固定在屏幕顶部,这就是所谓的"滑动置顶"效果。这个效果通常用于提供更好的用户体验,使用户在滚动内容时...
自动滑动屏幕功能,可以自动滑动微视、抖音等。可以解放双手,让程序自己跑起来。滑动时间也是随机的,模拟人看时间时间。
Android-滑动屏幕调整屏幕亮度.zip Android-滑动屏幕调整屏幕亮度.zip Android-滑动屏幕调整屏幕亮度.zip Android-滑动屏幕调整屏幕亮度.zip Android-滑动屏幕调整屏幕亮度.zip
在Android开发中,实现“左右滑动切换屏幕,上下滑动滚屏”的功能是一项常见的需求,这涉及到Android的触摸事件处理、布局管理以及视图滚动技术。以下将详细阐述这一主题。 1. 触摸事件处理 Android系统通过...
在Android开发中,滑动标题(Sliding Title)是一种常见的用户界面设计,它提供了一种动态展示和隐藏标题的方式,增强了用户体验。这个“android滑动标题demo”是为开发者提供了一个实现滑动标题功能的实例,它实现...
在Android应用开发中,滑动屏幕切换界面显示是一种常见的交互方式,这通常涉及到视图的切换和管理。在这个场景中,我们使用了Fragment这一核心组件来处理界面的展示。Fragment可以理解为一个轻量级的Activity,可以...
这种效果主要体现在用户上下滑动屏幕时,标题栏的颜色或透明度会逐渐变化,为用户带来更生动、自然的浏览体验。在Android和iOS平台上,这种效果可以通过编程实现。 在Android开发中,我们可以使用`...
在Android开发中,"防QQListView滑动置顶删除功能"是一种常见的用户界面交互设计,主要应用于消息列表或社交应用中。QQListView是基于Android原生ListView进行优化的一种视图组件,它提供了更加丰富的功能,如滑动...
本教程将深入讲解如何在RecyclerView中实现横向和纵向滑动,并实现滑动置顶以及跳转到特定项的功能。 首先,我们需要理解RecyclerView的基本结构。它包含一个Adapter,用于填充数据到视图,和一个LayoutManager,...
当内容超过屏幕大小时,用户可以通过滑动查看所有内容。在这个案例中,当ScrollView滚动时,标题栏的渐变隐藏效果会被触发。 - **XListView**:XListView是基于ListView的一个扩展,除了基本的列表滚动功能外,还...
在Android开发中,实现"向上滑动隐藏标题栏,向下滑动显示标题栏"的效果是一项常见的用户界面交互设计,尤其适用于手机应用中,以优化用户体验并最大化屏幕空间。这个功能通常被称为滑动手势控制的头部布局,使得...
然而,在实际应用中,我们经常遇到标题栏在用户滚动列表时的交互需求,比如标题随着ListView的滑动而隐藏或显示,以优化用户体验并提高界面的空间利用率。本教程将详细讲解如何实现这个功能,同时解决滑动过程中可能...
滑动屏幕调整屏幕亮度
在移动应用设计中,"滑动屏幕左侧返回"是一种常见的交互模式,特别是在Android和iOS平台上的应用程序。这个功能使得用户可以通过在屏幕上从左向右滑动来触发返回操作,简化了用户界面,提高了操作效率。以下是对这一...
标题置顶是指当用户滚动ListView时,某个特定的标题项(通常对应一个数据分组)会固定在屏幕顶部,即使在列表滚动过程中,这个标题依然可见,直到下一个标题出现并将其替换。这使得用户在浏览长列表时能清晰地识别...
Android仿ios微信滑动删除、置顶的实现: 左划ListView的item,当前条目出现“删除”和“置顶”两个按钮,点击其他位置,按钮隐藏,点击“删除”,当前条目消失。点击“置顶”,当前条目显示在第一行