使用路径动画完成一个简洁优雅的启动页动画

是不是受够了千篇一律的透明度变化的启动页动画,快来试试使用路径动画和属性动画构建一个特别的启动页动画吧.

最近在网上看到一个路径动画的例子,感觉效果很不错,仿照着例子写了一个路径动画的库,并且上传到jcenter,方便AS玩家通过依赖使用.
github地址:https://github.com/sunflowerseat/PathAnim
先上效果图,让图说话:
这里写图片描述
接下来,我讲讲怎么通过这个路径动画库来完成一个简洁优雅的启动页动画
首先在module中添加依赖

compile 'com.fancy.library:pathanim:1.0.1'

首先要完成路径动画,我们必须要先有一个路径.
可以使用GIMP 2这个工具来获取一个路径
这里写图片描述

导出路径:
这里写图片描述

得到一个路径之后,我们开始写布局文件
简单写一个logo背景,启动页显示的文字和一个版本号
布局文件参考:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:oak="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:id="@+id/big_background"
        >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/cpb_background"
        android:id="@+id/rl_background"
        android:layout_centerInParent="true"
        >
        <com.fancy.path_anim_lib.AnimatedSvgView
            android:id="@+id/animated_svg_view"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:layout_centerInParent="true"
            oak:oakSvgFillStart="500"
            oak:oakSvgFillTime="100"
            oak:oakSvgImageSizeX="200"
            oak:oakSvgImageSizeY="200"
            oak:oakSvgTraceTime="2000"
            oak:oakSvgTraceTimePerGlyph="1000" />

    </RelativeLayout>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="启动页动画"
        android:textSize="30sp"
        android:layout_below="@+id/rl_background"
        android:textStyle="bold"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="40dp"
        android:textColor="@color/startpage_blue"
        android:id="@+id/name"
        />

    </RelativeLayout>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="8.1.3"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="10dp"
        android:textSize="20sp"
        android:textColor="@color/startpage_blue"
        android:id="@+id/versionCode"
        />
</RelativeLayout>

解释一下AnimatedSvgView中一些重要参数的作用:
oakSvgFillTime路径动画填充时间
oakSvgImageSizeX 原图x所占像素
oakSvgImageSizeY 原图y所占像素
oakSvgTraceTimePerGlyph 路径绘制时间

Activity完成动画参考:

public class MainActivity extends AppCompatActivity {

