jjzjj

Android ImageView变形: from Square to Circle (Solution updated)

coder 2023-11-29 原文

我正在使用 CircularReveal 创建动画,将方形专辑封面变成圆形。以下是一个简短的 fragment 。

int cx = mImageView.getMeasuredWidth() / 2;
int cy = mImageView.getMeasuredHeight() / 2;

// get the initial radius for the clipping circle
int initialRadius = mImageView.getWidth() / 2;

// create the animation (the final radius is zero)
Animator anim = ViewAnimationUtils.createCircularReveal(mImageView, cx, cy, mImageView.getWidth(), initialRadius);
anim.setDuration(500);
anim.start();

问题是,在动画之后,图像不会保持圆形。我一直在寻找类似 Animation.fillAfter(boolean fillAfter) 调用的东西,但动画师没有那个选项。

以下是当前(故障)行为。

有什么建议可以在动画后将图像固定为圆圈吗?

最佳答案

我通过使用 GradientDrawable 和我的自定义 CardView 将此 CircularRevealView 完全替换为自定义 mask 来解决此问题。

我的 xml (tmp_activity.xml)

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="@color/background_button"
    tools:context=".TempActivity_">

    <com.myapp.customviews.AnimatableCardView
        android:id="@+id/base_view"
        android:layout_marginLeft="@dimen/margin_medium"
        android:layout_centerVertical="true"
        android:layout_width="@dimen/album_art_small"
        android:layout_height="@dimen/album_art_small"
        app:cardElevation="0dp">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_centerVertical="true"
                android:layout_centerHorizontal="true"
                android:src="@drawable/charlie"
                android:id="@+id/imageView2"/>

    </com.myapp.customviews.AnimatableCardView>
</RelativeLayout>

我的 Activity (请注意,我使用的是 Android Annotations,而不是 findViewById(..))

@EActivity(R.layout.tmp_activity)
public class TempActivity extends BaseActivity {
    @ViewById(R.id.base_view)
    ViewGroup mParent;

    @ViewById(R.id.imageView2)
    ImageView mImageView;

    GradientDrawable gradientDrawable;

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    private volatile boolean isCircle = false;
    @Override
    protected void onViewsCreated() {
        super.onViewsCreated();

        gradientDrawable = new GradientDrawable();
        gradientDrawable.setCornerRadius(30.0f);
        gradientDrawable.setShape(GradientDrawable.RECTANGLE);
        mParent.setBackground(gradientDrawable);

        mImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(final View v) {
                if (isCircle) {
                    makeSquare();
                }
                else {
                    makeCircle();
                }
                isCircle = !isCircle;
            }
        });
    }

    private void makeCircle() {
        ObjectAnimator cornerAnimation =
                ObjectAnimator.ofFloat(gradientDrawable, "cornerRadius", 30f, 200.0f);

        Animator shiftAnimation = AnimatorInflater.loadAnimator(this, R.animator.slide_right_down);
        shiftAnimation.setTarget(mParent);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.setDuration(500);
        animatorSet.playTogether(cornerAnimation, shiftAnimation);
        animatorSet.start();
    }

    private void makeSquare() {
        ObjectAnimator cornerAnimation =
                ObjectAnimator.ofFloat(gradientDrawable, "cornerRadius", 200.0f, 30f);

        Animator shiftAnimation = AnimatorInflater.loadAnimator(this, R.animator.slide_left_up);
        shiftAnimation.setTarget(mParent);

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.setDuration(500);
        animatorSet.playTogether(cornerAnimation, shiftAnimation);
        animatorSet.start();
    }
}

我的自定义CardView(AnimatableCardView)

public class AnimatableCardView extends CardView {
    private float xFraction = 0;
    private float yFraction = 0;

    private ViewTreeObserver.OnPreDrawListener preDrawListener = null;

    public AnimatableCardView(Context context) {
        super(context);
    }

    public AnimatableCardView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AnimatableCardView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    // Note that fraction "0.0" is the starting point of the view. This includes margins.
    // If this view was placed in (200,300), moveTo="0.1" for xFraction will give you (220,300)
    public void setXFraction(float fraction) {
        this.xFraction = fraction;

        if (((ViewGroup) getParent()).getWidth() == 0) {
            if (preDrawListener == null) {
                preDrawListener = new ViewTreeObserver.OnPreDrawListener() {
                    @Override
                    public boolean onPreDraw() {
                        getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
                        setXFraction(xFraction);
                        return true;
                    }
                };
                getViewTreeObserver().addOnPreDrawListener(preDrawListener);
            }
            return;
        }

        float translationX = Math.max(0, (((ViewGroup) getParent()).getWidth()) * fraction - (getWidth() * getScaleX() / 2));
        setTranslationX(translationX);
    }

