将 ImageView 锚定到折叠工具栏

Posted

技术标签:

【中文标题】将 ImageView 锚定到折叠工具栏【英文标题】:Anchor ImageView to Collapsing Toolbar 【发布时间】:2016-04-10 12:09:03 【问题描述】:

当 FloatingActionButton 锚定到 CollapsingToolbarLayout 时,它会在您向上滚动时消失,在您向下滚动到某个点后重新出现。我想知道您是否可以使用任何类型的视图来做到这一点。在我的应用程序中,我试图将 ImageView 锚定到 CollapsingToolbarLayout 但它不会像 FloatingActionButton 那样消失。这是 XML 代码。

<android.support.design.widget.AppBarLayout
    android:id="@+id/bar"
    android:layout_
    android:layout_
    android:fitsSystemWindows="true">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar"
        android:layout_
        android:layout_
        android:fitsSystemWindows="true"
        app:contentScrim="?attr/colorPrimary"
        app:expandedTitleMarginBottom="32dp"
        app:expandedTitleMarginEnd="64dp"
        app:expandedTitleMarginStart="48dp"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

        <ImageView
            android:id="@+id/header"
            android:layout_
            android:layout_
            android:background="@drawable/random"
            android:fitsSystemWindows="true"
            android:scaleType="centerCrop"
            app:layout_collapseMode="parallax" />

        <android.support.v7.widget.Toolbar
            android:id="@+id/anim_toolbar"
            android:layout_
            android:layout_
            app:layout_collapseMode="pin"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" >
            <ImageView
                android:layout_
                android:layout_
                android:layout_gravity="center"/>

        </android.support.v7.widget.Toolbar>
    </android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>

<android.support.v7.widget.RecyclerView
    android:id="@+id/scrollableview"
    android:layout_
    android:layout_
    app:layout_behavior="@string/appbar_scrolling_view_behavior" />

<com.example.sudarshan.testapp.MLRoundedImageView
    android:layout_
    android:layout_
    app:layout_anchor="@+id/bar"
    app:layout_anchorGravity="bottom|center"
    android:id="@+id/circularImage"/>
</android.support.design.widget.CoordinatorLayout>

ImageView 被锚定,但它不会像 FAB 那样消失和重新出现。

【问题讨论】:

【参考方案1】:

这种View消失和出现的行为只与FAB(FloatingActionButton)相关。 你应该看看FloatingActionButton 类的源代码。 这是Behavior 类中的方法,FloatingActionButton 的内部类负责该行为。

@Override
        public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionButton child,
                View dependency) 
            if (dependency instanceof Snackbar.SnackbarLayout) 
                updateFabTranslationForSnackbar(parent, child, dependency);
             else if (dependency instanceof AppBarLayout) 
                // If we're depending on an AppBarLayout we will show/hide it automatically
                // if the FAB is anchored to the AppBarLayout
                updateFabVisibility(parent, (AppBarLayout) dependency, child);
            
            return false;
        

编辑

你可以扩展 FloatingActionButton 类来实现我认为你需要的。

我已经扩展如下-

/**
 * Sked Series, All rights Reserved
 * Created by Sanjeet on 06-Jan-16.
 */
public class FloatingActionImageView extends FloatingActionButton 
    public FloatingActionImageView(Context context) 
        super(context);
    

    public FloatingActionImageView(Context context, AttributeSet attrs) 
        super(context, attrs);
    

    public FloatingActionImageView(Context context, AttributeSet attrs, int defStyleAttr) 
        super(context, attrs, defStyleAttr);
    

    public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) 
        Bitmap sBmp;

        if (bmp.getWidth() != radius || bmp.getHeight() != radius) 
            float smallest = Math.min(bmp.getWidth(), bmp.getHeight());
            float factor = smallest / radius;
            sBmp = Bitmap.createScaledBitmap(bmp, (int) (bmp.getWidth() / factor), (int) (bmp.getHeight() / factor), false);
         else 
            sBmp = bmp;
        

        Bitmap output = Bitmap.createBitmap(radius, radius,
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        final Paint paint = new Paint();
        final Rect rect = new Rect(0, 0, radius + 5, radius + 5);

        paint.setAntiAlias(true);
        paint.setFilterBitmap(true);
        paint.setDither(true);
        canvas.drawARGB(0, 0, 0, 0);
        paint.setColor(Color.parseColor("#BAB399"));
        canvas.drawCircle(radius / 2,
                radius / 2, radius / 2, paint);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(sBmp, rect, rect, paint);

        return output;
    

    @Override
    protected void onDraw(@NonNull Canvas canvas) 

        Drawable drawable = getDrawable();

        if (drawable == null) 
            return;
        

        if (getWidth() == 0 || getHeight() == 0) 
            return;
        
        Bitmap b = ((BitmapDrawable) drawable).getBitmap();
        Bitmap bitmap = null;
        if (b != null) 
            bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
         else 
            BitmapDrawable bitmapDrawable = null;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) 
                bitmapDrawable = ((BitmapDrawable) getResources().getDrawable(com.sked.dd.R.drawable.ic_menu_gallery, null));
             else 
                bitmapDrawable = ((BitmapDrawable) getResources().getDrawable(com.sked.dd.R.drawable.ic_menu_gallery));
            
            if (bitmapDrawable != null) 
                bitmap = bitmapDrawable.getBitmap();
            
        

        int w = getWidth();
        Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
        canvas.drawBitmap(roundBitmap, 0, 0, null);


    

