博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于Activity跳转动画大汇总
阅读量:6871 次
发布时间:2019-06-26

本文共 18372 字,大约阅读时间需要 61 分钟。

目录介绍

  • 1.业务需求:Activity正反两面,沿中心X,Y轴旋转180度

    • 1.0 具体业务需求
    • 1.1 用3D效果做翻转动画
    • 1.2 用2D效果做翻转动画【实际是缩小-放大,看上去是翻转】
  • 2.业务分析:两个界面放在同一个布局中

    • 2.1 布局设计思路分析
    • 2.2 代码展示
  • 3.具体动画逻辑做法:看具体代码

    • 3.1 定义3D旋转动画
    • 3.2 在activity处理翻转逻辑
    • 3.3 直接展示2D动画实现上面需求的代码
  • 4.关于Activity实现切换的方式

    • 4.1 实现切换的方式
    • 4.2 activity退出动画与显示动画
  • 5.使用overridePendingTransition方法实现Activity跳转动画

    • 5.1 如何实现,步骤演示
    • 5.2 源码分析
  • 6.使用style的方式定义Activity的切换动画

    • 6.1 定义包含动画的 Activity 主题
    • 6.2 定义切换动画 style
    • 6.3 定义具体动画文件
    • 6.4 应用到对应 Activity
    • 6.5 可能出现的bug

      • 6.5.1 添加动画后,出现从黑屏到新activity的过度
      • 6.5.2 没有动画,或动画与设置不一致
  • 7.使用ActivityOptions切换动画实现Activity跳转动画

    • 7.1 这种动画方式介绍
    • 7.2 代码实现方式
  • 8.使用ActivityOptions之后内置的动画效果通过style的方式

    • 8.1 定义动画文件
    • 8.2 定义切换动画style
    • 8.3 执行跳转逻辑
  • 9.使用ActivityOptions动画共享组件的方式实现跳转Activity动画

    • 9.1 定义共享组件
    • 9.2 调用startActivity执行跳转动画
    • 9.3 关于这几种方式的动画总结
  • 10.其他说明

    • 10.1 参考案例
    • 10.2 更新日志
    • 10.3 关于我的博客

0.备注

  • 建议结合代码,看博客更加高效,项目地址:
  • 如果你觉得好,欢迎star

1.业务需求与实现方法

  • 1.0 具体业务需求

    • 这个动画效果是把Activity当做一张纸,正反面都有内容,Activity都会以屏幕中心为翻转中心点(Z轴的翻转中心点可以自由设定),进行旋转。
    • 图形如下所示
  • 1.1 用3D效果做翻转动画

    • 下面2,3均是分析如何实现这种动画
  • 1.2 用2D效果做翻转动画【实际是缩小-放大,看上去是翻转】

    • 比较简单,效果也还不错,直接在看4.3 直接展示2D动画实现上面需求的代码
  • 1.4 代码案例展示
  • 直接找到代码中的这几个类
1.SplashAdFirstActivity,3d效果,沿中心x,y轴旋转,可以设置缩放效果,只需要设置z轴位移就可以2.SplashAdSecondActivity,3d效果,借鉴与网络,不是旋转的动画,但是效果很炫3.SplashAdThirdActivity,2d效果。看上去像是旋转,实则是缩放效果。几乎看上去效果和1类似由于产品需求,后来采用第三种方法

2.业务分析

  • 2.1 布局设计思路分析

    • 这个动画效果的思路是这样的,首先两个界面的布局都在同一个Layout文件中,因为这里只有一个Activity,所以两个界面的布局在同一个layout文件中就要有所设计。
  • 2.2 代码展示

    • 注意,在两个RelativeLayout中必须添加android:focusable=”true” ,android:focusableInTouchMode=”true”这两个属性来隔离两个界面的监听事件,使得当前显示的一面监听有效,另一个不显示的页面的监听无效,否则点击事件会乱套。

3.具体动画逻辑做法:看具体代码

  • 3.1 定义3D旋转动画

    • 翻转效果的设计,首先是确定翻转中心点的位置,通过传入X,Y,Z三个轴的中心点来确定。然后使用Camera根据传入的翻转度来进行翻转,翻转的类Rotate3D代码如下:
public class Rotate3D extends Animation {    // 开始角度    private final float mFromDegrees;    // 结束角度    private final float mToDegrees;    // X轴中心点    private final float mCenterX;    // Y轴中心点    private final float mCenterY;    // Z轴中心点    private final float mDepthZ;    //是否需要扭曲    private final boolean mReverse;    //摄像头    private Camera mCamera;    public Rotate3D(float fromDegrees, float toDegrees, float centerX,float centerY, float depthZ, boolean reverse) {        mFromDegrees = fromDegrees;        mToDegrees = toDegrees;        mCenterX = centerX;        mCenterY = centerY;        mDepthZ = depthZ;        mReverse = reverse;    }    @Override    public void initialize(int width, int height, int  parentWidth, int parentHeight) {        super.initialize(width, height, parentWidth, parentHeight);        mCamera = new Camera();    }    @Override    protected void applyTransformation(float interpolatedTime, Transformation t) {        final float fromDegrees = mFromDegrees;        // 生成中间角度        float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);        final float centerX = mCenterX;        final float centerY = mCenterY;        final Camera camera = mCamera;        //取得当前矩阵        final Matrix matrix = t.getMatrix();        camera.save();        if (mReverse) {            camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);        } else {            camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));        }        //翻转        camera.rotateY(degrees);        // 取得变换后的矩阵        camera.getMatrix(matrix);        camera.restore();        matrix.preTranslate(-centerX, -centerY);        matrix.postTranslate(centerX, centerY);    }}
  • 3.2 在activity处理翻转逻辑