    public float getXFraction() {
        return this.xFraction;
    }

    public void setYFraction(float fraction) {
        this.yFraction = fraction;

        if (((ViewGroup) getParent()).getHeight() == 0) {
            if (preDrawListener == null) {
                preDrawListener = new ViewTreeObserver.OnPreDrawListener() {
                    @Override
                    public boolean onPreDraw() {
                        getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
                        setYFraction(yFraction);
                        return true;
                    }
                };
                getViewTreeObserver().addOnPreDrawListener(preDrawListener);
            }
            return;
        }

        float translationY = Math.max(0, (((ViewGroup) getParent()).getHeight()) * fraction - (getHeight() * getScaleY() / 2));
        setTranslationY(translationY);
    }

    public float getYFraction() {
        return this.yFraction;
    }
}

slide_right_down.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
     android:ordering="together">
        <objectAnimator
            android:interpolator="@android:anim/accelerate_decelerate_interpolator"
            android:propertyName="xFraction"
            android:duration="@android:integer/config_mediumAnimTime"
            android:valueFrom="0.0"
            android:valueTo="0.5"
            android:valueType="floatType"/>

        <objectAnimator
            android:interpolator="@android:anim/accelerate_decelerate_interpolator"
            android:propertyName="yFraction"
            android:duration="@android:integer/config_mediumAnimTime"
            android:valueFrom="0.0"
            android:valueTo="0.1"
            android:valueType="floatType"/>

        <objectAnimator
            android:duration="@android:integer/config_mediumAnimTime"
            android:propertyName="scaleX"
            android:valueFrom="1.0"
            android:valueTo="1.5"/>

        <objectAnimator
            android:duration="@android:integer/config_mediumAnimTime"
            android:propertyName="scaleY"
            android:valueFrom="1.0"
            android:valueTo="1.5"/>
</set>

slide_left_up.xml

<?xml version="1.0" encoding="utf-8"?>
<set android:ordering="together"
     xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:propertyName="xFraction"
        android:duration="@android:integer/config_mediumAnimTime"
        android:valueFrom="0.5"
        android:valueTo="0.0"
        android:valueType="floatType"/>
    <objectAnimator
        android:propertyName="yFraction"
        android:duration="@android:integer/config_mediumAnimTime"
        android:valueFrom="0.1"
        android:valueTo="0.0"
        android:valueType="floatType"/>

    <objectAnimator
        android:duration="@android:integer/config_mediumAnimTime"
        android:propertyName="scaleX"
        android:valueFrom="1.5"
        android:valueTo="1.0"/>

    <objectAnimator
        android:duration="@android:integer/config_mediumAnimTime"
        android:propertyName="scaleY"
        android:valueFrom="1.5"
        android:valueTo="1.0"/>
</set>

这是结果(从设备上看更快更流畅)

关于Android ImageView变形: from Square to Circle (Solution updated),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39840304/

