View的滑动和属性动画

Android 自定义View:实现View的滑动效果 讲解了View的触摸事件,已经实现View滑动的7种方式 阅读详情

Android、View视图与坐标系
View的滑动和属性动画
从源码解析View的事件分发机制
View的工作流程
Android自定义view

View的滑动

  View的滑动是Android实现自定义控件的基础,同时在开发中我们也难免会遇到View的滑动处理。其实不管是哪种滑动方式,其基本思想都是类似的:当点击事件传到View时,系统记下触摸点的坐标,手指移动时系统记下移动后触摸的坐标并算出偏移量,并通过偏移量来修改View的坐标。实现View滑动有很多种方法,在这里主要讲解6种滑动方法,分别是layout()、offsetLeftAndRight()与offsetTopAndBottom()、LayoutParams、动画、scollTo 与 scollBy,以及Scroller。

layout()方法

  View进行绘制的时候会调用onLayout()方法来设置显示的位置,因此我们同样也可以通过修改View的left、top、right、bottom这4种属性来控制View的坐标。首先我们要自定义一个View,在onTouchEvent()方法中获取触摸点的坐标,代码如下所示:

 public boolean onTouchEvent(MotionEvent event) {
        //获取手指触摸点的横坐标和纵坐标
        int  x =(int) event.getX();
        int  y =(int) event.getY();
         switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                lastX = x;
                lastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                //计算移动的距离
                int offsetX = x - lastX;
                int offsetY = y - lastY;
                //调用layout方法来重新放置它的位置
                layout(getLeft() + offsetX, getTop() + offsetY,
                        getRight() + offsetX, getBottom() + offsetY);
                break;    
     ...

offsetLeftAndRight() 与 offsetTopAndBottom()

  这两种方法和layout()方法的效果差不多,其使用方式也差不多。我们将ACTION_MOVE中的代码替换成如下代码:

 case MotionEvent.ACTION_MOVE:
        //计算移动的距离
        int offsetX = x - lastX;
        int offsetY = y - lastY;
        //对 left 和 right 进行偏移
        offsetLeftAndRight(offsetX);
        //对 top 和 bottom 进行偏移
        offsetTopAndBottom(offsetY);
        break;   

LayoutParams(改变布局参数)

  LayoutParams主要保存了一个View的布局参数,因此我们可以通过LayoutParams来改变View的布局参数从而达到改变View位置的效果。同样,我们将ACTION_MOVE中的代码替换成如下代码:

LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)getLayoutParams();
    layoutParams.leftMargin = getLeft() + offsetX;
    layoutParams.topMargin = getBottom() + offsetY;
    setLayoutParams(layoutParams);

  因为父控件是 LinearLayout,所以我们用了LinearLayout.LayoutParams。如果父控件是RelativeLayout,则要使用RelativeLayout.LayoutParams。除了使用布局的LayoutParams外,我们还可以用ViewGroup.MarginLayoutParams来实现:

ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams)getLayoutParams();
    layoutParams.leftMargin = getLeft() + offsetX;
    layoutParams.topMargin = getBottom() + offsetY;
    setLayoutParams(layoutParams);

scrollTo与scollBy

  scrollTo(x,y)表示移动到一个具体的坐标点,而 scrollBy(dx,dy)则表示移动的增量为dx、dy。其中,scollBy最终也是要调用scollTo的。View.java的scollBy和scollTo的源码如下所示:

public void scrollTo(int x, int y) {
    if (mScrollX != x || mScrollY != y) {
        int oldX = mScrollX;
        int oldY = mScrollY;
        mScrollX = x;
        mScrollY = y;
        invalidateParentCaches();
        onScrollChanged(mScrollX, mScrollY, oldX, oldY);
        if (!awakenScrollBars()) {
              postInvalidateOnAnimation();
        }
    }
}

public void scrollBy(int x, int y) {
    scrollTo(mScrollX + x, mScrollY + y);
}

  scollTo、scollBy移动的是View的内容,如果在ViewGroup中使用,则是移动其所有的子View。我们将ACTION_MOVE中的代码替换成如下代码:

((View) getParent()).scrollBy(-offsetX,-offsetY);

  这里若要实现CustomView随手指移动的效果,就需要将偏移量设置为负值。为什么要设置为负值呢?下面具体讲解一下。假设我们正用放大镜来看报纸,放大镜用来显示字的内容。同样我们可以把放大镜看作我们的手机屏幕,它们都是负责显示内容的;而报纸则可以被看作屏幕下的画布,它们都是用来提供内容的。放大镜外的内容,也就是报纸的内容不会随着放大镜的移动而消失,它一直存在。同样,我们的手机屏幕看不到的视图并不代表其不存在,如图1所示。画布上有3个控件,即Button、EditText和SwichButton。只有Button在手机屏幕中显示,它的Android坐标为(60,60)。现在我们调用scrollBy(50,50),按照字面的意思,这个Button应该会在屏幕右下侧,可是事实并非如此。如果我们调用scrollBy(50,50),里面的参数都是正值,我们的手机屏幕向 X轴正方向,也就是向右边平移50,然后手机屏幕向Y轴正方向,也就是向下方平移 50,平移后的效果如图2所示。虽然我们设置的数值是正数并且在X轴和Y轴的正方向移动,但Button却向相反方向移动了,这是参考对象不同导致的差异。所以我们用scrollBy方法的时候要设置负数才会达到自己想要的效果。
image

图1

image
图2

Scroller

  我们在用scollTo/scollBy方法进行滑动时,这个过程是瞬间完成的,所以用户体验不大好。这里我们可以使用Scroller来实现有过渡效果的滑动,这个过程不是瞬间完成的,而是在一定的时间间隔内完成的。Scroller本身是不能实现View的滑动的,它需要与View的computeScroll()方法配合才能实现弹性滑动的效
果。在这里我们实现CustomView平滑地向右移动。首先我们要初始化Scroller,接下来重写computeScroll()方法,系统会在绘制View的时候在draw()方法中调用该方法。在这个方法中,我们调用父类的scrollTo()方法并通过Scroller来不断获取当前的滚动值,每滑动一小段距离我们就调用invalidate()方法不断地进行重绘,重绘就会调用computeScroll()方法,这样我们通过不断地移动一个小的距离并连贯起来就实现了平滑移动的效果。,代码如下所示:

    private Scroller mScroller;

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

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (mScroller.computeScrollOffset()) {
            ((View) getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            invalidate();
        }
    }

    public void smoothScrollTo(int destX, int destY) {
        int scrollX = getScrollX();
        int delta = destX - scrollX;
        mScroller.startScroll(scrollX, 0, delta, 0, 2000);
        invalidate();
    }

  我们在CustomView中写一个smoothScrollTo方法,调用Scroller的startScroll()方法,在2000ms内沿X轴平移delta像素,最后调用CustomView的smoothScrollTo()方法。这里我们设定CustomView沿着X轴向右平移400像素。

mCustomView.smoothScrollTo(-400,0);

