一、顶部标题显示和隐藏渐变效果
1.1 简单显示和隐藏
1.2 渐变效果
1.3 通过设置背景颜色实现
监听滚动,通过设置背景颜色alpha(范围0~255),实现布局渐变。
1.4 实现方式如下
xml 布局 ``` <?xml version=”1.0” encoding=”utf-8”?>
<RelativeLayout
android:id="@+id/rl_scroll_title_titleWhite"
android:layout_width="match_parent"
android:layout_height="45dp"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/white"
android:visibility="gone"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:src="@mipmap/ic_navigation_back_white"
android:tint="@color/red"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="标题部分"
android:layout_centerInParent="true"/>
</RelativeLayout>
- 2. activity 部分,所有实现都在这里面
重点关注这三个方法就可以了。
> 1.监听滚动,只控制显示和隐藏,布局初始隐藏,不用设置渐变度scrollListener()
> 2.监听滚动,通过设置alpha(范围0~1),实现布局渐变scrollListener2()
> 3,监听滚动,通过设置背景颜色alpha(范围0~255),实现布局渐变scrollListener3()
class ScrollTitleActivity : BaseActivity(R.layout.activity_scroll_title) { override fun initData() {
}
private var hasMeasured = false
override fun initEvent() {
//onCreate中获取控件的高度,参考: https://blog.csdn.net/wangzhongshun/article/details/105196366
//方法一
// tv_scroll_title_one.post { // val height = tv_scroll_title_one.height // LogUtils.e(“height=$height”)//height=750 // } //方法二 tv_scroll_title_one.viewTreeObserver.addOnPreDrawListener { //不做处理会一直重复调用,调用一次就够了 if (!hasMeasured){ val height = tv_scroll_title_one.height LogUtils.e(“height=$height”)//height=750 hasMeasured = true } true//返回true为可用状态 } } override fun onWindowFocusChanged(hasFocus: Boolean) { super.onWindowFocusChanged(hasFocus) //方法三,会重复调用,当Activity的窗口得到焦点和失去焦点时均会被调用一次,如果频繁地进行onResume和onPause,那么onWindowFocusChanged也会被频繁地调用,不太适合处理一些复杂的业务逻辑 val height = tv_scroll_title_one.height LogUtils.e(“height=$height”) }
@RequiresApi(Build.VERSION_CODES.M)
override fun initInterface() {
//1.监听滚动,只控制显示和隐藏,布局初始隐藏,不用设置渐变度
//scrollListener()
//2.监听滚动,通过设置alpha(范围0~1),实现布局渐变
//scrollListener2()
//3,监听滚动,通过设置背景颜色alpha(范围0~255),实现布局渐变
//scrollListener3()
}
@RequiresApi(Build.VERSION_CODES.M)
private fun scrollListener3() {
//初始进入隐藏,Color.argb转换工具https://www.wanandroid.com/tools/color
rl_scroll_title_titleWhite.visibility = View.GONE
rl_scroll_title_title.visibility = View.VISIBLE
sv_scroll_title_outer.setOnScrollChangeListener { view, i, i2, i3, i4 ->
val height = rl_scroll_title_title.height
LogUtils.e("i2 = $i2 ----------- height = $height")
if (i2 <= 0){
LogUtils.e("gone")
rl_scroll_title_titleWhite.visibility = View.GONE
rl_scroll_title_titleWhite.setBackgroundColor(Color.argb(0, 255, 255, 255))
}else if (i2 <= height){
rl_scroll_title_titleWhite.visibility = View.VISIBLE
val scale = i2.toFloat() / height
val alpha = (scale * 255).toInt()
LogUtils.e("scale = $scale ---- alpha = $alpha")
rl_scroll_title_titleWhite.setBackgroundColor(Color.argb(alpha, 255, 255, 255))
}else{
LogUtils.e("visible")
rl_scroll_title_titleWhite.visibility = View.VISIBLE
rl_scroll_title_titleWhite.setBackgroundColor(ContextCompat.getColor(this,R.color.white))
}
}
}
/**
* 监听滚动,通过设置alpha,实现布局渐变
*/
@RequiresApi(Build.VERSION_CODES.M)
private fun scrollListener2() {
rl_scroll_title_titleWhite.alpha = 0f
rl_scroll_title_titleWhite.visibility = View.VISIBLE
//这种情况,height不会为0,不需要处理
sv_scroll_title_outer.setOnScrollChangeListener { p0, p1, p2, p3, p4 ->
LogUtils.e("p2=$p2")
if (p2 <= 0) {
rl_scroll_title_titleWhite.alpha = 0f
} else if (p2 < rl_scroll_title_titleWhite.height) {
//1.监听滚动,直接设置控件的透明度来实现标题渐变
//3,根据某个控件设置滚动到某个控件时,完全不透明
val scale = p2.toFloat() / (rl_scroll_title_titleWhite.height)
rl_scroll_title_titleWhite.alpha = scale
} else {
rl_scroll_title_titleWhite.alpha = 1f
}
}
}
/**
* 监听滚动,只控制显示和隐藏,布局初始隐藏,不用设置渐变度
*/
@RequiresApi(Build.VERSION_CODES.M)
private fun scrollListener() {
//初始进入隐藏
rl_scroll_title_titleWhite.visibility = View.GONE
sv_scroll_title_outer.setOnScrollChangeListener { p0, p1, p2, p3, p4 ->
//获取rl_scroll_title_title控件的高度
val height = rl_scroll_title_titleWhite.height
LogUtils.e("p2=$p2---height=$height")
if (p2 <= height) {
//1.监听滚动,直接设置控件的透明度来实现标题渐变
rl_scroll_title_titleWhite.visibility = View.GONE
LogUtils.e("gone")
} else {
//初始进入 height 为 0
if (height == 0){
rl_scroll_title_titleWhite.visibility = View.INVISIBLE
}else{
rl_scroll_title_titleWhite.visibility = View.VISIBLE
}
LogUtils.e("visible")
}
}
}
override fun initIsToolbar(): Boolean {
return false
}
override fun onReload() {
}
}
<a name="dJkVl"></a>
## 二、吸顶,悬浮标题实现
<a name="skegm"></a>
### 2.1 通过两个 View 控制显示和隐藏实现
![iShot2020-09-1400.05.07.gif](https://cdn.nlark.com/yuque/0/2020/gif/1624725/1600013139931-9b8d4839-1cf7-41ff-82a8-1e58cd1622aa.gif#align=left&display=inline&height=1016&margin=%5Bobject%20Object%5D&name=iShot2020-09-1400.05.07.gif&originHeight=1016&originWidth=614&size=2955058&status=done&style=none&width=614)
- 布局文件
<?xml version=”1.0” encoding=”utf-8”?>
- activity
class ScrollStickActivity : BaseActivity(R.layout.activityscroll_stick) {
override fun initData() {
}
override fun initEvent() {
}
@RequiresApi(Build.VERSION_CODES.M)
override fun initInterface() {
//监听滚动
sv_scroll_stick_scroll.setOnScrollChangeListener { view, i, i2, i3, i4 ->
if (i2 > tv_scroll_stick_one.height){
tv_scroll_stick_stick2.visibility = View.VISIBLE
}else{
tv_scroll_stick_stick2.visibility = View.GONE
}
}
}
override fun onReload() {
}
}
```
### 2.2 和上面的方法类似,通过 addView 和 removeView 实现
缺点是当包裹内容布局中带有滑动特性的View(ListView,RecyclerView等),* 我们需要额外处理滑动冲突,并且这种包裹方式,会使得它们的缓存模式失效。_- 布局 ``` <?xml version=”1.0” encoding=”utf-8”?>
</LinearLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/yellow_FF9B52"/>
<TextView
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/green_07C0C2"/>
<TextView
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/red_F7E6ED"/>
<TextView
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/black_999999"/>
</LinearLayout>
</com.kiwilss.xview.ui.view.scrollview.widget.ObservableScrollView>
- activity
class ScrollStickActivity2 : BaseActivity(R.layout.activity_scroll_stick2) {
override fun initData() {
}
override fun initEvent() {
}
override fun initInterface() {
//监听滚动
sv_scroll_stick2_scroll.setScrollViewListener { scrollView, x, y, oldx, oldy ->
val h = tv_scroll_stick2_header.height
val height = ll_scroll_stick2_stick.top
LogUtils.e(“h = $h —- top = $height”)
if (y > 0 && y >= height){
//addview
if (rl_scroll_stick2_stick.parent != ll_scroll_stick2_title) {
ll_scroll_stick2_stick.removeView(rl_scroll_stick2_stick)
ll_scroll_stick2_title.addView(rl_scroll_stick2_stick)
}
}else{
//remove view
if (rl_scroll_stick2_stick.parent != ll_scroll_stick2_stick) {
ll_scroll_stick2_title.removeView(rl_scroll_stick2_stick)
ll_scroll_stick2_stick.addView(rl_scroll_stick2_stick)
}
}
}
}
override fun onReload() {
}
}
<a name="IVJxO"></a>
### 2.3 通过 MD 折叠布局实现
![iShot2020-09-1400.10.50.gif](https://cdn.nlark.com/yuque/0/2020/gif/1624725/1600013469832-98d69ed0-7860-48fe-bbf3-1c36c918eccb.gif#align=left&display=inline&height=1048&margin=%5Bobject%20Object%5D&name=iShot2020-09-1400.10.50.gif&originHeight=1048&originWidth=622&size=6804567&status=done&style=none&width=622)
- 布局
<?xml version=”1.0” encoding=”utf-8”?>
</androidx.core.widget.NestedScrollView>
- activity,可以什么都不用做就可以实现
class NestScrollStickActivity : BaseActivity(R.layout.activity_nestscroll_stick) {
override fun initData() {
}
override fun initEvent() {
}
override fun initInterface() {
//滚动监听,可以直接调用
nsv_scroll_stick_outer.setOnScrollChangeListener { v: NestedScrollView?, scrollX: Int, scrollY: Int, oldScrollX: Int, oldScrollY: Int ->
LogUtils.e("x = $scrollX --- y = $scrollY")
}
}
override fun initIsToolbar(): Boolean {
return false
}
}
<a name="0Zkde"></a>
### 2.4 ObservableScrollView
上面用到了自定义 ScrollView 帮助实现滚动监听,可以直接使用 NestScrollView。下面是自定义 ScrollView:
public class ObservableScrollView extends ScrollView {
private ScrollViewListener scrollViewListener = null;
public ObservableScrollView(Context context) {
super(context);
}
public ObservableScrollView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public ObservableScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setScrollViewListener(ScrollViewListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
@Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (scrollViewListener != null) {
scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
}
}
}
```
public interface ScrollViewListener {
void onScrollChanged(ObservableScrollView scrollView, int x, int y, int oldx, int oldy);
}
2.5 多个标题悬浮
使用自定义 View 实现,这个方法可以满足一个标题悬浮和多个标题悬浮,使用的关键点在于在想要悬浮的控件上加上 tag 属性,android:tag=”sticky”,只要加上这个就可以实现吸顶效果。
xml ``` <?xml version=”1.0” encoding=”utf-8”?>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_scroll_title_one"
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/colorAccent"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@color/white"
android:visibility="visible"
android:tag="sticky"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第一个悬停部分"
android:layout_centerInParent="true"/>
</RelativeLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/yellow_FF9B52"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@color/white"
android:visibility="visible"
android:tag="sticky"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第二个悬停部分"
android:layout_centerInParent="true"/>
</RelativeLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/green_07C0C2"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="45dp"
android:background="@color/white"
android:visibility="visible"
android:tag="sticky"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="第三个悬停部分"
android:layout_centerInParent="true"/>
</RelativeLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/red_F7E6ED"/>
<TextView
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/black_999999"/>
<TextView
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/blue_74D3FF"/>
<TextView
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/yellow_FF9B52"/>
<TextView
android:layout_width="match_parent"
android:layout_height="250dp"
android:background="@color/colorPrimary"/>
</LinearLayout>
</LinearLayout>
- StickyScrollView
public class StickyScrollView extends NestedScrollView {
/**
* 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";
/**
* Default height of the shadow peeking out below the stuck view.
*/
private static final int DEFAULT_SHADOW_HEIGHT = 10; // dp;
private ArrayList<View> stickyViews;
private View currentlyStickingView;
private float stickyViewTopOffset;
private int stickyViewLeftOffset;
private boolean redirectTouchesToStickyView;
private boolean clippingToPadding;
private boolean clipToPaddingHasBeenSet;
private int mShadowHeight;
private Drawable mShadowDrawable;
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();
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.StickyScrollView, defStyle, 0);
final float density = context.getResources().getDisplayMetrics().density;
int defaultShadowHeightInPix = (int) (DEFAULT_SHADOW_HEIGHT * density + 0.5f);
mShadowHeight = a.getDimensionPixelSize(
R.styleable.StickyScrollView_stuckShadowHeight,
defaultShadowHeightInPix);
int shadowDrawableRes = a.getResourceId(
R.styleable.StickyScrollView_stuckShadowDrawable, -1);
if (shadowDrawableRes != -1) {
mShadowDrawable = context.getResources().getDrawable(
shadowDrawableRes);
}
a.recycle();
}
/**
* Sets the height of the shadow drawable in pixels.
*
* @param height
*/
public void setShadowHeight(int height) {
mShadowHeight = height;
}
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() + stickyViewLeftOffset, getScrollY() + stickyViewTopOffset + (clippingToPadding ? getPaddingTop() : 0));
canvas.clipRect(0, (clippingToPadding ? -stickyViewTopOffset : 0),
getWidth() - stickyViewLeftOffset,
currentlyStickingView.getHeight() + mShadowHeight + 1);
if (mShadowDrawable != null) {
int left = 0;
int right = currentlyStickingView.getWidth();
int top = currentlyStickingView.getHeight();
int bottom = currentlyStickingView.getHeight() + mShadowHeight;
mShadowDrawable.setBounds(left, top, right, bottom);
mShadowDrawable.draw(canvas);
}
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();
}
// only compute the left offset when we start sticking.
stickyViewLeftOffset = getLeftForViewRelativeOnlyChild(viewThatShouldStick);
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);
}
}
}
- attr
三、参考
Android Scrollview上滑停靠—悬浮框停靠在标题栏下方(防微博详情页)
android ScrollView 吸顶效果
Android NestedScrollView滚动到顶部固定子View悬停