Android View移动和Kotlin动画

Android View移动和Kotlin动画

坐标系

Android系统中有两种坐标系,分别为Android坐标系和View坐标系

1.Android坐标系
将屏幕左上角的顶点作为Android坐标系的原点,这个原点向右是X轴正方向,向下是Y 轴正方向。另外在触控事件中,使用getRawX()和getRawY()方法获得的坐标也是 Android坐标系的坐标。
在这里插入图片描述
2.View坐标系
View坐标系是相当于Android坐标系的存在,两者存在,更好的控制View
在这里插入图片描述
通过图,就能算出控件的宽和高
View自身的坐标
通过如下方法可以获得View到其父控件(ViewGroup)的距离。
• getTop():获取View自身顶边到其父布局顶边的距离。
• getLeft():获取View自身左边到其父布局左边的距离。
• getRight():获取View自身右边到其父布局左边的距离。
• getBottom():获取View自身底边到其父布局顶边的距离。
3.MotionEvent方法
我们对控件的各种事件,点击,移动,触摸都会触发onTouchEvent(MotionEvent event)这个方法,MotionEvent 提供了获取焦点坐标的各种方法:
• getX():获取点击事件距离控件左边的距离,即视图坐标。
• getY():获取点击事件距离控件顶边的距离,即视图坐标。
• getRawX():获取点击事件距离整个屏幕左边的距离,即绝对坐标。
• getRawY():获取点击事件距离整个屏幕顶边的距离,即绝对坐标。

View的移动

1.控件手动移动
有三种方法重置位置
1)layout方法
2) offsetLeftAndRight(offerx); offsetTopAndBottom(offery);
3) LayoutParams方法重置

public class CustomView extends View {

    private int lastx;
    private int lasty;

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

    public CustomView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //获取手机触摸的坐标
        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastx = x;
                lasty = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //计算移动距离
                int offerx = x - lastx;
                int offery = y - lasty;
                //调用layout方法重置位置
                //1、第一种
                //    layout(getLeft()+offerx,getTop()+offery,getRight()+offerx,getBottom()+offery);
                //2、第二种,也可以调取下面方法刷新位置
                offsetLeftAndRight(offerx);
                offsetTopAndBottom(offery);
                //3、第三种 使用LayoutParams改变控件位置
                //      FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) getLayoutParams();
//                ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
//                layoutParams.leftMargin = getLeft() + offerx;
//                layoutParams.topMargin = getTop() + offery;
//                setLayoutParams(layoutParams);
                break;
        }
        return true;
    }
}

2.View的自动移动
1)采用View动画
可以采用View动画来移动,在res目录新建anim文件夹并创建translate.xml:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true">
    <!--  fillAfter 解决移动又会回到原来的位置。 -->
    <translate
        android:duration ="1000"
        android:fromXDelta="0"
        android:toXDelta="300"/>
</set>

调用

view_translate.animation = AnimationUtils.loadAnimation(this,R.anim.translate)

2)scrollTo与scollBy 和Scroller实现控件平移
scrollTo(x,y)表示移动到一个具体的坐标点,而scrollBy(dx,dy)则表示移动的增量为dx、dy,这个过程是瞬间完成了,如果配合Scroller,就有了过渡滑动的效果,和动画一样,创建自定义控件,创建方法初始化Scroller,重写computeScroll()方法,系统会在绘制View的时候在draw()方法中调用该方法

public class CustomView extends View {

    private int lastx;
    private int lasty;
    private Scroller scroller;

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

    public CustomView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        scroller = new Scroller(context);
    }

    public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //获取手机触摸的坐标
        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastx = x;
                lasty = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //计算移动距离
                int offerx = x - lastx;
                int offery = y - lasty;
                offsetLeftAndRight(offerx);
                offsetTopAndBottom(offery);
                break;
        }
        return true;
    }

    //系统会在绘制View的时候在draw()方法中调用该方法
    @Override
    public void computeScroll() {
        super.computeScroll();
        if (scroller.computeScrollOffset()){
            ((View)getParent()).scrollTo(scroller.getCurrX(),scroller.getCurrY());
            invalidate();
        }
    }

    public void smoothScrollTo(int destx,int desty){
        int scrollx = getScrollX();
        int deltax =destx -  scrollx;
        int scrolly = getScrollY();
        int deltay =desty -  scrolly;
        scroller.startScroll(scrollx,scrolly,deltax,deltay,2000);
    }
}

在布局中引用改控件,然后代码中执行移动方法,实现移动效果

customView.smoothScrollTo(-400,-200)

属性动画