解析Scroller

  上面介绍了如何使用Scroller进行滑动,但是其使用流程和一般的类的使用方式稍有不同。为了更好地理解Scroller的使用流程,我们有必要学习一下Scroller的源码。要想使用Scroller,必须先调用new Scroller()。下面先来看看Scroller的构造方法,代码如下所示:

    public Scroller(Context context) {
        this(context, null);
    }
    
    public Scroller(Context context, Interpolator interpolator) {
        this(context, interpolator,
        context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB);
    }
    
    public Scroller(Context context, Interpolator interpolator, boolean flywheel) {
        mFinished = true;
        if (interpolator == null) {
            mInterpolator = new ViscousFluidInterpolator();
        } else {
            mInterpolator = interpolator;
        }
        mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
        mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
        mFlywheel = flywheel;

        mPhysicalCoeff = computeDeceleration(0.84f); // look and feel tuning
    }    

  从上面的代码我们得知,Scroller有三个构造方法,通常情况下我们都用第一个;第二个需要传进去一个插值器Interpolator,如果不传则采用默认的插值器ViscousFluidInterpolator。接下来看看Scroller的startScroll()方法,代码如下所示:

    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        mMode = SCROLL_MODE;
        mFinished = false;
        mDuration = duration;
        mStartTime = AnimationUtils.currentAnimationTimeMillis();
        mStartX = startX;
        mStartY = startY;
        mFinalX = startX + dx;
        mFinalY = startY + dy;
        mDeltaX = dx;
        mDeltaY = dy;
        mDurationReciprocal = 1.0f / (float) mDuration;
    }

  在startScroll()方法中并没有调用类似开启滑动的方法,而是保存了传进来的各种参数:startX和startY表示滑动开始的起点,dx和dy表示滑动的距离,duration则表示滑动持续的时间。所以startScroll()方法只是用来做前期准备的,并不能使View进行滑动。关键是我们在startScroll()方法后调用了invalidate()方法,这个方法会导致View的重绘,而View的重绘会调用View的draw()方法,draw()方法又会调用View的computeScroll()方法。我们重写computeScroll()方法如下:

    public void smoothScrollTo(int destX, int destY) {
        int scrollX = getScrollX();
        int delta = destX - scrollX;
        mScroller.startScroll(scrollX, 0, delta, 0, 2000);
        invalidate();
    }

  我们在computeScroll()方法中通过Scroller来获取当前的ScrollX和ScrollY,然后调用scrollTo()方法进行View的滑动,接着调用invalidate方法来让View进行重绘,重绘就会调用computeScroll()方法来实现View的滑动。这样通过不断地移动一个小的距离并连贯起来就实现了平滑移动的效果。但是在Scroller中如何获取当前位置的ScrollX和ScrollY呢?我们忘了一点,那就是在调用scrollTo()方法前会调用Scroller的computeScrollOffset()方法。接下来看看computeScrollOffset()方法:

    public boolean computeScrollOffset() {
        if (mFinished) {
            return false;
        }

        int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
    
        if (timePassed < mDuration) {
            switch (mMode) {
            case SCROLL_MODE:
                final float x = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
                mCurrX = mStartX + Math.round(x * mDeltaX);
                mCurrY = mStartY + Math.round(x * mDeltaY);
                break;
            case FLING_MODE:
                final float t = (float) timePassed / mDuration;
                final int index = (int) (NB_SAMPLES * t);
                float distanceCoef = 1.f;
                float velocityCoef = 0.f;
                if (index < NB_SAMPLES) {
                    final float t_inf = (float) index / NB_SAMPLES;
                    final float t_sup = (float) (index + 1) / NB_SAMPLES;
                    final float d_inf = SPLINE_POSITION[index];
                    final float d_sup = SPLINE_POSITION[index + 1];
                    velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
                    distanceCoef = d_inf + (t - t_inf) * velocityCoef;
                }

                mCurrVelocity = velocityCoef * mDistance / mDuration * 1000.0f;
                
                mCurrX = mStartX + Math.round(distanceCoef * (mFinalX - mStartX));
                // Pin to mMinX <= mCurrX <= mMaxX
                mCurrX = Math.min(mCurrX, mMaxX);
                mCurrX = Math.max(mCurrX, mMinX);
                
                mCurrY = mStartY + Math.round(distanceCoef * (mFinalY - mStartY));
                // Pin to mMinY <= mCurrY <= mMaxY
                mCurrY = Math.min(mCurrY, mMaxY);
                mCurrY = Math.max(mCurrY, mMinY);

                if (mCurrX == mFinalX && mCurrY == mFinalY) {
                    mFinished = true;
                }

                break;
            }
        }
        else {
            mCurrX = mFinalX;
            mCurrY = mFinalY;
            mFinished = true;
        }
        return true;
    }

  首先会计算动画持续的时间timePassed。如果动画持续时间小于我们设置的滑动持续时间mDuration,则执行Switch语句。因为在startScroll()方法中的mMode值为SCROLL_MODE,所以执行分支语句SCROLL_MODE,然后根据插值器Interpolator来计算出在该时间段内移动的距离,赋值给mCurrX和mCurrY,这样我们就能通过Scroller来获取当前的ScrollX和ScrollY了。另外,computeScrollOffset()的返回值如果为true则表示滑动未结束,为false则表示滑动结束。所以,如果滑动未结束,我们就得持续调用
