前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >手把手教你实现Android开发中的3D卡片翻转效果!

手把手教你实现Android开发中的3D卡片翻转效果!

作者头像
博文视点Broadview
发布2023-05-06 19:41:13
2.4K0
发布2023-05-06 19:41:13
举报
文章被收录于专栏:博文视点Broadview

👆关注“博文视点Broadview”,获取更多书讯

以下内容节选自《Android自定义控件高级进阶与精彩实例》一书!


--正文--

《Android自定义控件高级进阶与精彩实例》一书中有一个使用Camera类(书中有对该类的详细讲解)实现3D卡片翻转效果的例子(效果如下所示)。

项目地址:请移步GitHub并搜索DialogFlipTest。

为了便于讲解实现原理,本文将通过通过一个简单的示例来进行展示,该示例的效果如下所示。

其实这个示例最初是Google给出的API Demos里的示例,具体路径为:src/com/example/android/apis/animation/Rotate3dAnimation.java

其中具体讲解了Rotate3dAnimation的实现原理,为了方便起见,这里会稍做修改,但最终的实现效果是完全相同的。

01

框架搭建

要实现ImageView的旋转,可使用如下两种函数。

  • 第一种函数是继承自ImageView类,在onDraw函数中实现图像的翻转。类似地,也可以继承自LinearLayout等容器类,同样在dispatchDraw函数中操作Canvas,以实现其所包含的控件的旋转效果。
  • 第二种函数是自定义Animation,通过给View设置自定义的Animation来实现旋转效果。在这里,我们使用这种函数。

在框架阶段,我们做了一个非常简单的demo,实现一张图片的来回切换,效果如下。

如效果图所示,当点击按钮时,图像从0°旋转至180°,当再点击按钮时,图像会旋转回来。

1.XML布局

Activity的布局非常简单,就是一个按钮和一个ImageView,代码如下(activity_rotate_ 3d.xml):

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?><LinearLayout    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"    android:orientation="vertical"    android:gravity="top|center_horizontal"    tools:context=".Rotate3DActivity">
    <Button        android:id="@+id/btn_open"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_margin="16dp"        android:onClick="onClickView"        android:text="翻转"        android:textColor="@android:color/black"        android:textSize="16sp"/>
    <LinearLayout        android:id="@+id/content"        android:layout_width="300dp"        android:layout_height="200dp"        android:layout_below="@id/btn_open"        android:orientation="vertical"        android:gravity="center_horizontal"        android:layout_marginTop="16dp">
        <ImageView            android:id="@+id/iv_logo"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:src="@mipmap/photo1"            android:scaleType="centerCrop"/>    </LinearLayout>
</LinearLayout>

大家可能会觉得,在ImageView的外围又包了一个LinearLayout,这样做多此一举。

是的,从这里来看,是没有必要,但后面我们会修改这个布局文件,到时候LinearLayout就有用了。为了讲解方便,此处提前进行布局。

需要注意ImageView外围所包装的id为content的LinearLayout,注意它的位置,我们将会在后续的代码中用到。

2.Activity代码

因为我们是通过自定义Animation来旋转控件的,所以肯定会在onCreate函数中对Animation进行初始化,然后在点击按钮时执行startAnimation。

下面先列出完整的代码:

代码语言:javascript
复制
public class Rotate3DActivity extends AppCompatActivity {    private View mContentRoot;
    private int duration = 600;    private Rotate3dAnimation openAnimation;    private Rotate3dAnimation closeAnimation;
    private boolean isOpen = false;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_rotate_3d);
        mContentRoot =  findViewById(R.id.content);
        initOpenAnim();        initCloseAnim();    }

    private void initOpenAnim() {        openAnimation = new Rotate3dAnimation(0, 180);        openAnimation.setDuration(duration);        openAnimation.setFillAfter(true);    }
    private void initCloseAnim() {        closeAnimation = new Rotate3dAnimation(180, 0);        closeAnimation.setDuration(duration);        closeAnimation.setFillAfter(true);    }
    public void onClickView(View v) {        if (openAnimation.hasStarted() && !openAnimation.hasEnded()) {            return;        }        if (closeAnimation.hasStarted() && !closeAnimation.hasEnded()) {            return;        }
        if (isOpen) {            mContentRoot.startAnimation(closeAnimation);        }else {            mContentRoot.startAnimation(openAnimation);        }        isOpen = !isOpen;    }}