    • 整个翻转过程分为两个阶段操作,第一阶段是从当前页面翻转到整个Activity垂直于手机屏幕(到这个时刻,正反两面都是不可见的)。第二阶段是从当前的整个Activity垂直于手机屏幕(到这个时刻,正反两面都是不可见的)状态翻转到第二个页面显示在手机屏幕上。
    • 代码如下所示
public class SplashAdFirstActivity extends BaseActivity {    @Bind(R.id.iv_ad)    ImageView ivAd;    @Bind(R.id.tv_time)    TextView tvTime;    //页面翻转容器FrameLayout    @Bind(R.id.fl)    LinearLayout fl;    //布局1界面RelativeLayout    @Bind(R.id.fl_ad)    FrameLayout flAd;    //布局2界面RelativeLayout    @Bind(R.id.fl_main)    FrameLayout flMain;    private TimeCount timeCount;    private boolean isClick = false;    //z轴翻转    private float z = 200.0f;    @Override    protected void onDestroy() {        super.onDestroy();        if (timeCount != null) {            timeCount.cancel();            timeCount = null;        }    }    @Override    public int getContentView() {        return R.layout.activity_splash_ad;    }    @Override    public void initView() {        initTimer();    }    private void initTimer() {        timeCount = new TimeCount(5 * 1000, 1000, tvTime);        timeCount.start();    }    @Override    public void initListener() {        ivAd.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                isClick = true;                applyRotation(1,0,90);                //applyRotation(0,0,-90);            }        });    }    @Override    public void initData() {    }    private class TimeCount extends CountDownTimer {        private TextView tv;        TimeCount(long millisInFuture, long countDownInterval, TextView tv) {            super(millisInFuture, countDownInterval);            //参数依次为总时长,和计时的时间间隔            this.tv = tv;        }        //计时完毕时触发        @Override        public void onFinish() {            //如果是点击了翻转,那么就不执行这里面的代码            if(!isClick){                //第一阶段翻转                applyRotation(1,0,90);                //applyRotation(0,0,-90);            }        }        @Override        public void onTick(long millisUntilFinished) {            //计时过程显示            StringBuilder sb = new StringBuilder();            sb.append("倒计时");            sb.append(millisUntilFinished / 1000);            sb.append("秒");            tv.setText(sb.toString());        }    }    /**     * 执行翻转第一阶段翻转动画     * @param tag view索引     * @param start 起始角度     * @param end 结束角度     */    private void applyRotation(int tag, float start, float end) {        // 得到中心点(以中心翻转)        //X轴中心点        final float centerX = fl.getWidth() / 2.0f;        //Y轴中心点        final float centerY = fl.getHeight() / 2.0f;        //Z轴中心点        final float depthZ = z;        // 根据参数创建一个新的三维动画,并且监听触发下一个动画        final Rotate3D rotation = new Rotate3D(start, end, centerX, centerY, depthZ, true);        //设置动画持续时间        rotation.setDuration(2500);        //设置动画变化速度        //rotation.setInterpolator(new AccelerateInterpolator());        //设置第一阶段动画监听器        rotation.setAnimationListener(new DisplayNextView(tag));        fl.startAnimation(rotation);    }    /**     * 第一阶段动画监听器     */    private final class DisplayNextView implements Animation.AnimationListener {        private final int tag;        private DisplayNextView(int tag) {            this.tag = tag;        }        @Override        public void onAnimationStart(Animation animation) {}        @Override        public void onAnimationEnd(Animation animation) {            //第一阶段动画结束时,也就是整个Activity垂直于手机屏幕,            //执行第二阶段动画            fl.post(new SwapViews(tag));            //调整两个界面各自的visibility            adjustVisibility();        }        @Override        public void onAnimationRepeat(Animation animation) {        }    }    /**     * 执行翻转第二个阶段动画     */    private final class SwapViews implements Runnable {        private final int tag;        SwapViews(int position) {            tag = position;        }        @Override        public void run() {            if (tag == 0) {                //首页页面以90~0度翻转                showView(flAd, flMain, 90, 0);            } else if (tag == 1) {                //音乐页面以-90~0度翻转                showView(flMain, flAd, -90, 0);            }        }    }    /**     * 显示第二个视图动画     * @param showView 要显示的视图     * @param hiddenView 要隐藏的视图     * @param startDegree 开始角度     * @param endDegree 目标角度     */    private void showView(FrameLayout showView, FrameLayout hiddenView, int startDegree, int endDegree) {        //同样以中心点进行翻转        float centerX = showView.getWidth() / 2.0f;        float centerY = showView.getHeight() / 2.0f;        float centerZ = z;        if (centerX == 0 || centerY == 0) {            //调用该方法getMeasuredWidth(),必须先执行measure()方法,否则会出异常。            showView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);            //获取该view在父容器里面占的大小            centerX = showView.getMeasuredWidth() / 2.0f;            centerY = showView.getMeasuredHeight() / 2.0f;        }        hiddenView.setVisibility(View.GONE);        showView.setVisibility(View.VISIBLE);        Rotate3D rotation = new Rotate3D(startDegree, endDegree, centerX, centerY, centerZ, true);        //设置动画持续时间        rotation.setDuration(2500);        //设置动画变化速度        //rotation.setInterpolator(new DecelerateInterpolator());        fl.startAnimation(rotation);    }    /**     * 两个布局的visibility调节     */    private void adjustVisibility(){        if(flAd.getVisibility() == View.VISIBLE){            flAd.setVisibility(View.GONE);        }else {            flMain.setVisibility(View.VISIBLE);        }        if(flMain.getVisibility() == View.VISIBLE){            flMain.setVisibility(View.GONE);        }else {            flAd.setVisibility(View.VISIBLE);        }    }}
  • 3.3 直接展示2D动画实现上面需求的代码
public class SplashAdThirdActivity extends BaseActivity {    @Bind(R.id.fl_ad)    FrameLayout flAd;    @Bind(R.id.fl_main)    FrameLayout flMain;    @Bind(R.id.fl)    LinearLayout fl;    @Bind(R.id.iv_ad)    ImageView ivAd;    @Bind(R.id.tv_time)    TextView tvTime;    private TimeCount timeCount;    private boolean isClick = false;    private ScaleAnimation sato0 = new ScaleAnimation(1,0,1,1,            Animation.RELATIVE_TO_PARENT,0.5f, Animation.RELATIVE_TO_PARENT,0.5f);    private ScaleAnimation sato1 = new ScaleAnimation(0,1,1,1,            Animation.RELATIVE_TO_PARENT,0.5f,Animation.RELATIVE_TO_PARENT,0.5f);    @Override    protected void onDestroy() {        super.onDestroy();        if (timeCount != null) {            timeCount.cancel();            timeCount = null;        }    }    @Override    public int getContentView() {        return R.layout.activity_splash_ad;    }    @Override    public void initView() {        initTimer();    }    private void initTimer() {        timeCount = new TimeCount(5 * 1000, 1000, tvTime);        timeCount.start();    }    @Override    public void initListener() {        ivAd.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                isClick = true;                flAd.startAnimation(sato0);            }        });    }    @Override    public void initData() {        showView1();        sato0.setDuration(500);        sato1.setDuration(500);        sato0.setAnimationListener(new Animation.AnimationListener() {            @Override            public void onAnimationStart(Animation animation) {            }            @Override            public void onAnimationEnd(Animation animation) {                if (flAd.getVisibility() == View.VISIBLE){                    flAd.setAnimation(null);                    showView2();                    flMain.startAnimation(sato1);                }else{                    flMain.setAnimation(null);                    showView1();                    flAd.startAnimation(sato1);                }            }            @Override            public void onAnimationRepeat(Animation animation) {            }        });    }    private class TimeCount extends CountDownTimer {        private TextView tv;        TimeCount(long millisInFuture, long countDownInterval, TextView tv) {            super(millisInFuture, countDownInterval);            //参数依次为总时长,和计时的时间间隔            this.tv = tv;        }        //计时完毕时触发        @Override        public void onFinish() {            //如果是点击了翻转,那么就不执行这里面的代码            if(!isClick){                //第一阶段翻转                flAd.startAnimation(sato0);            }        }        @Override        public void onTick(long millisUntilFinished) {            //计时过程显示            StringBuilder sb = new StringBuilder();            sb.append("倒计时");            sb.append(millisUntilFinished / 1000);            sb.append("秒");            tv.setText(sb.toString());        }    }    private void showView1(){        flAd.setVisibility(View.VISIBLE);        flMain.setVisibility(View.GONE);    }    private void showView2(){        flAd.setVisibility(View.GONE);        flMain.setVisibility(View.VISIBLE);    }}

4.关于Activity实现切换的方式