scrollTo()方法和invalidate()方法来进行View的滑动。讲到这里总结一下Scroller的原理:Scroller并不能直接实现View的滑动,它需要配合View的computeScroll()方法。在computeScroll()中不断让View进行重绘,每次重绘都会计算滑动持续的时间,根据这个持续时间就能算出这次View滑动的位置,我们根据每次滑动的位置调用scrollTo()方法进行滑动,这样不断地重复上述过程就形成了弹性滑动。

属性动画

  View 动画提供了AlphaAnimation、RotateAnimation、TranslateAnimation、ScaleAnimation这4种动画方式,并提供了AnimationSet动画集合来混合使用多种动画。随着Android3.0属性动画的推出,View动画不再风光。相比属性动画,View动画一个非常大的缺陷突显,其不具有交互性。当某个元素发生View动画后,其响应事件的位置依然在动画进行前的地方,所以View动画只能做普通的动画效果,要避免涉及交互操作。但是它的优点也非常明显:效率比较高,使用也方便。由于 Android 3.0之前已有的动画框架Animation存在一些局限性,也就是动画改变的只是显示,但View的位置没有发生变化,View移动后并不能响应事件。在Animator框架中使用最多的就是AnimatorSet和ObjectAnimator配合:使用 ObjectAnimator进行更精细化的控制,控制一个对象和一个属性值,而使用多个ObjectAnimator组合到AnimatorSet形成一个动画。属性动画通过调用属性get、set方法来真实地控制一个View的属性值,因此,强大的属性动画框架基本可以实现所有的动画效果。

ObjectAnimator

  ObjectAnimator 是属性动画最重要的类,创建一个 ObjectAnimator 只需通过其静态工厂类直接返还一个ObjectAnimator对象。参数包括一个对象和对象的属性名字,但这个属性必须有get和set方法,其内部会通过Java反射机制来调用set方法修改对象的属性值。下面看看平移动画是如何实现的,代码如下所示:

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "translationX", 200);
objectAnimator.setDuration(300);
objectAnimator.start();

  通过ObjectAnimator的静态方法,创建一个ObjectAnimator对象,查看ObjectAnimator.java的静态方法ofFloat(),代码如下所示:

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
        anim.setFloatValues(values);
        return anim;
}

  从源码可以看出第一个参数是要操作的Object;第二个参数是要操作的属性;最后一个参数是一个可变的float类型数组,需要传进去该属性变化的取值过程,这里设置了一个参数,变化到200。与View动画一样,也可以给属性动画设置显示时长、插值器等属性。下面就是一些常用的可以直接使用的属性动画的属性值。

  • translationX和translationY:用来沿着X轴或者Y轴进行平移。
  • rotation、rotationX、rotationY:用来围绕View的支点进行旋转。
  • PrivotX和PrivotY:控制View对象的支点位置,围绕这个支点进行旋转和缩放变换处理。默认该支点位置就是View对象的中心点。
  • alpha:透明度,默认是1(不透明),0代表完全透明。
  • x和y:描述View对象在其容器中的最终位置。

  需要注意的是,在使用ObjectAnimator的时候,要操作的属性必须要有get和set方法,不然ObjectAnimator就无法生效。如果一个属性没有get、set方法,也可以通过自定义一个属性类或包装类来间接地给这个属性增加get和set方法。现在来看看如何通过包装类的方法给一个属性增加get和set方法,代码如下所示:

private static class MyView {
    private View mTarget;

    public MyView(View mTarget) {
        this.mTarget = mTarget;
    }

    public int getWidth(){
        return mTarget.getLayoutParams().width;
    } 
        
    public void setWidth(int width){
        mTarget.getLayoutParams().width = width;
        mTarget.requestLayout();
    }
}

使用时只需要操作包类就可以调用get、set方法了:

MyView myView = new MyVIew(mButton);
ObjectAnimator.ofFloat(myView, "width", 500).setDuration(500).start();

ValueAnimator

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

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,100);
valueAnimator.setTarget(view);
valueAnimator.setDuration(1000).start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        Float f = (Float) animation.getAnimatedValue();
    }
});

动画的监听

完整的动画具有start、Repeat、End、Cancel这4个过程,代码如下所示:

ObjectAnimator animator = ObjectAnimator.ofFloat(view,"alpha",1.5f);
animator.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationCancel(Animator animation) {
        super.onAnimationCancel(animation);
    }

    @Override
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation);
    }
    @Override
    public void onAnimationRepeat(Animator animation) {
        super.onAnimationRepeat(animation);
    }

    @Override
    public void onAnimationStart(Animator animation) {
        super.onAnimationStart(animation);
    }
});

  大部分时候我们只关心 onAnimationEnd 事件,Android 也提供了 AnimatorListenterAdaper来让我们选择必要的事件进行监听。

组合动画——AnimatorSet

  AnimatorSet 类提供了一个 play()方法,如果我们向这个方法中传入一个 Animator 对象(ValueAnimator或ObjectAnimator),将会返回一个AnimatorSet.Builder的实例。AnimatorSet的play()方法源码如下所示:

public Builder play(Animator anim) {
    if (anim != null) {
       return new Builder(anim);
    }
    return null;
}

  很明显,在play()方法中创建了一个AnimatorSet.Builder类,这个Builder类是AnimatorSet的内部类。
我们来看看这个Builder类中有什么,代码如下所示:

    public class Builder {

        private Node mCurrentNode;

        Builder(Animator anim) {
            mDependencyDirty = true;
            mCurrentNode = getNodeForAnimation(anim);
        }

        public Builder with(Animator anim) {
            Node node = getNodeForAnimation(anim);
            mCurrentNode.addSibling(node);
            return this;
        }

        public Builder before(Animator anim) {
            Node node = getNodeForAnimation(anim);
            mCurrentNode.addChild(node);
            return this;
        }

        public Builder after(Animator anim) {
            Node node = getNodeForAnimation(anim);
            mCurrentNode.addParent(node);
            return this;
        }

        public Builder after(long delay) {
            // setup dummy ValueAnimator just to run the clock
            ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
            anim.setDuration(delay);
            after(anim);
            return this;
        }
    }

  从源码中可以看出,Builder类采用了建造者模式,每次调用方法时都返回 Builder 自身用于继续构建。AnimatorSet.Builder中包括以下4个方法。

  • after(Animator anim):将现有动画插入到传入的动画之后执行。
  • after(long delay):将现有动画延迟指定毫秒后执行。
  • before(Animator anim):将现有动画插入到传入的动画之前执行。
  • with(Animator anim):将现有动画和传入的动画同时执行。

  AnimatorSet正是通过这几种方法来控制动画播放顺序的。很多读者可能还是一头雾水,这里再举一个例子,代码如下所示:

 ObjectAnimator animator1 = ObjectAnimator.ofFloat(view,"translationX",0,200f,0);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(view,"scaleX",1f,2f);
        ObjectAnimator animator3 = ObjectAnimator.ofFloat(view,"rotationX",0,90f,0);
        AnimatorSet set = new AnimatorSet();
        set.setDuration(1000);
        set.play(animator1).with(animator2).after(animator3);

  首先我们创建3个ObjectAnimator,分别是animator1、animator2和animator3,然后创建AnimatorSet。在
这里先执行 animator3,然后同时执行 animator1 和 animator2(也可以调用set.playTogether(animator1,
animator2);来使这两种动画同时执行)。

以上内容摘自《Android进阶之光》

View滑动动画的选择及其left, marginLeft, translationX参数的总结 最近由于项目需要,做一个比较复杂的3D动画,核心就是根据手指的滑动来翻转3D效果。因此,又回顾了一下view滑动效果,而且根据不同的方式实现了一下,发现其中很多参数容易搞混,比如改变view的left,marginLeft,translationX中的任意一个值,对另外2个值及其getX是否有影响,因此,做了一下实验,发现挺有意思,结果如下:从上面的数据来看,这几个view的参数之间的值相互之间不影 阅读详情

相关推荐

Android View 的尺寸大小变化的时候要求有一个过度的动画

最近在项目里有个需求要求一个View 的尺寸大小变化的时候要求有一个过度的动画(view.getLayoutParams().height 100--->400)查看了一些资料后成功搞定,下面跟大家一起分享 解决的方法主要是继承Animation重写里面的几个方法,成功搞定

android 动画遮挡_Android使用LayoutParams属性进行左右侧滑动画