在代码中,我们自定义的Animation叫Rotate3dAnimation,具体实现会在后面详细讲解。

在onCreate函数中,是初始化环节:

代码语言:javascript
复制
protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_rotate_3d);
    mContentRoot =  findViewById(R.id.content);
    initOpenAnim();    initCloseAnim();}

注意这里的mContentRoot,它就是XML中包裹ImageView的LinearLayout,表示需要旋转的控件的根布局。

从效果图可以看出,从0°到180°和从180°到0°,是两个不同的动画过程,分别用openAnimation和closeAnimation来表示。

下面只讲解openAnimation动画过程:

代码语言:javascript
复制
private void initOpenAnim() {    openAnimation = new Rotate3dAnimation(0, 180);    openAnimation.setDuration(duration);    openAnimation.setFillAfter(true);}

从这里大概可以看出,Rotate3dAnimation有两个参数,分别是fromDegrees和endDegrees。因为我们需要在完成动画之后,让View保持完成动画时的状态,所以要用到setFillAfter(true)函数。

3.自定义Animation函数

该自定义Animation函数的主要作用是实现控件在中间位置从fromDegrees旋转到endDegrees。

重写Animation的函数比较简单,主要是重写如下两个函数:

代码语言:javascript
复制
public class Rotate3dAnimation extends Animation {        public Rotate3dAnimation(float fromDegrees, float endDegrees) {            }    @Override    public void initialize(int width, int height, int parentWidth, int parentHeight) {        super.initialize(width, height, parentWidth, parentHeight);                …// 在这里执行初始化操作
    }
    @Override    protected void applyTransformation(float interpolatedTime, Transformation t) {                …// 执行自定义动画操作
        super.applyTransformation(interpolatedTime, t);    }}

上面就是自定义Animation的框架,其中主要涉及3个函数

  • 构造函数:很明显,构造函数主要是为了传入一些参数,比如这里的fromDegrees和endDegrees。
  • initialize:initialize函数会在执行动画前调用,参数中的width、height表示将要执行动画的View的宽和高,parentWidth、parentHeight表示执行动画的View的父控件的宽和高。因为该函数会在执行动画前调用,所以一般会在该函数中执行一些初始化操作。
  • applyTransformation:applyTransformation函数最重要,它就是用来实现自定义Animation的函数,相关参数如下。
  • float interpolatedTime:正在执行的Animation的当前进度,取值范围为0~1。
  • Transformation t:当前进度下,需要对控件应用的变换操作都保存在Transformation中。

我们知道一般通过Animation.setDuration(long durationMillis)来设置动画时长,在applyTransformation函数中,会将时长转化为进度来表示,这个进度就是interpolatedTime,它是一个浮点数,取值范围为0~1。

动画的进度一般是从0到1,假设动画的最小更新进度为0.001,即进度每隔0.001更新一次界面,每次更新界面都是通过调用applyTransformation函数来实现的。

所以,在每次更新动画时,当前的动画进度就是这里的interpolatedTime,而这个进度对应的需要对View控件所做的操作,全部保存在参数Transformation t中。

自定义Animation就是通过上面的步骤完成的,下面来看看如何实现Rotate3dAnimation。

4.Rotate3dAnimation

Rotate3dAnimation的代码比较简单,下面先全部列出,然后逐个讲解:

代码语言:javascript
复制
public class Rotate3dAnimation extends Animation {    private final float mFromDegrees;    private final float mEndDegree;
    private float mCenterX,mCenterY;    private Camera mCamera;
    public Rotate3dAnimation(float fromDegrees, float endDegree) {        mFromDegrees = fromDegrees;        mEndDegree = endDegree;    }
    @Override    public void initialize(int width, int height, int parentWidth, int parentHeight) {        super.initialize(width, height, parentWidth, parentHeight);        mCenterX = width/2;        mCenterY = height/2;        mCamera = new Camera();    }
    @Override    protected void applyTransformation(float interpolatedTime, Transformation t) {        float degrees = mFromDegrees + ((mEndDegree - mFromDegrees) * interpolatedTime);
        mCamera.save();        final Matrix matrix = t.getMatrix();        mCamera.rotateY(degrees);        mCamera.getMatrix(matrix);        mCamera.restore();
        matrix.preTranslate(-mCenterX, -mCenterY);        matrix.postTranslate(mCenterX, mCenterY);
        super.applyTransformation(interpolatedTime, t);    }}

首先,在构造函数中,传入两个参数fromDegrees和endDegree,fromDegrees表示开始旋转的角度,endDegree表示结束旋转的角度。

然后,在initialize函数中执行初始化操作。根据本书1.2节的讲解可知,我们要围绕控件中心点旋转,因此需要获取控件中心点的位置坐标。所以,在初始化时,计算出控件中心点的位置坐标:

代码语言:javascript
复制
public void initialize(int width, int height, int parentWidth, int parentHeight) {    super.initialize(width, height, parentWidth, parentHeight);    mCenterX = width/2;    mCenterY = height/2;    mCamera = new Camera();}

最后,执行applyTransformation函数中的操作。

其中:

第1步,根据当前进度计算出当前的旋转角度:

代码语言:javascript
复制
float degrees = mFromDegrees + ((mEndDegree - mFromDegrees) * interpolatedTime);

第2步,利用Camera将图片绕Y轴旋转degrees的角度:

代码语言:javascript
复制
mCamera.save();final Matrix matrix = t.getMatrix();mCamera.rotateY(degrees);mCamera.getMatrix(matrix);mCamera.restore();

第3步,将旋转中心移到控件中心点位置:

代码语言:javascript
复制
matrix.preTranslate(-mCenterX, -mCenterY);matrix.postTranslate(mCenterX, mCenterY);

第4步,调用super.applyTransformation(interpolatedTime, t)来执行改变过的动画操作,以将操作最终体现在控件上。

到此,就实现了我们想要的效果,如下所示。

02

效果改进

1.图片缩放原理概述

从最后实现的效果图可以看出一个问题,翻转时的图像效果与开始时看到的效果不完全相同,不同点在于后面实现的翻转效果,翻转过程中图像很大,如图1所示。

图1

而本文开始时看到的效果的翻转过程截图如图2所示。

图2

可以看到,在图2中,翻转过程中的图像没有那么大,基本保持原大小不变。

从本书1.2节可以知道,图像旋转时的大小跟其与Z轴的距离有关,View与Camera的距离越大,显示的图像越小。

所以,在图像从0°旋转到180°的过程中,图像与Camera的距离关系如图3所示。

图3

从当前的效果图可以看出,随着旋转角度的增加,倾斜之后的图像会变大,在旋转角度达到90°时图像最大。

同样地,要解决这个问题,就得随着图像变大,将View与Camera的距离增大,这样View就会变小。所以,这个View与Camera的距离变化过程就形成了上面的曲线。

当图像需要从0°旋转至90°时,View与Camera的距离需要越来越大,并在旋转到90°时达到最大。而当图像需要从90°旋转至180°时,整个距离变化过程与从0°旋转至90°时的相反,这点从曲线的变化情况就可以看出。

因此需要将图像从0°至180°的整个旋转过程分为两段,从0°旋转至90°时执行下面的代码,使View与Camera的距离逐渐增大:

代码语言:javascript
复制
z = mDepthZ * interpolatedTime;camera.translate(0.0f, 0.0f, z);

这里的mDepthZ是固定数值,默认值为400。如果动画中图像的旋转角度区间就是从0°旋转至90°,那么View与Camera的距离会随着动画的播放越变越大,在旋转角度达到90°时距离达到最大,这与图3中的情况相同。