    private AnimatedSvgView mAnimatedSvgView;
    private RelativeLayout rl_background;
    private RelativeLayout big_background;
    private TextView versionCode;
    private TextView name;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_svg);
        //路径动画的View
        mAnimatedSvgView = (AnimatedSvgView) findViewById(R.id.animated_svg_view);
        //需要整体上移的RelativeLayout
        rl_background = (RelativeLayout) findViewById(R.id.rl_background);
        //需要变换形状的RelativeLayout
        big_background = (RelativeLayout) findViewById(R.id.big_background);
        //版本号文字
        versionCode = (TextView) findViewById(R.id.versionCode);
        versionCode.setAlpha(0);
        //logo下方文字
        name = (TextView) findViewById(R.id.name);
        name.setAlpha(0);
        preAnim(rl_background);
        mAnimatedSvgView.getLayoutParams().width = getScreenWidth(this) / 2;
        mAnimatedSvgView.getLayoutParams().height = getScreenWidth(this) / 2;


        //路径传入,把GIMP2工具导出的path部分作为String传递给该方法.
        mAnimatedSvgView.setGlyphStrings(AnimPath.ANIM_PATH);
        //Path填充颜色
        mAnimatedSvgView.setFillPaints(255,255,255,255);
        //设置跑动光线的颜色
        mAnimatedSvgView.setTraceColors(255,255,255,255);
        //设置轮廓颜色
        mAnimatedSvgView.setTraceResidueColors(255,255,255,255);

        mAnimatedSvgView.setOnStateChangeListener(new AnimatedSvgView.OnStateChangeListener() {
            @Override
            public void onStateChange(int state) {
                if (state == AnimatedSvgView.STATE_FILL_STARTED) {

                    AnimatorSet set = new AnimatorSet();
                    Interpolator interpolator = new DecelerateInterpolator();
                    ObjectAnimator a1 = ObjectAnimator.ofFloat(mAnimatedSvgView, "translationY", 0);
                    a1.setInterpolator(interpolator);
                    set.playTogether(a1);
                    set.start();
                }
            }
        });
    }

    public void preAnim(final View v) {
        GradientDrawable drawable = (GradientDrawable) v.getBackground();
        drawable.setCornerRadius(0);
        ObjectAnimator anim = ObjectAnimator.ofFloat(v, "scaleX", new float[]{1f,1f});
        anim.setDuration(1);
        anim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                start(v,700);
            }
        });
        anim.start();
    }

    public void endAnim() {
        AnimatorSet set = new AnimatorSet();
        ObjectAnimator a2 = ObjectAnimator.ofFloat(big_background, "y", big_background.getY(),big_background.getY()/8);
        ObjectAnimator a3 = ObjectAnimator.ofFloat(versionCode, "alpha", 0f,1f);
        ObjectAnimator a4 = ObjectAnimator.ofFloat(name, "alpha", 0f,1f);
        set.playTogether(a2, a3, a4);
        set.setDuration(700);
        set.start();
        mAnimatedSvgView.start();
    }

    /**
     * 矩形变圆角动画
     */
    public void start(final View v,long duration) {
        //需要的参数 drawable对象
        ObjectAnimator cornerAnimation = ObjectAnimator.ofFloat(v.getBackground(), "cornerRadius", new float[]{0, v.getWidth() / 2});
        cornerAnimation.setDuration(duration);
        final ObjectAnimator heightAnimation = ObjectAnimator.ofInt(v, "xxx", new int[]{v.getHeight(), v.getWidth() / 2});
        heightAnimation.setDuration(duration);
        heightAnimation.addUpdateListener(new com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(com.nineoldandroids.animation.ValueAnimator valueAnimator) {
                v.getLayoutParams().height = (int) heightAnimation.getAnimatedValue();
                v.requestLayout();
            }
        });
        ObjectAnimator animator = ObjectAnimator.ofInt(v, "xx", v.getWidth(), v.getWidth() / 2).setDuration(duration);
        animator.addUpdateListener(new ObjectAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(com.nineoldandroids.animation.ValueAnimator valueAnimator) {
                int value = (int) valueAnimator.getAnimatedValue();
                v.getLayoutParams().width = value;
                v.requestLayout();
            }
        });

        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(cornerAnimation).with(heightAnimation).with(animator);
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                endAnim();
            }
        });
        animatorSet.start();
    }

    public int getScreenWidth(Context context) {
        WindowManager manager = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        Display display = manager.getDefaultDisplay();
        return display.getWidth();
    }
}

好了,经过以上步骤就能完成一个简洁大方的启动页动画了.
最后有几点补充:
关于demo中的矩形变圆的属性动画,需要启动该动画的view背景必须是drawable文件,如下形式:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="0dp" />
    <solid android:color="@color/startpage_blue"/>
</shape>

否则在使用启动属性动画是会报错,当然你也可以不使用这个属性动画,用自己的动画替代.

源码已上传到github