  • 4.1 实现切换的方式

    • 调用startActivity方法启动一个新的Activity并跳转其页面
    • 调用finish方法销毁当前的Activity返回上一个Activity界面
  • 4.2 activity退出动画与显示动画

    • 当调用startActivity方法的时候启动一个新的activity,这时候就涉及到了旧的Activity的退出动画和新的Activity的显示动画;
    • 当调用finish方法的时候,销毁当前Acitivity,就涉及到了当前Activity的退出动画和前一个Activity的显示动画;
    • 所以我们的activity跳转动画是分为两个部分的:一个Activity的销毁动画与一个Activity的显示动画,明白了这一点之后我们开始看一下第一种实现Activity跳转动画的方式:通过overridePendingTransition方法实现Activity切换动画。

5.使用overridePendingTransition方法实现Activity跳转动画

  • 5.1 如何实现,步骤演示

    • overridePendingTransition方法是Activity中提供的Activity跳转动画方法,通过该方法可以实现Activity跳转时的动画效果。
    • 可以直接参考我的项目:或者
    • 具体代码如下所示
Intent intent = new Intent(this, MainActivity.class);startActivity(intent);overridePendingTransition(R.anim.screen_zoom_in, R.anim.screen_zoom_out);finish();
  • 动画代码如下所示
  • 5.2 源码分析

    • 看下面这一段注释可以知道:

      • overridePendingTransition方法需要在startAtivity方法或者是finish方法调用之后立即执行
      • 参数enterAnim表示的是从Activity a跳转到Activity b,进入b时的动画效果
      • 参数exitAnim表示的是从Activity a跳转到Activity b,离开a时的动过效果
      • 若进入b或者是离开a时不需要动画效果,则可以传值为0
/** * Call immediately after one of the flavors of {@link #startActivity(Intent)} * or {@link #finish} to specify an explicit transition animation to * perform next. * * 

As of {@link android.os.Build.VERSION_CODES#JELLY_BEAN} an alternative * to using this with starting activities is to supply the desired animation * information through a {@link ActivityOptions} bundle to * {@link #startActivity(Intent, Bundle)} or a related function. This allows * you to specify a custom animation even when starting an activity from * outside the context of the current top activity. * * @param enterAnim A resource ID of the animation resource to use for * the incoming activity. Use 0 for no animation. * @param exitAnim A resource ID of the animation resource to use for * the outgoing activity. Use 0 for no animation. */public void overridePendingTransition(int enterAnim, int exitAnim) { try { ActivityManagerNative.getDefault().overridePendingTransition( mToken, getPackageName(), enterAnim, exitAnim); } catch (RemoteException e) { }}

6.使用style的方式定义Activity的切换动画