而在第2段过程中,即从90°旋转至180°时,整个View与Camera的距离变化情况就要反过来,在90°时距离达到最大,在180°时距离回归到初始值:

代码语言:javascript
复制
z = mDepthZ * (1.0f - interpolatedTime);camera.translate(0.0f, 0.0f, z);

很明显,这段代码是符合要求的。所以,后面我们为了区分是从0°旋转至90°的逐渐增大曲线还是从90°旋转至180°的逐渐减小曲线,引入了一个reverse变量来进行标识。

2.改造Rotate3dAnimation

根据上面的原理,我们对Rotate3dAnimation函数进行改造,改造后的代码如下。下面先列出完整代码,然后详细讲解:

代码语言:javascript
复制
public class Rotate3dAnimation extends Animation {    private final float mFromDegrees;    private final float mEndDegree;    private float mDepthZ = 400;    private float mCenterX,mCenterY;    private final boolean mReverse;    private Camera mCamera;
    public Rotate3dAnimation(float fromDegrees, float toDegrees,                             boolean reverse) {        mFromDegrees = fromDegrees;        mEndDegree = toDegrees;        mReverse = reverse;    }
    @Override    public void initialize(int width, int height, int parentWidth, int parentHeight) {        super.initialize(width, height, parentWidth, parentHeight);        mCamera = new Camera();        mCenterX = width/2;        mCenterY = height/2;    }
    @Override    protected void applyTransformation(float interpolatedTime, Transformation t) {        float degrees = mFromDegrees + ((mEndDegree - mFromDegrees) * interpolatedTime);
        mCamera.save();        float z;        if (mReverse) {            z = mDepthZ * interpolatedTime;            mCamera.translate(0.0f, 0.0f, z);        } else {            z = mDepthZ * (1.0f - interpolatedTime);            mCamera.translate(0.0f, 0.0f, z);        }                final Matrix matrix = t.getMatrix();        mCamera.rotateY(degrees);        mCamera.getMatrix(matrix);        mCamera.restore();
        matrix.preTranslate(-mCenterX, -mCenterY);        matrix.postTranslate(mCenterX, mCenterY);
        super.applyTransformation(interpolatedTime, t);    }}

首先看初始化函数,在初始化函数中有一个boolean reverse参数,这个参数用于标识曲线是逐渐增大的还是逐渐减小的。reverse为true时,表示距离逐渐增大;reverse为false时,表示距离逐渐减小。

然后在applyTransformation中,增加了沿Z轴移动的代码:

代码语言:javascript
复制
float z;if (mReverse) {    z = mDepthZ * interpolatedTime;    mCamera.translate(0.0f, 0.0f, z);} else {    z = mDepthZ * (1.0f - interpolatedTime);    mCamera.translate(0.0f, 0.0f, z);}

很明显,当mReverse为true时,View沿Z轴的移动距离随动画的播放而增大,在动画结束(interpolatedTime等于1)时达到最大。当mReverse为false时,View沿Z轴的移动距离随动画的播放而减小,在动画结束时,View沿Z轴的移动距离回归到0。

3.改造Activity

因为我们把原本从0°旋转至180°的动画拆成了两段,所以需要先执行从0°旋转至90°的动画,结束后接着执行从90°旋转至180°的动画,即核心代码如下:

代码语言:javascript
复制
private void initOpenAnim() {    openAnimation = new Rotate3dAnimation(0, 90, true);    openAnimation.setDuration(duration);    openAnimation.setFillAfter(true);    openAnimation.setAnimationListener(new AnimationListener() {                @Override        public void onAnimationStart(Animation animation) {                    }                @Override        public void onAnimationRepeat(Animation animation) {                    }                @Override        public void onAnimationEnd(Animation animation) {            mLogoIv.setVisibility(View.GONE);            mDescTv.setVisibility(View.VISIBLE);
            Rotate3dAnimation rotateAnimation = new Rotate3dAnimation(90, 180,false);            rotateAnimation.setDuration(duration);            rotateAnimation.setFillAfter(true);            mContentRl.startAnimation(rotateAnimation);        }    });}

