Snackbar getAnchorView() 与父视图

Posted

技术标签:

【中文标题】Snackbar getAnchorView() 与父视图【英文标题】:Snackbar getAnchorView() vs. parent view 【发布时间】:2020-06-24 14:07:47 【问题描述】:

我已阅读 Snackbar documentation

但不确定小吃店的 parentTarget(父视图)和 anchoredView 之间的区别。

如有错误请指正:

1) parent view 是小吃店从该视图沿着 hierchy 视图向上查找 suitable parent view

2) 合适的父视图不是anchoredView。

当一个人设置parentView(ctor 要求)和anchoredView 时会发生什么?

小吃店会在哪里营业?

【问题讨论】:

你自己试过了吗? 【参考方案1】:

SnackBar 的父视图将告诉您哪个容器或布局将 应绘制小吃吧。通常,snackbar 会寻找协调员 布局作为您作为参数传递的视图的父级,如果它 找不到一个它会采取活动内容布局 (android.R.id.content) Framelayout 作为父级。

代码取自SnackBar

@Nullable
    private static ViewGroup findSuitableParent(View view) 
        ViewGroup fallback = null;
        do 
            if (view instanceof CoordinatorLayout) 
                // We've found a CoordinatorLayout, use it
                return (ViewGroup) view;
             else if (view instanceof FrameLayout) 
                if (view.getId() == android.R.id.content) 
                    // If we've hit the decor content view, then we didn't find a CoL in the
                    // hierarchy, so use it.
                    return (ViewGroup) view;
                 else 
                    // It's not the content view but we'll use it as our fallback
                    fallback = (ViewGroup) view;
                
            
            if (view != null) 
                // Else, we will loop and crawl up the view hierarchy and try to find a parent
                final ViewParent parent = view.getParent();
                view = parent instanceof View ? (View) parent : null;
            
         while (view != null);
        // If we reach here then we didn't find a CoL or a suitable content view so we'll fallback
        return fallback;
    

BaseTransientBottomBar 的锚点会告诉你在哪个视图之上 将显示小吃吧。

代码取自BaseTransientBottomBar

private int calculateBottomMarginForAnchorView() 
    if (anchorView == null) 
      return 0;
    

    int[] anchorViewLocation = new int[2];
    anchorView.getLocationOnScreen(anchorViewLocation);
    int anchorViewAbsoluteYTop = anchorViewLocation[1];

    int[] targetParentLocation = new int[2];
    targetParent.getLocationOnScreen(targetParentLocation);
    int targetParentAbsoluteYBottom = targetParentLocation[1] + targetParent.getHeight();

    return targetParentAbsoluteYBottom - anchorViewAbsoluteYTop;
  

...

/** Sets the view the @link BaseTransientBottomBar should be anchored above. */
  @NonNull
  public B setAnchorView(@Nullable View anchorView) 
    this.anchorView = anchorView;
    return (B) this;
  

  /**
   * Sets the id of the view the @link BaseTransientBottomBar should be anchored above.
   *
   * @throws IllegalArgumentException if the anchor view is not found.
   */
  @NonNull
  public B setAnchorView(@IdRes int anchorViewId) 
    this.anchorView = targetParent.findViewById(anchorViewId);
    if (this.anchorView == null) 
      throw new IllegalArgumentException("Unable to find anchor view with id: " + anchorViewId);
    
    return (B) this;
  

你可以在这里找到 SnackBar 的源代码Material SnackBar 和 BaseTransientBottomBar 这里BaseTransientBottomBar

【讨论】:

谢谢,你能用一个例子解释一下两者的区别吗? on top of which view snackbar will be shownon which container or layout will the snackbar should be drawn.

以上是关于Snackbar getAnchorView() 与父视图的主要内容,如果未能解决你的问题,请参考以下文章

Snackbar源码分析

Android SnackBar使用方法

Snackbar 的高度自定义

BottomNavigation 下的 Snackbar

Android Material Design 系列之 SnackBar详解

Vue Snackbar 消息条队列显示,依次动画消失的实现