  • 6.1 定义包含动画的 Activity 主题

    • 在res/values/styles.xml文件中
  • 6.2 定义切换动画 style

    • 还是res/values/styles.xml 文件中

      • activityOpenEnterAnimation // 用于设置打开新的Activity并进入新的Activity展示的动画
      • activityOpenExitAnimation // 用于设置打开新的Activity并销毁之前的Activity展示的动画
      • activityCloseEnterAnimation // 用于设置关闭当前Activity进入上一个Activity展示的动画
      • activityCloseExitAnimation // 用于设置关闭当前Activity时展示的动画
  • 6.3 定义具体动画文件

    • res/anmi/res/top_to_bottom_in.xml
    • res/anmi/res/top_to_bottom_out.xml
    • res/anmi/res/bottom_to_top_in.xml
    • res/anmi/res/bottom_to_top_out.xml
  • 6.4 应用到对应 Activity

    • 在清单文件中添加
 
  • 6.5 可能出现的bug

    • 6.5.1 添加动画后,出现从黑屏到新activity的过度

      • 问题:添加动画后,出现从黑屏到新activity的过度。
      • 原因:没有设置相应的消失动画。
      • 解决方法:设置相应的消失动画,如果不想设置消失动画,可以使用写一个假动画,这个动画是没有任何效果,只是为了避免出现黑屏,运行效果为原acticity静止不动,新启动的activity执行进入动画。
    • 6.5.2 没有动画,或动画与设置不一致

      • 问题:没有动画,或动画与设置不一致
      • 原因:当页面切换时需要进入和消失两个动画,当没有进入动画时,消失动画也不会执行,会执行系统动画,如果没有系统动画则没有动画,或者某个页面使用第一或第二种方式设置了动画(动画执行优先级,系统动画 < AppTheme < (overridePendingTransitionActivityOptionsCompat))。
      • 解决方法:为了保证进入和消失都有动画,要将动画主题设置到两个Activity上。也可以将主题设置到application上,这样整个应用都是用该切换动画。如果是某个页面使用第一或第二种方式设置了动画,那么在启动和退出时最好都要设置,不然会造成启动和退出不一致的情况。

7.使用ActivityOptions切换动画实现Activity跳转动画

  • 7.1 这种动画方式介绍

    • 上面我们讲解的通过overridePendingTransition方法基本上可以满足我们日常中对Activity跳转动画的需求了,但是MD风格出来之后,overridePendingTransition这种老旧、生硬的方式怎么能适合我们的MD风格的App呢?好在google在新的sdk中给我们提供了另外一种Activity的过度动画——ActivityOptions。并且提供了兼容包——ActivityOptionsCompat。ActivityOptionsCompat是一个静态类,提供了相应的Activity跳转动画效果,通过其可以实现不少炫酷的动画效果。
  • 7.2 代码实现方式

    • 代码诠释

      • 传入了ActivityOptions.makeSceneTransitionAnimation,该方法表示将Activity a平滑的切换到Activity b,其还有几个重载方法可以指定相关的View,即以View为焦点平滑的从Activity a切换到Activity b。
      • 这里的setFeature就是为activity的窗口设置特性,不同的特性对应不同的布局方式,比如可以设置无toolbar模式,有toolbar模式等等。而这里设置的是需要过渡动画,并且我们获取了Android中内置的explode动画,并设值给了Activity的window窗口对象,这样当Activity被启动的时候就会执行explode所带便的动画效果了。
    • 在startActivity页面
Intent intent = new Intent(MainActivity.this, ThreeActivity.class);startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this).toBundle());
  • 在跳转后的页面
@Overrideprotected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    // 设置contentFeature,可使用切换动画    getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);    Transition explode = TransitionInflater.from(this).inflateTransition(Android.R.transition.explode);    getWindow().setEnterTransition(explode);    setContentView(R.layout.activity_main);}