同样地,closeAnimation先执行从180°旋转至90°的动画,结束后再执行从90°旋转至0°的动画。这里就不再列出相关代码了。

通过扫码查看右侧的效果图可以看出,基本上完成了动画图像大小不变的旋转动作,但在图像旋转到90°的时候,会明显地卡一下,这是因为此处有一个停顿以便过渡到下一个动画过程,我们可以使用加速器来解决这个问题:

代码语言:javascript
复制
private void initOpenAnim() {    openAnimation = new Rotate3dAnimation(0, 90,true);    …    openAnimation.setInterpolator(new AccelerateInterpolator());    openAnimation.setAnimationListener(new AnimationListener() {        @Override        public void onAnimationEnd(Animation animation) {            Rotate3dAnimation rotateAnimation = new Rotate3dAnimation(90, 180,false);            …            rotateAnimation.setInterpolator(new DecelerateInterpolator());            mContentRoot.startAnimation(rotateAnimation);        }        …    });}

由以上代码可见,从0°旋转至90°时使用加速器,从90°旋转至180°时使用减速器,在90°时旋转速度最快。同样地,closeAnimation也使用加速器来解决这个问题,效果如下。

从效果图可以看到,这样就初步实现了开始时的效果,但还是有所不同,开始时的效果在旋转至90°后,显示的是另一张图像,这是怎么做到的呢?

03

正背面显示不同的内容

回顾一下开始时的动画,效果如下。

可以看到,在图像旋转至90°时,ImageView显示的图像变为另一张图像。

方案一:通过替换图像资源实现

因为我们已经将从0°至180°的旋转过程划分为从0°至90°和从90°至180°这两个过程,所以在90°时为ImageView替换图像,即可实现背面显示另一张图像的效果,可扫码查看效果图。

首先,在点击“翻转”按钮的时候,给ImageView配置上初始图像:

代码语言:javascript
复制
public void onClickView(View v) {    …    if (isOpen) {        ((ImageView)findViewById(R.id.iv_logo)).setImageResource(R.mipmap.photo2);        mContentRoot.startAnimation(closeAnimation);    }else {        ((ImageView)findViewById(R.id.iv_logo)).setImageResource(R.mipmap.photo1);        mContentRoot.startAnimation(openAnimation);    }    isOpen = !isOpen;}

然后,在90°时,开始下一个动画前,给ImageView配置上另一张图像:

代码语言:javascript
复制
private void initOpenAnim() {    openAnimation = new Rotate3dAnimation(0, 90,true);    openAnimation.setDuration(duration);    openAnimation.setFillAfter(true);    openAnimation.setInterpolator(new AccelerateInterpolator());    openAnimation.setAnimationListener(new AnimationListener() {        @Override        public void onAnimationEnd(Animation animation) {            ((ImageView)findViewById(R.id.iv_logo)).setImageResource(R.mipmap.photo2);            …            mContentRoot.startAnimation(rotateAnimation);        }        …    });}

整个代码的难度不大,这里就不再详述了。这样处理后,就实现了我们想要的效果。

方案二:使用多控件显示/隐藏实现

方案一只能解决同一个控件中显示不同内容的问题,但若要正背面显示不同的控件,就没办法了。

这时可以使用方案二,即在布局中引入两个ImageView控件,用从0°旋转至90°时显示一个控件而从90°旋转至180°时显示另一个控件的方式来实现。