有关Android ImageView变形: from Square to Circle (Solution updated)的更多相关文章

  1. ruby-on-rails - Rails 数据/基准变形问题 - 2

    在我的Rails3.2.6应用程序中,我有一个模型表示有关小部件的数据集合。在我看来,此类的正确名称是WidgetData,复数形式,因为每个小部件有不止一项数据。如果我要求Rails为这个类生成一个表单:=form_for@widget_datado|f|...我得到一个错误ActionView::Template::Error(undefinedmethod'widget_datum_path'...。大概这是因为Rails数据/数据变形规则。我不确定如何最好地解决这个问题:我可以让Rails指示我的模型实际上应该是WidgetDatum。或者我可以以某种方式在这种特殊情况下禁用变

  2. ruby - Ruby 中过去时的 ActiveSupport 变形库? - 2

    是否有ruby​​的过去式库,可以将单词转换为过去式? 最佳答案 查看“verbs”rubygem(github|rubygems|documentation)。在命令行中输入:geminstallverbs将此添加到您的gemfile中:gem"verbs","~>2.1.0"并确保在实现前重启您的Rails服务器并退出您的Rails控制台。 关于ruby-Ruby中过去时的ActiveSupport变形库?,我们在StackOverflow上找到一个类似的问题:

  3. javascript - 使用 Three.js 变形 - 2

    我正在使用Three.js开发一个在线工具,更准确地说,它是关于变形和缩放3d对象的各个部分的。我询问是否有一种方法可以像这样在Three.js中变形对象http://n-e-r-v-o-u-s.com/cellCycle/(横条在右上角),以一种自由的方式。以及我如何建模像环面但具有矩形截面而不是圆形的网格。有人遇到过这种问题吗?提前致谢。 最佳答案 如果您正在考虑创建程序几何体,您可以尝试查看http://mrdoob.github.com/three.js/examples/webgl_geometries2.html它们也可

  4. javascript - 如何使用 JavaScript 修复图像透视变形和旋转? - 2

    我有一些使用手机拍摄的图像。是否有任何JavaScript库可以拉直纸张的照片并将其展平?例如,我想创建一个矩形图像,而该图像没有任何失真。换句话说我想知道如何用JavaScript修复透视扭曲和旋转?例如,我在下面的示例图片中找到了this文章:如何用javascript修复这种类型的图像? 最佳答案 不需要额外的npm包,创建一个不规则的裁剪框就可以实现,首先将图像加载到Canvas中,在图像上调整4个裁剪点,将部分放入一个规则的矩形Canvas中。点击此链接获取详细代码和步骤ImagePerspectivecorrection

  5. javascript - 变形目标 Three.js - 2

    我正在尝试开始使用morphtargets和three.js。然而,关于这个主题的文档似乎并不多。当我查看源代码时,morphTargetInfluences[]似乎很神奇。这是如何运作的?我该如何使用它?值1是全强度吗?如何区分同一模型上的不同变形目标?我只是想了解morphTargetInfluences[]提前致谢 最佳答案 http://threejs.org/examples/webgl_morphtargets.html变形目标是几何体顶点位置的集合,用于在它们之间进行自动插值。您可以使用在morphTargetInfl

  6. javascript - 在 WebGL 和 three.js 中创建图像变形效果 - 2

    我正在学习three.js,尝试尝试转换图像。我非常喜欢显示的效果here.我要遵循哪些步骤才能转换与此类似的图像?到目前为止我有://instantiatealoadervarloader=newTHREE.TextureLoader();//loadaresourceloader.load(//resourceURL'clouds.jpg',//Functionwhenresourceisloadedfunction(texture){init(newTHREE.MeshBasicMaterial({map:texture}));},//Functioncalledwhendown

  7. javascript - 如何使用 snap.svg 为路径变形设置动画 - 2

    我一直在寻找一个关于如何为svg路径变形设置动画的好例子。我知道如何使用SMIL来做一些非常复杂的事情,但是snap.svg是新的和Shiny的,而且每个人似乎都喜欢它,所以我想看一看。我在任何地方都找不到关于如何在任何地方进行动画路径变形的好例子。希望snap.svg专家能为我指明正确的方向?这是svg图像的链接及其代码:linktoimage 最佳答案 不太确定您的意思是只想要Snap中的当前动画还是其他内容。只是举例说明通常如何制作一些动画...s=Snap(400,620);varpath=s.path("M94.2,265

  8. php - Laravel 变形关系 - 2

    我有一个关于在Laravel中保存多态关系的问题。这是我想在Laravel中创建的模型。商店有很多产品,产品可以是“项目”、“事件”或“服务”。我有以下表格:商店编号用户编号姓名事件编号公开标题描述产品编号店铺编号productable_id可生产类型这是我设置模型的方式:classShopextendsModel{publicfunctionproducts(){return$this->hasMany('App\Product');}}classProductextendsModel{publicfunctionproductable(){return$this->morphTo(

  9. php - 人脸检测+图像变形 - 2

    我希望创建一个类似photofunia.com的网站,基本上您可以在其中对图像应用大量效果。我想知道是否有人可以指导我在正确的方向上必须使用哪些技术来实现同样的目标?此外,是否有任何开源命令行实用程序可用于创建此类图像?我认为Image::Magick或GD无法处理此类效果。如果我错了,请纠正我。感谢您的宝贵时间。 最佳答案 这篇博文可能会有所帮助:http://svay.com/blog/index/post/2009/06/19/Face-detection-in-pure-PHP-%28without-OpenCV%29

  10. java - Java 中是否有用于变形图像(或处理)的库? - 2

    我正计划编写将图像变形为特定形状的软件(基于在不同图像中定义相似区域的点和vector,以及“平均”形状的计算)。显然这非常困难,因此我正在寻找一个可以处理图像变形的库(这样我就可以专注于GUI,并将必要的坐标提供给库)。为了澄清,我想做的一个例子是:加载图片(比如图片1和2)定义图像中的相似点(例如,图像1和2中的鼻尖,坐标为(1,5)和(1,7))计算点的平均坐标(这样就是(1,6))将每个图像上定义的点变形为相同的坐标(因此将所有Nose变形为(1,6))保存图片现在当然实际用例会复杂得多(我还想变形线和其他形状(vector)而不是单一坐标,但原理会保持不变。

随机推荐