快动手写一个属于你的独特的启动页动画吧.
有任何问题欢迎加群讨论:283272067
希望大家多聊技术,多分享代码.

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
### 回答1: 好的,下面是一个使用 HTML、JS 和 CSS 构建的简单的上传文件的前端面的示例: HTML: ``` <div class="upload-container"> <h1>Upload Your Files</h1> <form action="" method="post" enctype="multipart/form-data"> <input type="file" id="file-input" name="file"/> <label for="file-input">Choose a file</label> <button type="submit">Upload</button> </form> </div> ``` CSS: ``` .upload-container { display: flex; flex-direction: column; align-items: center; } input[type="file"] { display: none; } label { background-color: blue; color: white; padding: 12px 20px; border-radius: 25px; cursor: pointer; } button[type="submit"] { background-color: green; color: white; padding: 12px 20px; border-radius: 25px; margin-top: 20px; cursor: pointer; } ``` JS: ``` const input = document.getElementById("file-input"); const label = document.querySelector("label"); label.addEventListener("click", function() { input.click(); }); input.addEventListener("change", function() { label.innerHTML = input.files[0].name; }); ``` 该示例实现了一个简单的上传文件的前端面,用户可以通过点击「Choose a file」按钮选择要上传的文件,并通过点击「Upload」按钮上传文件。 希望对你有帮助! ### 回答2: 要设计一个好看的上传文件的前端面,可以参考以下步骤: 1. 首先,确定面的整体布局和风格。可以选择一个简洁清晰的设计风格,如扁平化或简约风格。面可以分为两个部分:文件选择区和文件展示区。 2. 在文件选择区,设计一个吸引人的上传按钮。使用CSS设置按钮的样式,可以考虑添加动效或渐变效果,以增加面的互动性和吸引力。 3. 为了方便用户了解和选择文件,添加一个文件列表部分。使用HTML的表格或列表元素,以及CSS的样式设置,展示上传的文件名称、大小、日期等信息。 4. 考虑用户体验,为文件选择区添加文件预览功能。可以使用HTML5的File API获取文件的本地路径,然后使用JavaScript将其显示在面上。如果上传的是图片文件,可以在文件预览区域显示缩略图,增加用户的可视性。 5. 为了提高用户的上传效率,可以添加拖放文件上传的功能。使用JavaScript的拖放事件,监听用户的拖放操作,并获取拖入文件的路径。添加一些提示效果,如边框高亮、拖放区域背景色改变等,增强用户的操作体验。 6. 当用户选择完文件后,添加上传按钮。点击该按钮后,使用JavaScript编写文件上传的逻辑,将文件发送到后端服务器进行处理。可以通过Ajax技术实现异步上传,面无需刷新即可显示上传进度和上传结果。 7. 在上传过程中,为了提高用户体验,可以显示上传进度条或动画效果。使用CSS的过渡或动画效果,或者在JavaScript中实时计算并更新上传进度。 8. 最后,添加一些错误处理的提示。如未选择文件、文件类型不支持等错误情况的提示信息,可以使用JavaScript的弹窗或浮动提示框等方式进行展示。 通过以上步骤,可以设计一个既美观又实用的上传文件的前端面。在设计过程中,要注重用户体验和交互性,保证面的易用性和可访问性。 ### 回答3: 要设计一个好看的上传文件的前端面,可以采用以下的HTML、CSS和JavaScript代码实现。 HTML部分: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>上传文件面</title> <link rel="stylesheet" href="style.css"> </head> <body> <div class="container"> <h1>上传文件</h1> <form id="uploadForm" action="upload.php" method="post" enctype="multipart/form-data"> <input type="file" name="file" id="fileInput"> <button type="submit">上传</button> </form> <p id="status"></p> </div> <script src="script.js"></script> </body> </html> ``` CSS部分(style.css): ```css body { background-color: #f2f2f2; font-family: Arial, sans-serif; } .container { width: 300px; margin: 0 auto; padding: 20px; background-color: #fff; border-radius: 5px; box-shadow: 0 0 5px rgba(0, 0, 0, 0.1); } h1 { text-align: center; } input[type="file"] { display: block; margin: 10px 0; } button { display: block; margin: 0 auto; padding: 10px 20px; background-color: #428bca; color: #fff; border: none; border-radius: 3px; cursor: pointer; } p#status { text-align: center; margin-top: 20px; font-weight: bold; color: #428bca; } ``` JavaScript部分(script.js): ```javascript document.getElementById("uploadForm").addEventListener("submit", function(e) { e.preventDefault(); // 阻止默认提交行为 var fileInput = document.getElementById("fileInput"); var file = fileInput.files[0]; if (file) { var fileSize = file.size; var fileName = file.name; // 将文件信息展示给用户 document.getElementById("status").innerHTML = "正在上传: " + fileName + " (" + fileSize + " bytes)"; // 可以在这里使用AJAX或者FormData发送文件到服务器 } }); ``` 这个前端使用简洁清晰的样式,有一个标题,一个文件选择框,一个上传按钮和一个用于展示上传状态的段落。点击上传按钮时,会通过JavaScript获取到用户选择的文件,然后可以通过AJAX或者FormData将文件发送到后端服务器处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值