将Activity的布局代码改为如下代码(activity_rotate_3d.xml):

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?><LinearLayout    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"    android:orientation="vertical"    android:gravity="top|center_horizontal"    tools:context=".Rotate3DActivity">
    <Button        android:id="@+id/btn_open"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_margin="16dp"        android:onClick="onClickView"        android:text="翻转"        android:textColor="@android:color/black"        android:textSize="16sp"/>
    <LinearLayout        android:id="@+id/content"        android:layout_width="300dp"        android:layout_height="200dp"        android:layout_below="@id/btn_open"        android:orientation="vertical"        android:gravity="center_horizontal"        android:layout_marginTop="16dp">
        <ImageView            android:id="@+id/iv_logo"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:src="@mipmap/photo1"            android:scaleType="centerCrop"/>
        <ImageView            android:id="@+id/iv_logo_2"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:src="@mipmap/photo2"            android:scaleType="centerCrop"            android:visibility="gone"/>    </LinearLayout>
</LinearLayout>

可见,相比原来的布局代码,这里在实现动画的容器(id为content的LinearLayout)中增加了一个ImageView,它的资源是photo2。然后在动画中,在openAnimation结束时,将image1隐藏并显示image2,这时的动画效果就是切换到图片二了:

代码语言:javascript
复制
private void initOpenAnim() {    openAnimation = new Rotate3dAnimation(0, 90,true);    openAnimation.setDuration(duration);    openAnimation.setFillAfter(true);    openAnimation.setInterpolator(new AccelerateInterpolator());    openAnimation.setAnimationListener(new AnimationListener() {        …        @Override        public void onAnimationEnd(Animation animation) {            ((ImageView)findViewById(R.id.iv_logo)).setVisibility(View.GONE);            ((ImageView)findViewById(R.id.iv_logo_2)).setVisibility(View.VISIBLE);            …            mContentRoot.startAnimation(rotateAnimation);        }    });}

同样地,在翻转动画中,在closeAnimation结束时,将image2隐藏并显示image1,这时的动画效果就是切换到图片一了:

代码语言:javascript
复制
private void initCloseAnim() {    closeAnimation = new Rotate3dAnimation(180, 90,true);    closeAnimation.setDuration(duration);    closeAnimation.setFillAfter(true);    closeAnimation.setInterpolator(new AccelerateInterpolator());    closeAnimation.setAnimationListener(new AnimationListener() {        …        @Override        public void onAnimationEnd(Animation animation) {            ((ImageView)findViewById(R.id.iv_logo)).setVisibility(View.VISIBLE);            ((ImageView)findViewById(R.id.iv_logo_2)).setVisibility(View.GONE);            …            mContentRoot.startAnimation(rotateAnimation);        }    });}

这样,ImageView显示图像的功能就实现了,通过这种方式实现的控件可以实现正背面不同的布局效果,如图4所示。

图4

根据以上的原理,我们若要实现这个效果,只需要在图像旋转至90°时显示/隐藏不同的控件即可。

想要了解更多自定义控件的使用?那就赶紧去看一下《Android自定义控件高级进阶与精彩实例》这本书吧!

▊《Android自定义控件高级进阶与精彩实例》

启舰 著

  • 专注于介绍Android自定义控件进阶知识
  • 通过精彩的案例对各种绘制、动画技术进行了糅合讲解

读者可以通过本书从宏观层面、源码层面对Android自定义控件建立完整的认识。

本书主要内容有3D特效的实现、高级矩阵知识、消息处理机制、派生类型的选择方法、多点触控及辅助类、RecyclerView的使用方法及3D卡片的实现、动画框架Lottie的讲解与实战等。本书适合中高级从业者对Android自定义控件相关知识进行查漏补缺和深入学习。

(京东满100减50,快快扫码抢购吧!)

代码语言:javascript
复制
如果喜欢本文欢迎 在看丨留言丨分享至朋友圈 三连

 热文推荐  
书单 | 阿里技术书单,满足你的“大厂情结”
《漫画算法2》2021全新进阶版来袭!
一文了解预训练语言模型!
Flink+Alink,当大数据遇见机器学习!


▼点击阅读原文,获取本书详情~
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-06-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 博文视点Broadview 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 要实现ImageView的旋转,可使用如下两种函数。
  • 1.图片缩放原理概述
  • 回顾一下开始时的动画,效果如下。
  • 可以看到,在图像旋转至90°时,ImageView显示的图像变为另一张图像。
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档