1.ObjectAnimator
ObjectAnimator 是属性动画最重要的类,内部的工作机制是通过寻找特定属性的get和set方法,然后通过方法不断地对值进行改变,从而实现动画效果的,有好多属性值,不同的值,执行不同的方法
• translationX和translationY:用来沿着X轴或者Y轴进行平移。
• rotation、rotationX、rotationY:用来围绕View的支点进行旋转。
• PrivotX和PrivotY:控制View对象的支点位置,围绕这个支点进行旋转和缩放变换处理。默认该支点 位置就是View对象的中心点。
• alpha:透明度,默认是1(不透明),0代表完全透明。
• scaleX scaleY:沿X Y轴缩放

        //透明动画
        var objectAnimator = ObjectAnimator.ofFloat(tv_animator,"alpha",1f,0f,1f)
        objectAnimator.duration = 2000
        objectAnimator.start()

        //平移动画-X
        var objectAnimator1 = ObjectAnimator.ofFloat(tv_animator,"translationX",200f)
        objectAnimator1.duration = 2000
        objectAnimator1.start()

2.ValueAnimator
ValueAnimator不提供任何动画效果,它更像一个数值发生器,用来产生有一定规律的数字,从而让调 用者控制动画的实现过程。通常情况下,在ValueAnimator的AnimatorUpdateListener中监听数值的变化,从 而完成动画的变换

     var valueAnimator = ValueAnimator.ofFloat(0f,100f)
        valueAnimator.setTarget(tv_animator1)
        valueAnimator.duration = 1000
        valueAnimator.start()
        valueAnimator.addUpdateListener {
            val  float = it.getAnimatedValue()
            Log.e("---->" ,""+float)
        }

3.动画的监听
完整的动画具有start、Repeat、End、Cancel这4个过程

 var objectAnimator2 = ObjectAnimator.ofFloat(btn_animator,"translationY",200f)
        objectAnimator2.duration = 2000
        objectAnimator2.addListener(object : Animator.AnimatorListener {
            override fun onAnimationStart(animation: Animator) {
                Log.e("---->","动画执行开始")
            }

            override fun onAnimationEnd(animation: Animator) {
				//大部分情况下,我们都要监听的是这个,在动画结束后,执行什么操作
                Log.e("---->","动画执行结束")
            }

            override fun onAnimationCancel(animation: Animator) {
                Log.e("---->","动画执行取消")
            }

            override fun onAnimationRepeat(animation: Animator) {

            }
        })
        objectAnimator2.start()

4.组合动画——AnimatorSet
Builder 类采用了建造者模式,每次调用方法时都返回 Builder 自身用于继续构建。 AnimatorSet.Builder中包括以下4个方法。
• after(Animator anim):将现有动画插入到传入的动画之后执行。
• after(long delay):将现有动画延迟指定毫秒后执行。
• before(Animator anim):将现有动画插入到传入的动画之前执行。
• with(Animator anim):将现有动画和传入的动画同时执行。
AnimatorSet正是通过这几种方法来控制动画播放顺序的。

        val  objectAnimator3 = ObjectAnimator.ofFloat(tv_animator2,"translationX",0f,200f,0f)
        val  objectAnimator4 = ObjectAnimator.ofFloat(tv_animator2,"scaleX",1.0f,2.0f,1.0f)
        val  objectAnimator5 = ObjectAnimator.ofFloat(tv_animator2,"rotationX",0f,90f,0f)
        val animatorSet = AnimatorSet()
        animatorSet.duration = 1000
        //设定执行顺序
        animatorSet.play(objectAnimator3).with(objectAnimator4).after(objectAnimator5)
        animatorSet.start()

5.组合动画——PropertyValuesHolder

      val propertyValuesHolder1 = PropertyValuesHolder.ofFloat("scaleX",1f,1.5f)
        val propertyValuesHolder2 = PropertyValuesHolder.ofFloat("rotationX",1f,90f,0f)
        val propertyValuesHolder3 = PropertyValuesHolder.ofFloat("alpha",1f,0.3f,1f)
        val  objectAnimator6 = ObjectAnimator.ofPropertyValuesHolder(tv_animator3,propertyValuesHolder1,propertyValuesHolder2,propertyValuesHolder3)
        objectAnimator6.setDuration(1000).start()

6.在XML中使用属性动画
在res文件中新建animator文件,在里面新建一个 scale.xml

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:duration="3000"
    android:propertyName="scaleX"
    android:valueFrom="1.0"
    android:valueTo="2.0"
    android:valueType="floatType">

</objectAnimator>
        val animator = AnimatorInflater.loadAnimator(this,R.animator.scale)
        animator.setTarget(tv_animator4)
        animator.start()
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值