Activity的布局:Aty代码:Java1234567891011121314151617181920212223242526272829303132333435363738/*** 布局属性动画测试 * 本aty的布局最外层时RelativeLayout* bottom是个LinearLayout,和动画的实现没多大关系* top层是自定义的LinearLayout布局,重写onTo...

weixin_42523670的博客 502

详解Android Scroller与computeScroll的调用机制关系

主要介绍了详解Android Scroller与computeScroll的调用机制关系的相关资料,需要的朋友可以参考下

Android 属性动画使用(一)

首先扯点别的:感觉自己好久没有用笔写过字了,下午去超市每个小本子,写写诗,练练字,陶冶一下情操,也不能有事没事就喝酒。今天记录一下自己学习属性动画的过程,是看着郭霖大神的博客,链接会在文章末尾贴出。1 ValueAnimator ValueAnimator 。给它一个初始值和结束值,以及动画的时间,ValueAnimator 会自动计算在动画时间内如何从初始值过渡到结束值。 1.使用场景1:

leilifengxingmw的博客 1049

如何优雅地进行频谱分析—— 一行代码实现绘制MATLAB频谱、功率谱图

之前的文章里讲了关于信号频谱、能量谱的相关理论和MATLAB编程实现方法: Mr.看海:信号频域分析方法的理解(频谱、能量谱、功率谱、倒频谱、小波分析) Mr.看海:频域特征值提取的MATLAB代码实现(频谱、功率谱、倒频谱) 不过对于刚刚开始进行这方面研究,或者对MATLAB不甚熟悉,抑或者不想花太多时间用在编程这件事上的同学,目前缺少一种足够便捷、高效、可靠的代码。 所以笔者想做这样一件事:编写一个函数,同学们只需要导入自己要分析的数据,并按照自己的需求设置部分选项,调用一行代码就可以实现绘制频

fengzhuqiaoqiu的博客 2万+

UDS(三)网络层时间参数

网络层定义了N_Ar、N_As、N_Br、N_Bs、N_Cr、N_Cs六个时间参数。 网络层在检测到错误的时间传递至上层使用者 1.当N_As 超时时,即发送方没有及时发送出N_PDU,系统将放弃信息的接收并传递<N_Result> = <N_TIMEOUT_A>的N_USData.comfirm指示 2.当N_Ar超时时,即接收方没有及时发送出N_PDU,系统将放弃信息的接收并传递<N_Result> = <N_TIMEOUT_A>的N_USData.co

weixin_44522306的博客 1万+

属性动画ValueAnimator在自定义View中的使用

功能强大的属性动画(property animation)最近在学习有关自定义View的内容,在Github上看到好多开源的View控件,如果涉及动画,基本上都使用的是属性动画,真心觉得属性动画比以前的补间动画强大太多了,也学习到了使用属性动画自定义View的方便和强大。所以想记录一下在自定义View时,使用属性动画的几个方面。属性动画的强大之处在于可以对任意对象的任意属性增加动画效果,并且可以自...

XiaoMu_Mu的博客 446

【全网最新】使用 1panel面板 部署若依系统( springboot 和 vue)项目

打开前端项目的vue.config.js文件,检查devServer下的proxy代理部分,然后将下面这个端口修改为你要在打包后访问的端口,即使用nginx代理前的接口。这个端口默认是80端口,这里把其修改为不会冲突的8010端口,后台接口的地址配置为9080,不过感觉这里设置的8010和9080可能没有用,因为部署前端静态页面是,也配置了一次网页的外部接口和api的接口,后期有空了再验证。打开右侧的Maven,点击:生存期->package,然后点击运行,等待打包成功,包在如图所示的文件夹中。

老薛的专栏 1757

【Android开发】 View的属性动画

View的属性动画 在许多的场景中,我们可能不只需要简单的移动,旋转,透明,变大缩小等等,我们需要加入持续的时间,定格的时间,多种组合特效等等,于是我们需要使用 Android 的动画能力。在早期的 Android 中,只有帧动画和 View 动画。View 动画提供了 AlphaAnimation、 TranslateAnimation、 RotateAnimation 和ScaleAnimation 这4种动画方式。但他们不具有交互性,即当某个元素发生 View 动画之后,其响应事件的位置依然在动画进行

HelloWorled的博客 443

AFE芯片做什么用的?AFE(Analog Front End) 模拟前端

AFE采样精度的影响因素非常多,需要综合考虑各种因素,并根据实际应用场景来选择合适的参数和方法。通过减少噪声、提高采样频率、调节放大器增益、降低电源噪声、优化传输线路、进行温度补偿、选择合适的ADC分辨率、根据信号类型选择合适的AFE参数、进行器件匹配和校准等方法,可以提高AFE的采样精度,从而更好地满足各种应用需求。版权声明:本文为优快云博主「czf.Forver」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

学海无涯的专栏 4万+

现代密码学5.3--Hash and MAC

现代密码学5.3--Hash and MAC 博主正在学习INTRODUCTION TO MODERN CRYPTOGRAPHY (Second Edition) --Jonathan Katz, Yehuda Lindell,做一些笔记供自己回忆,如有错误请指正。整理成一个系列现代密码学,方便检索。 第二章定义了完美安全及其对应的密码方案“一次一密”, 第三章介绍了多种安全定义 3.1-3.3 计算安全,PRG和基于PRG构造的满足计算安全的密码方案; 3.4-3.5 CPA安全,PRF和基于PRF构

qq_41545715的博客 686

View绘制总结--View结合Scroller实现平滑移动(computeScroll())

适用范围:        当View或者ViewGroup中的内容超过一个屏幕时,我们必须要通过滑动的方式使得用户可以查看那些超过屏幕的内容,如果 直接调用ScrollTo()或者ScrollBy()的方式来移动的话会让用户觉得太突然而且效果不好看,这时候就可以使用Scroller来实现平滑移动。 Scroller的本质及作用:        Scroller本质就是一个Helper类,里

BrianLee的专栏 2478

LabVIEW调用.so文件的方法

LabVIEW调用.so文件的方法

m0_37878912的博客 3025

Android 实现View滑动的几种方式

View本身的scrollTo/scrollBy方法 /** * Set the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be * invalidated. ...

JoeLittleStar的专栏 431

基于强化学习控制策略的三相逆变器仿真

强化学习控制器的核心在于定义状态空间、动作空间、奖励函数以及选择合适的强化学习算法(例如DQN、DDPG等)。对于三相逆变器,状态可以是输出电压、电流等信息;动作则可能是调制指数的变化量;奖励函数则应鼓励快速准确地跟踪参考信号。定义状态空间和动作空间状态空间可以包括逆变器的输出电压、电流及其变化率等信息。动作空间则是控制器可执行的动作,例如PWM信号的调整幅度。matlab深色版本% 定义状态和动作空间维度numObs = 6;% 假设有六个状态变量(例如三相电压和电流)

amy_mhd的博客 136

R语言单因素被试内ANOVA检验

在R语言中,我们可以使用多种方法进行被试内ANOVA检验,其中包括使用内建函数或使用外部包。我们随机选择了10个被试,并对每个被试使用了三种不同的药物处理。通过上述代码示例,我们可以使用R语言进行单因素被试内ANOVA检验。假设我们的数据存储在一个名为"data"的数据框中,其中包含两个列:一个列是被试的编号,另一个列是生物指标的测量值。在上述代码中,我们创建了一个名为"data"的数据框,其中"Subject"列包含了被试的编号,"Measurement"列包含了生物指标的测量值。参数指定了数据来源。

PixelNovaO的博客 363

View的滑动实现之三(使用动画,属相动画及延时策略)

前面我们已经介绍了两种View的滑动实现,今天我们介绍另一种滑动方式,即使用动画。通过动画我们能够让一个View进行平移,而平移就是一种动画。使用动画来移动View主要操作的是translateX和translateY属性,既可以使用传统的View动画,也可以采用属性动画。但是,如果使用属性动画的话,为了兼容android3.0以下的版本,需要使用开源动画库nineoldandroids,大家感兴

gongzhiyao37390814的博客 754

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

View事件体系学习(一)滑动

View 的滑动可以通过三种方法来实现: 通过 View 本身提供的 scrollTo / scrollBy 方法来实现。 通过动画给 View 施加平移效果来实现滑动。 通过改变 View 的 LayoutParams 使得 View 重新布局从而实现滑动。 (一) scrollTo / scroll By scrollTo: scrollBy: 丛源码来看,scrol

ribs0714的博客 244

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

android 动态滑动效果怎么做,Android实现View滑动效果的6种方法

本文实例为大家分享了Android实现View滑动效果的具体代码,供大家参考,具体内容如下一、View的滑动简介View的滑动是Android实现自定义控件的基础,同时在开发中我们也难免会遇到View的滑动的处理。其实不管是那种滑动的方式基本思想都是类似的:当触摸事件传到View时,系统记下触摸点的坐标,手指移动时系统记下移动后的触摸的坐标并算出偏移量,并通过偏移量来修改View的坐标。实现Vie...

weixin_33037813的博客 1439

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

View的事件体系_View的基础知识和滑动

一.View的基础知识 View的位置主要是由4个顶点来决定的,分别对应View的4个属性,left,top,right,bottom,其中top是左上角纵坐标,left是左上角横坐标,right是右上角横坐标,bottom是右上角纵坐标,需要注意的是,这些坐标是相对于View的父容器来说的,因此它是一种相对坐标 view的坐标和父容器的关系如下图所示 获取这4个成员变量的方法如下: Left=...

weixin_40877822的博客 197

View体系与自定义View(二)—— View的滑动

当点击事件传到View时,系统会记下触摸点的坐标,手指移动时系统记下移动后触摸的坐标并计算出偏移量,通过偏移量来修改View的坐标。实现View滑动有很多中方法,主要有:layout()、offsetLeftAndRight()与offsetTopAndBottom()、LayoutParams、动画、scrollTo和scrollBy,以及Scroller。 1 layout()方法 View进行绘制的时候会调用onLayout()方法来设置显示的位置,因此可以通过修改View的left、top、righ

xingyu19911016的博客 762

【Android】view的基础知识

的平移滑动效果,是一种较为灵活且常用的方式。这种方法不仅可以控制滑动的距离和方向,还能够调整滑动的速度、加速度等效果,让动画更流畅和自然。是 Android 中的 UI 组件的基类,代表了用户界面上的一个可视元素。LayoutParams用于保存一个view的布局参数,我们可以通过改变view的布局参数来改变位置。可以直接对 View 的属性进行动画操作,是另一种实现弹性滑动效果的方式。是 Android 提供的一个辅助类,用于实现 View 的平滑滑动。的初始位置的偏移量,单位是像素。

Patrick_yuxuan的博客 1322

View 的滑动

View的滑动 主要有三种方式:View本身的srollTo/srollBy,通过动画,通过改变View的LayoutParams重新布局。 1.使用srollTo/srollBy /** * Set the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be * invalidated. .

时代我西的博客 117

android view的width或者height变化的动画,Android View

1.View坐标(1)View的坐标参数主要有哪些?分别有什么要注意的要点?几个主要的坐标参数:1)Left,Right,top,Bottom;他们表示的并非是距离屏幕左上方的绝对值,而是表示view和他的父控件的相对坐标值,并且代表View的初始坐标,在绘制完毕后就不会再改变。2)X和Y表示的是View左上角相对于父控件的坐标值,即实时相对坐标。3)TranslationX,translatio...

weixin_33158756的博客 1722

View与ViewGroup

文章目录1. `View`和`ViewGroup`的关系2. 坐标获取3. View的滑动3.1 案例`layout()`3.2 案例`offsetLeftAndRight & offsetTopAndBottom`3.3 案例`LayoutParams(改变布局参数)`3.4 动画3.4.1 属性动画组合动画 `AnimatorSet``XML`中定制属性动画3.5 `scrollTo`与`scollBy` 1. View和ViewGroup的关系     View是Android所有控件的基类,

梦否 947

View的基础与滑动

View是一种界面层的控件的一种抽象,我们知道的大多数控件都是直接或间接继承自View如等等注意:EditText在compose中并没有相关控件,而是通过TextField来进行组合Android中View本身就可以是单个控件也可以是由多个控件组合成的一组控件如下面。

m0_61130325的博客 680
上一篇: Android、View视图与坐标系
下一篇: 从源码解析View的事件分发机制
「已注销」
博客等级 码龄9年 13粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值