8.使用ActivityOptions之后内置的动画效果通过style的方式

  • 8.1 定义动画文件

    • 这种方式其实就是通过style的方式展示和使用ActivityOptions过度动画,下面是实现通过定义style方式定义过度动画的步骤:
    • res目录下新建一个transition目录,然后创建资源文件,然后使用这些系统自带的过渡动画效果,这里设置了过度时长为300ms
  • 8.2 定义切换动画style
@transition/activity_explode
@transition/activity_explode
  • 8.3 执行跳转逻辑
/*** 点击按钮,实现Activity的跳转操作* 通过Android5.0及以上style的方式实现activity的跳转动画*//*** 调用ActivityOptions.makeSceneTransitionAnimation实现过度动画*/Intent intent = new Intent(MainActivity.this, FourActivity.class);startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this).toBundle());

9.使用ActivityOptions动画共享组件的方式实现跳转Activity动画

  • 这里的共享组件动画效果是指将前面一个Activity的某个子View与后面一个Activity的某个子View之间有过渡效果,即在这种过度效果下实现Activity的跳转操作。那么如何实现两个组件View之间实现过渡效果呢?
  • 9.1 定义共享组件

    • 在Activity a中的button按钮点击transitionName属性:
  • 在Activity b的布局文件中为组件定义transitionName属性,这样这两个组件相当于有了过度对应关系,这里需要注意的是这两个组件的transitionName属性的值必须是相同的。
  • 9.2 调用startActivity执行跳转动画

    • 需要说明的是这里调用的ActivityOptions.makeSceneTransitionAnimation方法,传递了三个参数,其中第一个参数为context对象,第二个参数为启动Activity的共享组件,第三个参数为启动Activity的共享组件transitionName属性值。
/*** 点击按钮,实现Activity的跳转操作* 通过Android5.0及以上共享组件的方式实现activity的跳转动画*/Intent intent = new Intent(MainActivity.this, FiveActivity.class);startActivity(intent, ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, button, "shareNames").toBundle());
  • 9.3 关于这几种方式的动画总结

    • 通过overridePendingTransition方式和ActivityOptions动画API实现Activity的切换动画效果;
    • overridePendingTransition方法从Android2.0开始,基本上能够覆盖我们activity跳转动画的需求;
    • ActivityOptions API是在Android5.0开始的,可以实现一些炫酷的动画效果,更加符合MD风格;
    • ActivityOptions还可以实现两个Activity组件之间的过度动画;

10.其他说明

  • 10.1 参考案例

  • 10.2 更新日志

    • v1.0.0 更新于2017年3月19日
    • v1.0.1 更新于2018年1月5日
  • 10.3 关于我的博客

    • github:
    • 喜马拉雅听书:
    • 知乎:
    • 简书:
    • csdn:
    • 新浪博客:

转载地址:http://yicfl.baihongyu.com/

你可能感兴趣的文章
unity3D中使用Socket进行数据通信(二)
查看>>
bytes数据类型和字符串的编码解码,三元运算,进制互换
查看>>
TCP和UDP通信(C#网络编程) ---- 系列文章
查看>>
腾讯2016笔试题-微信红包-找出数组中过半数的数字
查看>>
CentOS7 防火墙配置(关闭)
查看>>
Android静默安装实现方案,仿360手机助手秒装和智能安装功能
查看>>
Asp.Net Core获取当前上下文对象
查看>>
ppoint的使用
查看>>
MQ对比
查看>>
Buildroot 指定内核版本
查看>>
mysql生成不重复随机数(unique number generation)
查看>>
五种IO模型透彻分析
查看>>
22.Linux-块设备驱动之框架详细分析(详解)
查看>>
ELK系列~NLog.Targets.Fluentd到达如何通过tcp发到fluentd
查看>>
struts2系列(二):struts2参数传递错误、struts2的输入错误验证
查看>>
spring mvc拦截器原理分析
查看>>
ARKit从入门到精通(6)-ARSession介绍
查看>>
C复杂声明举例
查看>>
TensorFlow基础笔记(11) max_pool2D函数
查看>>
vue2.0 自定义 饼状图 (Echarts)组件
查看>>