这是输出 -

【讨论】:

真是一个绝妙的解决方案。谢谢【参考方案2】:

经过测试并运行良好

public class RoundedImage extends FloatingActionButton 

public RoundedImage(Context context) 
    super(context);


public RoundedImage(Context context, AttributeSet attrs) 
    super(context, attrs);


public RoundedImage(Context context, AttributeSet attrs, int defStyle) 
    super(context, attrs, defStyle);


@Override
protected void onDraw(Canvas canvas) 
    BitmapDrawable drawable = (BitmapDrawable) getDrawable();

    if (drawable == null) 
        return;
    

    if (getWidth() == 0 || getHeight() == 0) 
        return;
    

    Bitmap fullSizeBitmap = drawable.getBitmap();

    int scaledWidth = getMeasuredWidth();
    int scaledHeight = getMeasuredHeight();

    Bitmap mScaledBitmap;
    if (scaledWidth == fullSizeBitmap.getWidth()
            && scaledHeight == fullSizeBitmap.getHeight()) 
        mScaledBitmap = fullSizeBitmap;
     else 
        mScaledBitmap = Bitmap.createScaledBitmap(fullSizeBitmap,
                scaledWidth, scaledHeight, true );
    



    Bitmap circleBitmap = getCircledBitmap(mScaledBitmap);

    canvas.drawBitmap(circleBitmap, 0, 0, null);



public Bitmap getRoundedCornerBitmap(Context context, Bitmap input,
                                     int pixels, int w, int h, boolean     squareTL, boolean squareTR,
                                     boolean squareBL, boolean squareBR) 

    Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
    Canvas canvas = new Canvas(output);
    final float densityMultiplier = context.getResources()
            .getDisplayMetrics().density;

    final int color = 0xff424242;

    final Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, w, h);
    final RectF rectF = new RectF(rect);

    // make sure that our rounded corner is scaled appropriately
    final float roundPx = pixels * densityMultiplier;

    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(color);
    canvas.drawRoundRect(rectF, roundPx, roundPx, paint);

    // draw rectangles over the corners we want to be square
    if (squareTL) 
        canvas.drawRect(0, 0, w / 2, h / 2, paint);
    
    if (squareTR) 
        canvas.drawRect(w / 2, 0, w, h / 2, paint);
    
    if (squareBL) 
        canvas.drawRect(0, h / 2, w / 2, h, paint);
    
    if (squareBR) 
        canvas.drawRect(w / 2, h / 2, w, h, paint);
    

    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
    canvas.drawBitmap(input, 0, 0, paint);

    return output;


Bitmap getCircledBitmap(Bitmap bitmap) 

    Bitmap result = Bitmap.createBitmap(bitmap.getWidth(),
            bitmap.getHeight(), Config.ARGB_8888);






    Canvas canvas = new Canvas(result);

    int color = Color.BLUE;
    Paint paint = new Paint();
    Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());

    paint.setAntiAlias(true);
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(color);
//        canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
    canvas.drawCircle(bitmap.getWidth()/2, bitmap.getHeight()/2,     bitmap.getHeight()/2, paint);

    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
    canvas.drawBitmap(bitmap, rect, rect, paint);



    return result;



然后在xml中调用

  <yourPackageName.RoundedImage
    android:id="@+id/singleCompLogo"
    android:layout_
    android:layout_
    android:layout_margin="16dp"
    android:clickable="true"
    android:padding="5dp"
    app:layout_collapseMode="parallax"
    app:layout_collapseParallaxMultiplier="0.4"
    app:layout_anchor="@id/app_bar_layout"
    app:civ_border_
    app:layout_anchorGravity="bottom|left|start"
    android:src="@mipmap/image" />

用你的包名替换你的包名

【讨论】:

【参考方案3】:

在您的工具栏 xml 中添加 app:layout_scrollFlags="scroll|enterAlways"

    <android.support.v7.widget.Toolbar
            android:id="@+id/anim_toolbar"
            android:layout_
            android:layout_
            app:layout_collapseMode="pin"
            app:layout_scrollFlags="scroll|enterAlways"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light" >
....
</android.support.v7.widget.Toolbar>

查看here

希望对你有帮助。

【讨论】:

以上是关于将 ImageView 锚定到折叠工具栏的主要内容,如果未能解决你的问题,请参考以下文章

将 Windows 窗体工具提示锚定到鼠标

如何将 UIAlertController 操作表锚定到特定单元格 UICollectionView?

如何将视图锚定到 android 软键盘

如何将 Reality Composer (RealityKit) 场景锚定到检测到的图像

将项目锚定到屏幕中心并带有一些偏移

导航栏可以锚定到特定位置吗?