精华内容
下载资源
问答
  • 所以在触发这些操作的同时,往往需要过渡形式动画来引导用户是如何从一个界面切换到另一个界面的,我们来看看一些常见的界面切换的过渡方式吧。淡入淡出的过渡效果是最为常见的处理手法,这种效果往往能很直观的...
  • 除了整体 UI 的美观,在合适的地方添加合适的动画效果往往比静态页面更具有表现力,达到更自然的效果。比如,一个简单的 loading 动画或者页面切换效果不仅能缓解用户的等待情绪,甚至通过使用品牌 logo 等形式,...
  • 常见动画的缓动函数

    千次阅读 2019-05-09 10:23:08
    大多时候,我们的动画都是线性变化的。例如,一个点从0运动到1,假如中间有8个点,那就应该是0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8。但有的时候,我们需要一种非线性的变化。例如我们做一架飞机起飞,它的变化应该是从慢...

    大多时候,我们的动画都是线性变化的。例如,一个点从0运动到1,假如中间有8个点,那就应该是0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8。但有的时候,我们需要一种非线性的变化。例如我们做一架飞机起飞,它的变化应该是从慢到快的。又比如一个小球落地,它的轨迹应该是抛物线,而且还会弹起。

    要做到这些,就需要用到缓动函数(EasingFunction)。很多语言都提供了缓动函数库,但如我们想(或者说需要)自己实现时,就需要知道这些缓动函数的函数形式。

    我们让时间为t,值为y,那么缓动函数就是y=f(t)。我们假设t的取值范围是[0,1],同样y的值域也是[0,1],这个规定对我们后面的计算有极大的帮助。怎么把时间变成[0,1]里的数,又怎么把[0,1]范围的值转为实际的值,相信并不难。举个例子,我们的时间是[0,1000ms],那么把时间除以1000,就是[0,1]的数组了。我们的值是[15,100],那么我们把结果x作以下运算即可转化:15+(100-15)*x。

    我们知道,很多缓动函数都有EaseIn,EaseOut,EaseInOut的选项。其实EaseIn就是EaseOut旋转180度得到的,而EaseInOut是把值分为[0,0.5],(0,5,1]两段,前面用EaseIn,后面用EaseOut得到的。假如我们已经得到EaseIn的函数形式是y=f(t),那么EaseOut的函数形式就是y=1-f(1-t)。所以我们只需要求出每种缓动函数的EaseIn即可。

    一、线性变化

    不使用缓动函数默认就是线性变化。它的函数形式很明显:

    y=t

    没错,这就是线性动画的缓动函数。

    二、端点略有收回(BackEase)

    表现出来就是一辆车开得太快,过了终点又往回倒一点点。

    函数形式是:

    y=t^3-0.3*t*sin(t*π)

    C#代码:

    case EasingMethod.BackEaseIn:
        t = x[i];
        MidValues[i] = Math.Pow(t, 3) - 0.3 * t * Math.Sin(t * Math.PI);
        break;
    case EasingMethod.BackEaseOut:
        t = 1 - x[i];
        MidValues[i] = 1 - (Math.Pow(t, 3) - 0.3 * t * Math.Sin(t * Math.PI));
        break;

    三、加速/减速(SineEase)(较缓)

    表现出来是慢慢加速。

    函数形式是:

    y=sin(t*π/2)

    C#代码:

    case EasingMethod.SineEaseIn:
        t = 1 - x[i];
        MidValues[i] = 1 - (Math.Sin(t * Math.PI / 2));
        break;
    case EasingMethod.SineEaseOut:
        t = x[i];
        MidValues[i] = Math.Sin(t * Math.PI / 2);
        break;

    四、加速/减速(CircleEase)(较迅速)

    同样是加速,这个表现出来就是加油加得很猛那种。

    函数形式:

    y=sqrt(1-t^2)

    其实加减数函数还有很多,可以用幂不同的指数函数去做,例如是t^2、t^3、t^4,指数越大,变化越迅速。

    C#代码:

    case EasingMethod.CircleEaseIn:
        t = x[i];
        MidValues[i] = 1 - Math.Sqrt(1 - t * t);
        break;
    case EasingMethod.CircleEaseOut:
        t = 1 - x[i];
        MidValues[i] = Math.Sqrt(1 - t * t);
        break;

    五、振荡(ElasticEase)

    这个一般做弹簧的那种运动。

    函数形式:

    y=100^t*sin(8.5π*t)/100

    C#代码:

    case EasingMethod.ElasticEaseIn:
        t = x[i];
        MidValues[i] = Math.Pow(100, t) * Math.Sin(8.5 * Math.PI * t) / 100;
        break;
    case EasingMethod.ElasticEaseOut:
        t = 1 - x[i];
        MidValues[i] = 1 - (Math.Pow(100, t) * Math.Sin(8.5 * Math.PI * t) / 100);
        break;

    六、弹跳(BounceEase)

    这个表现出来就是有弹力的小球落地的那种运动了。

    这种运行没办法有一个统一的函数去做,我们只能把它切成若干段,每一段都是抛物线:

    [0,0.1]  y=-(t-0.05)^2+0.0025

    (0.1,0.3]  y=-(t-0.2)^2+0.01

    (0.3,0.7]  y=-(t-0.5)^2+0.04

    (0.7,1]  y=-(t-1)^2+0.09

    C#代码:

    case EasingMethod.BounceEaseIn:
        t = x[i];
        MidValues[i] = (
            (t <= 0.1 ? (-Math.Pow(t - 0.05, 2) + 0.0025) : 0) +
            ((t > 0.1 && t <= 0.3) ? (-Math.Pow(t - 0.2, 2) + 0.01) : 0) +
            ((t > 0.3 && t <= 0.7) ? (-Math.Pow(t - 0.5, 2) + 0.04) : 0) +
            (t > 0.7 ? (-Math.Pow(t - 1, 2) + 0.09) : 0)
            ) / 0.09;
        break;
    case EasingMethod.BounceEaseOut:
        t = 1 - x[i];
        MidValues[i] = 1 - (
            (t <= 0.1 ? (-Math.Pow(t - 0.05, 2) + 0.0025) : 0) +
            ((t > 0.1 && t <= 0.3) ? (-Math.Pow(t - 0.2, 2) + 0.01) : 0) +
            ((t > 0.3 && t <= 0.7) ? (-Math.Pow(t - 0.5, 2) + 0.04) : 0) +
            (t > 0.7 ? (-Math.Pow(t - 1, 2) + 0.09) : 0)
            ) / 0.09;
        break;

     

    展开全文
  • 互联网广告表现形式有哪几种?

    千次阅读 2019-06-20 09:50:49
    随着互联网技术的发展,互联网广告已成为企业推广的重要途径,那么互联网广告的形式...网幅广告具有诸如通栏、旗帜、按钮、对联、浮动等表现形式常见的横幅尺寸为:950 * 60通栏Banner,468 * 60全尺寸Banner,12...

    随着互联网技术的发展,互联网广告已成为企业推广的重要途径,那么互联网广告的形式又有哪些?我们一起来看看!

    1、网幅广告(Banner)

    网幅广告是最早的互联网广告形式。它是以GIF,JPG,Flash等格式创建的图像文件,定位在网页中用来展现广告内容。网幅广告具有诸如通栏、旗帜、按钮、对联、浮动等表现形式。常见的横幅尺寸为:950 * 60通栏Banner,468 * 60全尺寸Banner,125 * 125方形按钮,120 * 90按钮,120 * 60按钮,88 * 31小按钮,120 * 240垂直Banner等

    我们可以将网幅广告分为三类:静态,动态和交互式。

    静态:静态网幅是网页上的固定广告图像。它的优点是制作简单;缺点不够生动,有些沉闷乏味。事实证明,静态广告的点击率和互动广告的点击率很低。

    动态:动态网幅广告具有各种动态元素,或移动或闪烁。它通常使用GIF动态图像格式或Flash动画格式。通过丰富多彩的动态图像,它可以向观众提供更多信息,并加深观众的印象。动态广告的点击率通常高于静态广告的点击率。动态广告在制作中并不比静态广告复杂得多,而且尺寸也很小,因此它是目前最重要的互联网广告形式。

    交互式:无论是静态广告还是动态广告,都还停留在让用户被动看的阶段。互联网相对于传统媒体的最大优势是互动,因此出现了对观众更具吸引力的交互式广告。交互式广告有多种形式,例如游戏,插播式,回答问题,下拉菜单,填写表格等。这类广告不再是让用户单纯地看广告,还需要用户参与到广告中来,甚至“玩”广告。这种广告比其他广告包含更多的内容,可以让用户在参与的过程中,对企业与产品有更深刻的认识和了解。

    2、文本链接广告

    文本链接广告是一行文字作为一个广告,点击进入相应的广告页面。这是一种对浏览者干扰最少,但却较为有效果的互联网广告形式。有时候,最简单广告形式效果却最好。

    3、富媒体广告

    在互联网发展初期,由于宽带原因,互联网广告主要基于文本和低质量的GIF和JPG格式图片为主。随着互联网的普及和技术的进步,出现了具有声音,图像和文字的多媒体组合的媒体形式,人们普遍把这些媒介形式的组合叫富媒体,以技术设计的广告被称为富媒体广告。富媒体广告形式多样,内容丰富,影响力强,但通常成本更高。

    4、视频广告

    视频广告是通着网络视频的发展而新兴的一种广告形式。它的表现手法类似于传统的电视广告,都是在正常的视频节目中插入广告片段。例如,在节目开始之前或节目结束之后播放广告视频。与插播式广告一样,它也是一种迫使用户观看的广告形式,但它比前者更友好。

    5、搜索引擎竞价广告

    竞价是搜索引擎广告的主要形式。这是一种根据最高支付原则对购买相同关键字的网站进行排名的方法。拍卖排名最重要的特征是按点击付费。如果用户没有点击,则不收取广告费。在同一关键词广告中,单次点击出价最高的广告排列在第一位,其他位置按照广告主出价不同,从高到低来一次排队。

    展开全文
  • React 中常见动画实现方式

    千次阅读 2019-08-06 15:51:35
    除了整体 UI 的美观,在合适的地方添加合适的动画效果往往比静态页面更具有表现力,达到更自然的效果。比如,一个简单的 loading 动画或者页面切换效果不仅能缓解用户的等待情绪,甚至通过使用品牌 logo 等形式,...

    有什么问题可以加微信问吧 cannywill ,尽量帮助, 一起进步

    转自于:https://segmentfault.com/a/1190000012783439

    现在,用户对于前端页面的要求已经不能满足于实现功能,更要有颜值,有趣味。除了整体 UI 的美观,在合适的地方添加合适的动画效果往往比静态页面更具有表现力,达到更自然的效果。比如,一个简单的 loading 动画或者页面切换效果不仅能缓解用户的等待情绪,甚至通过使用品牌 logo 等形式,默默达到品牌宣传的效果。

    React 作为最近几年比较流行的前端开发框架,提出了虚拟 DOM 概念,所有 DOM 的变化都先发生在虚拟 DOM 上,通过 DOM diff 来分析网页的实际变化,然后反映在真实 DOM 上,从而极大地提升网页性能。然而,在动画实现方面,React 作为框架并不会直接给组件提供动画效果,需要开发者自行实现,而传统 web 动画大多数都通过直接操作实际 DOM 元素来实现,这在 React 中显然是不被提倡的。那么,在 React 中动画都是如何实现的呢?

    所有动画的本质都是连续修改 DOM 元素的一个或者多个属性,使其产生连贯的变化效果,从而形成动画。在 React 中实现动画本质上与传统 web 动画一样,仍然是两种方式: 通过 css3 动画实现和通过 js 修改元素属性。只不过在具体实现时,要更为符合 React 的框架特性,可以概括为几类:

    1. 基于定时器或 requestAnimationFrame(RAF) 的间隔动画;
    2. 基于 css3 的简单动画;
    3. React 动画插件 CssTransitionGroup
    4. 结合 hook 实现复杂动画;
    5. 其他第三方动画库。

    一、基于定时器或 RAF 的间隔动画

    最早,动画的实现都是依靠定时器 setIntervalsetTimeout 或者 requestAnimationFrame(RAF) 直接修改 DOM 元素的属性。不熟悉 React 特性的开发者可能会习惯性地通过 ref 或者 findDOMNode() 获取真实的 DOM 节点,直接修改其样式。然而,通过 ref 直接获取真实 DOM 并对其操作是是不被提倡使用,应当尽量避免这种操作。

    因此,我们需要将定时器或者 RAF 等方法与 DOM 节点属性通过 state 联系起来。首先,需要提取出与变化样式相关的属性,替换为 state,然后在合适的生命周期函数中添加定时器或者 requestAnimationFrame 不断修改 state,触发组件更新,从而实现动画效果。

    示例

    以一个进度条为例,代码如下所示:

    // 使用requestAnimationFrame改变state
    import React, { Component } from 'react';
    
    export default class Progress extends Component {
        constructor(props) {
            super(props);
            this.state = {
                percent: 10
            };
        }
    
        increase = () => {
            const percent = this.state.percent;
            const targetPercent = percent >= 90 ? 100 : percent + 10;
            const speed = (targetPercent - percent) / 400;
            let start = null;
            const animate = timestamp => {
                if (!start) start = timestamp;
                const progress = timestamp - start;
                const currentProgress = Math.min(parseInt(speed * progress + percent, 10), targetPercent);
                this.setState({
                    percent: currentProgress
                });
                if (currentProgress < targetPercent) {
                    window.requestAnimationFrame(animate);
                }
            };
            window.requestAnimationFrame(animate);
        }
    
        decrease = () => {
            const percent = this.state.percent;
            const targetPercent = percent < 10 ? 0 : percent - 10;
            const speed = (percent - targetPercent) / 400;
            let start = null;
            const animate = timestamp => {
                if (!start) start = timestamp;
                const progress = timestamp - start;
                const currentProgress = Math.max(parseInt(percent - speed * progress, 10), targetPercent);
                this.setState({
                        percent: currentProgress
                    });
                if (currentProgress > targetPercent) {
                    window.requestAnimationFrame(animate);
                }
            };
            window.requestAnimationFrame(animate);
        }
    
        render() {
            const { percent } = this.state;
    
            return (
                <div>
                    <div className="progress">
                        <div className="progress-wrapper" >
                            <div className="progress-inner" style = {{width: `${percent}%`}} ></div>
                        </div>
                        <div className="progress-info" >{percent}%</div>
                    </div>
                    <div className="btns">
                        <button onClick={this.decrease}>-</button>
                        <button onClick={this.increase}>+</button>
                    </div>
                </div>
            );
        }
    }

    在示例中,我们在 increase 和 decrease 函数中构建线性过渡函数 animationrequestAnimationFrame 在浏览器每次重绘前执行会执行过渡函数,计算当前进度条width 属性并更新该 state,使得进度条重新渲染。该示例的效果如下所示:

    RAF实现进度条效果

    这种实现方式在使用 requestAnimationFrame 时性能不错,完全使用纯 js 实现,不依赖于 css,使用定时器时可能出现掉帧卡顿现象。此外,还需要开发者根据速度函数自己计算状态,比较复杂。

    二、基于 css3 的简单动画

    当 css3 中的 animation 和 transition 出现和普及后,我们可以轻松地利用 css 实现元素样式的变化,而不用通过人为计算实时样式。

    示例

    我们仍以上面的进度条为例,使用 css3 实现进度条动态效果,代码如下所示:

    import React, { Component } from 'react';
    
    export default class Progress extends Component {
        constructor(props) {
            super(props);
            this.state = {
                percent: 10
            };
        }
    
        increase = () => {
            const percent = this.state.percent + 10;
            this.setState({
                percent: percent > 100 ? 100 : percent,
            })
        }
    
        decrease = () => {
            const percent = this.state.percent - 10;
            this.setState({
                percent: percent < 0 ? 0 : percent,
            })
        }
    
        render() {
            // 同上例, 省略
            ....
        }
    }
    .progress-inner {
      transition: width 400ms cubic-bezier(0.08, 0.82, 0.17, 1);
      // 其他样式同上,省略
      ...
    }

    在示例中,increase 和 decrease 函数中不再计算 width,而是直接设置增减后的宽度。需要注意的是,在 css 样式中设置了 transition 属性,当 width 属性发生变化时自动实现样式的动态变化效果,并且可以设置不同的速度效果的速度曲线。该示例的效果如下图所示,可以发现,与上一个例子不同的是,右侧的进度数据是直接变化为目标数字,没有具体的变化过程,而进度条的动态效果因为不再是线性变化,效果更为生动。

    进度条效果

    基于 css3 的实现方式具有较高的性能,代码量少,但是只能依赖于 css 效果,对于复杂动画也很难实现。此外,通过修改 state 实现动画效果,只能作用于已经存在于 DOM 树中的节点。如果想用这种方式为组件添加入场和离场动画,需要维持至少两个 state 来实现入场和离场动画,其中一个 state 用于控制元素是否显示,另一个 state 用于控制元素在动画中的变化属性。在这种情况下,开发者需要花费大量精力来维护组件的动画逻辑,十分复杂繁琐。

    三、React 动画插件 CssTransitionGroup

    React 曾为开发者提供过动画插件 react-addons-css-transition-group,后交由社区维护,形成现在的 react-transition-group,该插件可以方便地实现组件的入场和离场动画,使用时需要开发者额外安装。react-transition-group 包含 CSSTransitionGroup 和 TransitionGroup 两个动画插件,其中,后者是底层 api,前者是后者的进一步封装,可以较为便捷地实现 css 动画。

    示例

    以一个动态增加tab的为例,代码如下:

    import React, { Component } from 'react';
    import { CSSTransitionGroup } from 'react-transition-group';
    
    let uid = 2;
    export default class Tabs extends Component {
        constructor(props) {
            super(props);
            this.state = {
                activeId: 1,
                tabData: [{
                    id: 1,
                    panel: '选项1'
                }, {
                    id: 2,
                    panel: '选项2'
                }]
            };
        }
    
        addTab = () => {
            // 添加tab代码
            ...
        }
    
        deleteTab = (id) => {
            // 删除tab代码
            ...
        }
    
        render() {
            const { tabData, activeId } = this.state;
    
            const renderTabs = () => {
                return tabData.map((item, index) => {
                    return (
                        <div
                            className={`tab-item${item.id === activeId ? ' tab-item-active' : ''}`}
                            key={`tab${item.id}`}
                        >
                            {item.panel}
                            <span className="btns btn-delete" onClick={() => this.deleteTab(item.id)}>✕</span>
                        </div>
                    );
                })
            }
    
            return (
                <div>
                    <div className="tabs" >
                        <CSSTransitionGroup
                          transitionName="tabs-wrap"
                          transitionEnterTimeout={500}
                          transitionLeaveTimeout={500}
                        >
                          {renderTabs()}
                        </CSSTransitionGroup>
                        <span className="btns btn-add" onClick={this.addTab}>+</span>
                    </div>
                    <div className="tab-cont">
                        cont
                    </div>
                </div>
            );
        }
    }
    /* tab动态增加动画 */
    .tabs-wrap-enter {
      opacity: 0.01;
    }
    
    .tabs-wrap-enter.tabs-wrap-enter-active {
      opacity: 1;
      transition: all 500ms ease-in;
    }
    
    .tabs-wrap-leave {
      opacity: 1;
    }
    
    .tabs-wrap-leave.tabs-wrap-leave-active {
      opacity: 0.01;
      transition: all 500ms ease-in;
    }

    CSSTransitionGroup 可以为其子节点添加额外的 css 类,然后通过 css 动画达到入场和离场动画效果。为了给每个 tab 节点添加动画效果,需要先将它们包裹在 CSSTransitionGroup 组件中。 当设定 transitionName 属性为 'tabs-wrapper'transitionEnterTimeout 为400毫秒后,一旦 CSSTransitionGroup 中新增节点,该新增节点会在出现时被添加上 css 类 'tabs-wrapper-enter',然后在下一帧时被添加上 css 类 'tabs-wrapper-enter-active'。由于这两个 css 类中设定了不同的透明度和 css3 transition 属性,所以节点实现了透明度由小到大的入场效果。400毫秒后 css 类 'tabs-wrapper-enter' 和 'tabs-wrapper-enter-active' 将会同时被移除,节点完成整个入场动画过程。离场动画的实现类似于入场动画,只不过被添加的 css 类名为 'tabs-wrapper-leave' 和 'tabs-wrapper-leave-active'。该示例效果如下图所示:

    动态增加tab效果

    CSSTransitionGroup 支持以下7个属性:
    CSSTransitionGroup 属性

    其中,入场和离场动画是默认开启的,使用时需要设置 transitionEnterTimeout 和 transitionLeaveTimeout。值得注意的是,CSSTransitionGroup 还提供出现动画(appear),使用时需要设置 transitionAppearTimeout。那么,出现动画和入场动画有什么区别呢?当设定 transitionAppear 为 true 时,CSSTransitionGroup 在初次渲染时,会添加一个出现阶段。在该阶段中,CSSTransitionGroup 的已有子节点都会被相继添加 css 类 'tabs-wrapper-appear' 和 'tabs-wrapper-appear-active',实现出现动画效果。因此,出现动画仅适用于 CSSTransitionGroup 在初次渲染时就存在的子节点,一旦 CSSTransitionGroup 完成渲染,其子节点就只可能有入场动画(enter),不可能有出现动画(appear)。

    此外,使用 CSSTransitionGroup 需要注意以下几点:

    • CSSTransitionGroup 默认在 DOM 树中生成一个 span 标签包裹其子节点,如果想要使用其他 html 标签,可设定 CSSTransitionGroup 的 component 属性;
    • CSSTransitionGroup 的子元素必须添加 key 值才会在节点发生变化时,准确地计算出哪些节点需要添加入场动画,哪些节点需要添加离场动画;
    • CSSTransitionGroup 的动画效果只作用于直接子节点,不作用于其孙子节点;
    • 动画的结束时间不以 css 中 transition-duration 为准,而是以 transitionEnterTimeouttransitionLeaveTimeoutTransitionAppearTimeout 为准,因为某些情况下 transitionend 事件不会被触发,详见MDN transitionend

    CSSTransitionGroup 实现动画的优点是:

    • 简单易用,可以方便快捷地实现元素的入场和离场动画;
    • 与 React 结合,性能比较好。

    CSSTransitionGroup 缺点也十分明显:

    • 局限于出现动画,入场动画和离场动画;
    • 由于需要制定 transitionName,灵活性不够;
    • 只能依靠 css 实现简单的动画。

    四、结合 hook 实现复杂动画

    在实际项目中,可能需要一些更炫酷的动画效果,这些效果仅依赖于 css3 往往较难实现。此时,我们不妨借助一些成熟的第三方库,如 jQuery 或 GASP,结合 React 组件中的生命周期钩子方法 hook 函数,实现复杂动画效果。除了 React 组件正常的生命周期外,CSSTransitionGroup 的底层 api TransitonGroup 还为其子元素额外提供了一系列特殊的生命周期 hook 函数,在这些 hook 函数中结合第三方动画库可以实现丰富的入场、离场动画效果。

    TransisitonGroup 分别提供一下六个生命周期 hook 函数:

    • componentWillAppear(callback)
    • componentDidAppear()
    • componentWillEnter(callback)
    • componentDidEnter()
    • componentWillLeave(callback)
    • componentDidLeave()

    它们的触发时机如图所示:

    示例

    GASP 是一个 flash 时代发展至今的动画库,借鉴视频帧的概念,特别适合做长时间的序列动画效果。本文中,我们用 TransitonGroup 和 react-gsap-enhancer(一个可以将 GSAP 应用于 React 的增强库)完成一个图片画廊,代码如下:

    import React, { Component } from 'react';
    import { TransitionGroup } from 'react-transition-group';
    import GSAP from 'react-gsap-enhancer'
    import { TimelineMax, Back, Sine } from 'gsap';
    
    class Photo extends Component {
        constructor(props) {
            super(props);
        }
    
        componentWillEnter(callback) {
            this.addAnimation(this.enterAnim, {callback: callback})
        }
    
        componentWillLeave(callback) {
            this.addAnimation(this.leaveAnim, {callback: callback})
        }
    
        enterAnim = (utils) => {
            const { id } = this.props;
            return new TimelineMax()
                .from(utils.target, 1, {
                    x: `+=${( 4 - id ) * 60}px`,
                    autoAlpha: 0,
                    onComplete: utils.options.callback,
                }, id * 0.7);
        }
    
        leaveAnim = (utils) => {
            const { id } = this.props;
            return new TimelineMax()
                .to(utils.target, 0.5, {
                    scale: 0,
                    ease: Sine.easeOut,
                    onComplete: utils.options.callback,
                }, (4 - id) * 0.7);
        }
    
        render() {
            const { url } = this.props;
            return (
                <div className="photo">
                    <img src={url} />
                </div>
            )
        }
    }
    
    const WrappedPhoto = GSAP()(Photo);
    
    export default class Gallery extends Component {
        constructor(props) {
            super(props);
            this.state = {
                show: false,
                photos: [{
                    id: 1,
                    url: 'http://img4.imgtn.bdimg.com/it/u=1032683424,3204785822&fm=214&gp=0.jpg'
                }, {
                    id: 2,
                    url: 'http://imgtu.5011.net/uploads/content/20170323/7488001490262119.jpg'
                }, {
                    id: 3,
                    url: 'http://tupian.enterdesk.com/2014/lxy/2014/12/03/18/10.jpg'
                }, {
                    id: 4,
                    url: 'http://img4.imgtn.bdimg.com/it/u=360498760,1598118672&fm=27&gp=0.jpg'
                }]
            };
        }
    
        toggle = () => {
            this.setState({
                show: !this.state.show
            })
        }
    
        render() {
            const { show, photos } = this.state;
    
            const renderPhotos = () => {
                return photos.map((item, index) => {
                    return <WrappedPhoto id={item.id} url={item.url} key={`photo${item.id}`} />;
                })
            }
    
            return (
                <div>
                    <button onClick={this.toggle}>toggle</button>
                    <TransitionGroup component="div">
                        {show && renderPhotos()}
                    </TransitionGroup>
                </div>
            );
        }
    }

    在该示例中,我们在子组件 Photo 的 componentWillEnter 和 componentWillLeave 两个 hook 函数中为每个子组件添加了入场动画 enterAnim 和 离场动画 LeaveAnim。在入场动画中,使用 TimeLineMax.from(target, duration, vars, delay) 方式建立时间轴动画,指定了每个子组件的动画移动距离随 id 增大而减小,延期时间随着 id 增大而增大,离场动画中每个子组件的延期时间随着 id 增大而减小,从而实现根据组件 id 不同具有不同的动画效果。实际使用时,你可以根据需求对任一子组件添加不同的效果。该示例的效果如下图所示:

     

    在使用 TransitionGroup 时,在 componentnWillAppear(callback)componentnWillEntercallback)componentnWillLeave(callback) 函数中一定要在函数逻辑结束后调用 callback,以保证 TransitionGroup 能正确维护子节点的状态序列。关于 GASP 的详细使用方法可参考GASP官方文档和博文GSAP,专业的Web动画库,本文不再赘述。

    结合 hook 实现动画可以支持各种复杂动画,如时间序列动画等,由于依赖第三方库,往往动画效果比较流畅,用户体验较好。但是第三方库的引入,需要开发者额外学习对应的 api,也提升了代码复杂度。

    五、其他第三方动画库

    此外,还有很多优秀的第三方动画库,如 react-motion,Animated,velocity-react等,这些动画库在使用时也各有千秋。

    Animated

    Animated 是一个跨平台的动画库,兼容 React 和 React Native。由于在动画过程中,我们只关心动画的初始状态、结束状态和变化函数,并不关心每个时刻元素属性的具体值,所以 Animated 采用声明式的动画,通过它提供的特定方法计算 css 对象,并传入 Animated.div 实现动画效果。

    示例

    我们使用 Animated 实现一个图片翻转的效果,代码如下。

    import React, { Component } from 'react';
    import Animated from 'animated/lib/targets/react-dom';
    
    export default class PhotoPreview extends Component {
        constructor(props) {
            super(props);
            this.state = {
                anim: new Animated.Value(0)
            };
        }
    
        handleClick = () => {
            const { anim } = this.state;
            anim.stopAnimation(value => {
                Animated.spring(anim, {
                    toValue: Math.round(value) + 1
                }).start();
            });
        }
    
        render() {
            const { anim } = this.state;
    
            const rotateDegree = anim.interpolate({
                inputRange: [0, 4],
                outputRange: ['0deg', '360deg']
            });
    
            return (
                <div>
                    <button onClick={this.handleClick}>向右翻转</button>
                    <Animated.div
                        style={{
                            transform: [{
                                rotate: rotateDegree
                            }]
                        }}
                        className="preivew-wrapper"
                    >
                        <img
                            alt="img"
                            src="http://img4.imgtn.bdimg.com/it/u=1032683424,3204785822&fm=214&gp=0.jpg"
                        />
                    </Animated.div>
                </div>
            );
        }
    }

    在该示例中,我们希望实现每点击一次按钮,图片向右旋转90°。在组件初始化时新建了一个初始值为 0 的 Animated 对象 this.state.animAnimated 对象中有插值函数 interpolate,当设定输入区间 inputRange 和输出区间 outputRange 后,插值函数可以根据 Animated 对象的当前值进行线性插值,计算得到对应的映射值。

    在本例中,我们假设每点击一次按钮,this.state.anim 的值加 1,图像需要转动90°。在 render 函数中,我们设置插值函数 this.state.anim.interpolate 的输入区间为[0, 4],输出区间为['0deg', '360deg']。当执行动画时,this.state.anim 的值发生变化,插值函数根据 this.state.anim 当前值,计算得到旋转角度 rotateDegree,触发组件的重新渲染。因此,如果 Animated 对象当前值为 2,对应的旋转角度就是 180deg。在组件渲染结构中,需要使用 Animated.div 包裹动画节点,并将 rotateDegree 封装为 css 对象作为 stlye 传入 Animated.div 中,实现节点 css 属性的变化。

    在点击事件中,考虑到按钮可能连续多次点击,我们首先使用 stopAnimation 停止当前正在进行的动画,该函数会在回调函数中返回一个 {value : number} 对象,value 对应最后一刻的动画属性值。根据获取的 value 值,随后使用 Animated.spring 函数开启一次新的弹簧动画过程,从而实现一个流畅的动画效果。由于每次转动停止时,我们希望图片的翻转角度都是90°的整数倍,所以需要对 Animated.spring 的终止值进行取整。最终我们实现了如下效果:

    image

    使用时需要注意一下几点:

    • Animated 对象的值和其插值结果只能作用于 Animated.div 节点;
    • interpolate 默认会根据输入区间和输出区间进行线性插值,如果输入值超出输入区间不受影响,插值结果默认会根据输出区间向外延展插值,可以通过设置 extrapolate 属性限制插值结果区间。

    Animated 在动画过程中不直接修改组件 state,而是通过其新建对象的组件和方法直接修改元素的属性,不会重复触发 render 函数,是 React Native 中非常稳定的动画库。但是在 React 中存在低版本浏览器兼容问题,且具有一定学习成本。

    结语

    当我们在 React 中实现动画时,首先要考量动画的难易程度和使用场景,对于简单动画,优先使用 css3 实现,其次是基于 js 的时间间隔动画。如果是元素入场动画和离场动画,则建议结合 CSSTransitionGroup 或者 TransitionGroup 实现。当要实现的动画效果较为复杂时,不妨尝试一些优秀的第三方库,打开精彩的动效大门。

    Ps. 本文所有示例代码可访问 github 查看

    展开全文
  • 在flash动画中,尤其是在短片制作中,或多或少要表现出一些更复杂的动作。但是,flash本身的道法局限性,让我们觉得在制作动画时...逐帧动画动画的一种常见形式,即逐帧绘制动作的每个细节。显然,这是一项艰苦的工作

    在flash动画中,尤其是在短片制作中,或多或少要表现出一些更复杂的动作。但是,flash本身的道法局限性,让我们觉得在制作动画时手脚受到束缚,或者在动画上花费了太多的时间和精力。在这里,艺点动画总结了我在制作动画短片方面的一些经验。这些技巧不仅用于flash动画,而且有助于制作GIF动画。当你遇到这样的问题时,你可以参考一下。

    主要包括逐帧动画的方法和技巧,以及充分利用flash变形功能的表现技巧。

    逐帧动画的表现方法与技术

    逐帧动画是动画的一种常见形式,即逐帧绘制动作的每个细节。显然,这是一项艰苦的工作,但使用一些小技巧可以减少工作量。

    这些技巧包括:简化主体、循环法、节选渐变法、替代法、复制法、再加工法、掩蔽法等,下面我们用动画实例逐一详细讲解。你也可以参考这些视频演示教程,轻松掌握flash和动画制作的基本用法。(flashmx多媒体系统教程,flashmx2004视频教程实例制作分析)

    首先,动作的主体是否简单,对生产的工作量有很大的影响。善于简化活动主体,可以使工作效率提高一倍。

    其中一个最明显的例子就是小“媒人”功夫系列。从图中可以看出,动画的主体相当简化。如果我们用这类题材来制作以动作为主的电影,如果采用整体逐帧制作,工作量也可以承受。试想一下,用逼真的人像作为动作的主体来制作这样的动画,工作量会增加很多。

    1.循环法

    这是最常用的动画表现方法。它将一些动作简化为一个只有几帧,甚至两三帧动画的电影剪辑(例如,兔子的翻跟头动作是由前一个例子中的两个帧组成的)。它利用电影剪辑的循环特性来显示一些动画,如头发、衣服漂浮、行走、说话等动画。这种方法经常被使用。

    逐帧动画(下载原始文件)逐帧动画逐帧动画逐帧动画逐帧动画帧3

    在上面的例子中,元帅天篷斗篷的浮动动画是一个由三个帧组成的电影剪辑。聪明的读者一定认为只需要绘制一个框架,其他两个框架可以在第一个框架的基础上稍作修改。

    注:这种逐帧循环的动画,要注意其“节奏”,才能取得好的效果。

    2.节选渐变法

    手掌打开和关闭(下载原始文件)

    在表演一个“慢”动作时,如手慢慢张开,头(前)慢慢抬起,一帧一帧的动画会让你窒息而死。我们可以考虑从整个动作中选取几个关键帧,然后用渐变或闪光的方法来表现整个动作。

    3.替代法

    这是一个聪明的方法,可以用其他东西代替复杂的动作。另一个可以是很多东西,比如阴影和声音。下面两个例子使用阴影和声音来表示动作。
    如果能够帮助到大家,希望能给我多多鼓励我哦!

    展开全文
  • 1、生成压缩包时请一定设置压缩格式为存储而不是其它压缩模式。...这是查看缩略图所产生的缓存文件,你一定是使用缩略图的形式查看图片文件了,所以才会出现这个文件,这是正常的表现,并不是什么病毒。 禁止产生T
  • Android 动画之补间动画

    千次阅读 2016-10-24 21:15:30
    在Android中,动画可以分为三种模式,View Animation、Frame Animation、Property Animation,其中Frame Animation又是View Animation一种特殊形式,只不过它和平移、旋转等常见的View Animation在表现形式上略有...
  •   动画的概念不同于一般意义上的动画片,动画是一种综合艺术,它是集合了绘画、漫画、电影、数字媒体、摄影、音乐、文学等众多艺术门类于一身的艺术表现形式。   动画的英文有很多表述,如animation、cartoon、...
  • Android动画
  • Android的动画可以分为三种:View动画、帧动画和属性动画,帧动画也属于View动画的一种,只不过它和平移、旋转等常见的View动画表现形式上略有不同而已。 1、View动画 平移动画:TranslateAnimation 缩放动画:...
  • 动画补间动画

    2019-07-07 21:35:14
      动画的概念不同于一般意义上的动画片,动画是一种综合艺术,它是集合了绘画、漫画、电影、数字媒体、摄影、音乐、文学等众多艺术门类于一身的艺术表现形式。   动画的英文有很多表述,如animation、cartoon、...
  • Android动画总结

    2016-08-14 14:09:42
    严格来讲,帧动画也属于View动画,只是它和常见的View动画表现形式不一样而已View动画属于对各种场景对象做图像变换从而产生动画效果,属于渐进式动画,且支持自定义;帧动画是按一定顺序播放一系列图像产生的动画...
  • Android动画深入分析

    2016-08-11 21:52:10
    动画分为三种:帧动画,属性动画,视图动画,其实帧动画也属于视图动画的一种,只不过它和平移、旋转等常见的View动画表现形式上略有不同。帧动画是顺序播放一组预先定义好的图片,类似于电影播放,使用xml定义,使用...
  • 七、Android动画

    2016-03-19 16:44:51
    Android的动画可以分为3种,View动画,帧动画和属性动画,其实帧动画也...View动画的一种,只不过它和平移,旋转等常见的View动画表现形式上面略有 不同而已。 属性动画通过动态地改变对象的属性从而达到动画效果。
  • Android动画入门(一)

    2015-12-24 00:22:53
    动画可以分为三种:View动画、帧动画、属性动画,其实帧动画也属于View动画的一种,只不过它和平移、旋转等常见的View动画表现形式上略有不同而已。View动画通过对场景里的对象不断做图像变换(平移、缩放、...
  • 逐帧动画讲解

    2017-12-01 10:16:51
    逐帧动画是一种常见动画形式(Frame By Frame),其原理是在“连续的关键帧”中分解动画动作,也就是在时间轴的每帧上逐帧绘制不同的内容,使其连续播放而成动画。 因为逐帧动画的帧序列内容不一样,不但给制作...
  • 一:简介:  android的动画类型分为两种:  1.视图动画  2....逐帧动画是一种常见动画形式,其原理是在“连续的关键帧“中分解动画动作,也就是在时间轴上的每帧上逐帧绘制不用的内容,使其...
  • 3D动画概述暨骨骼动画实现

    千次阅读 2017-12-20 10:31:53
    引言本文论述了3D领域内的常见动画类型的运作机制。不同于其他文章简单的罗列和介绍每种类型的3D动画,本文尝试以一种优化演进的思路对动画运作机理进行递进式推演,在这个过程中自然而然的推导出常见的几种3D动画...
  • Android动画(一):View动画(补间动画)

    千次阅读 2016-08-07 10:00:32
    一、动画的简单介绍: 在Android项目的开发过程中,如果某些控件或者界面突然的出现或者消失,会造成分厂差的用户体验。所以我们需要为特定的控件或者界面添加一些动画效果.二、分类:View动画(补间动画)、帧动画、...
  • Android中动画的类型,按照系统版本可以简单的分为两大类型,一种是传统的动画,也就是Android中最常用的View动画,即帧动画和补间动画;...View动画动画和补间动画是安卓中最常见动画表现形式有AlphaAni
  • Android之属性动画、值动画

    千次阅读 2015-05-09 11:18:53
    Android属性动画 什么是Android属性动画 同类技术对比 补间动画Tween Animation 帧动画Frame Animation 属性动画Property Animation 属性动画组成部分相关类介绍 ObjectAnimator对象动画执行类 介绍 示例 ...
  • Android自定义动画专题一

    千次阅读 2017-06-25 02:04:48
    Android自定义动画 在目前的移动端产品中,不管是app还是网页一个好看酷炫的...1.Android原生动画Android下已经给我们提供了几种原生动画表现形式:①补间动画平移:TranslateAnimation旋转:RotateAnimation缩放:S

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,832
精华内容 5,132
关键字:

动画常见的表现形式