如何在Android中创建幻灯片版式动画? [英] How to create slide layout animation in Android?

查看:172
本文介绍了如何在Android中创建幻灯片版式动画?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好,我想在我的动态创建幻灯片动画一样显示在图片。 当我点击更多按钮橙色布局应该拿出像滑块在白色铺陈,当我点击小于按钮它应该往下走像滑块。

Hi, I want to create a slide animation in My Activity like shown in Images. when I click More button the Orange layout should come up like slider over the white lay out and when I click Less button it should go down like slider.

请建议我任何样品code或任何教程创建这样的方法最好的方法。

please suggest me any sample code or any tutorial for best way to create such an Approach.

谢谢!

推荐答案

使用该面板类这将满足你的要求,你也可以处理该事件。

Use this Panel class this will fulfil your requirement and you can also handle the event.

参考: HTTP://$c$c.google.com / P / Android的MISC-部件/

Panel.java

Panel.java

public class Panel extends LinearLayout {

    /**
     * Callback invoked when the panel is opened/closed.
     */
    public static interface OnPanelListener {
        /**
         * Invoked when the panel becomes fully closed.
         */
        public void onPanelClosed(Panel panel);
        /**
         * Invoked when the panel becomes fully opened.
         */
        public void onPanelOpened(Panel panel);
    }

    private boolean mIsShrinking;
    private int mPosition;
    private int mDuration;
    private boolean mLinearFlying;
    private int mHandleId;
    private int mContentId;
    private View mHandle;
    private View mContent;
    private Drawable mOpenedHandle;
    private Drawable mClosedHandle;
    private float mTrackX;
    private float mTrackY;
    private float mVelocity;

    private OnPanelListener panelListener;

    public static final int TOP = 0;
    public static final int BOTTOM = 1;
    public static final int LEFT = 2;
    public static final int RIGHT = 3;

    private enum State {
        ABOUT_TO_ANIMATE,
        ANIMATING,
        READY,
        TRACKING,
        FLYING,
    };
    private State mState;
    private Interpolator mInterpolator;
    private GestureDetector mGestureDetector;
    private int mContentHeight;
    private int mContentWidth;
    private int mOrientation;
    private float mWeight;
    private PanelOnGestureListener mGestureListener;
    private boolean mBringToFront;

    public Panel(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Panel);
        mDuration = a.getInteger(R.styleable.Panel_animationDuration, 750);     // duration defaults to 750 ms
        mPosition = a.getInteger(R.styleable.Panel_position, BOTTOM);           // position defaults to BOTTOM
        mLinearFlying = a.getBoolean(R.styleable.Panel_linearFlying, false);    // linearFlying defaults to false
        mWeight = a.getFraction(R.styleable.Panel_weight, 0, 1, 0.0f);          // weight defaults to 0.0
        if (mWeight < 0 || mWeight > 1) {
            mWeight = 0.0f;
            //Log.w(TAG, a.getPositionDescription() + ": weight must be > 0 and <= 1");
        }
        mOpenedHandle = a.getDrawable(R.styleable.Panel_openedHandle);
        mClosedHandle = a.getDrawable(R.styleable.Panel_closedHandle);

        RuntimeException e = null;
        mHandleId = a.getResourceId(R.styleable.Panel_handle, 0);
        if (mHandleId == 0) {
            e = new IllegalArgumentException(a.getPositionDescription() + 
                    ": The handle attribute is required and must refer to a valid child.");
        }
        mContentId = a.getResourceId(R.styleable.Panel_content, 0);
        if (mContentId == 0) {
            e = new IllegalArgumentException(a.getPositionDescription() + 
                    ": The content attribute is required and must refer to a valid child.");
        }
        a.recycle();

        if (e != null) {
            throw e;
        }
        mOrientation = (mPosition == TOP || mPosition == BOTTOM)? VERTICAL : HORIZONTAL;
        setOrientation(mOrientation);
        mState = State.READY;
        mGestureListener = new PanelOnGestureListener();
        mGestureDetector = new GestureDetector(mGestureListener);
        mGestureDetector.setIsLongpressEnabled(false);

        // i DON'T really know why i need this...
        setBaselineAligned(false);
    }

    /**
     * Sets the listener that receives a notification when the panel becomes open/close.
     *
     * @param onPanelListener The listener to be notified when the panel is opened/closed.
     */
    public void setOnPanelListener(OnPanelListener onPanelListener) {
        panelListener = onPanelListener;
    }

    /**
     * Gets Panel's mHandle
     * 
     * @return Panel's mHandle
     */
    public View getHandle() {
        return mHandle;
    }

    /**
     * Gets Panel's mContent
     * 
     * @return Panel's mContent 
     */
    public View getContent() {
        return mContent;
    }


    /**
     * Sets the acceleration curve for panel's animation.
     * 
     * @param i The interpolator which defines the acceleration curve 
     */
    public void setInterpolator(Interpolator i) {
        mInterpolator = i; 
    }

    /**
     * Set the opened state of Panel.
     * 
     * @param open True if Panel is to be opened, false if Panel is to be closed.
     * @param animate True if use animation, false otherwise.
     *
     * @return True if operation was performed, false otherwise.
     * 
     */
    public boolean setOpen(boolean open, boolean animate) {
        if (mState == State.READY && isOpen() ^ open) {
            mIsShrinking = !open;
            if (animate) {
                mState = State.ABOUT_TO_ANIMATE;
                if (!mIsShrinking) {
                    // this could make flicker so we test mState in dispatchDraw()
                    // to see if is equal to ABOUT_TO_ANIMATE
                    mContent.setVisibility(VISIBLE);
                }
                post(startAnimation);
            } else {
                mContent.setVisibility(open? VISIBLE : GONE);
                postProcess();
            }
            return true;
        }
        return false;
    }

    /**
     * Returns the opened status for Panel.
     * 
     * @return True if Panel is opened, false otherwise.
     */
    public boolean isOpen() {
        return mContent.getVisibility() == VISIBLE;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mHandle = findViewById(mHandleId);
        if (mHandle == null) {
            String name = getResources().getResourceEntryName(mHandleId);
            throw new RuntimeException("Your Panel must have a child View whose id attribute is 'R.id." + name + "'");
        }
        mHandle.setOnTouchListener(touchListener);
        mHandle.setOnClickListener(clickListener);

        mContent = findViewById(mContentId);
        if (mContent == null) {
            String name = getResources().getResourceEntryName(mHandleId);
            throw new RuntimeException("Your Panel must have a child View whose id attribute is 'R.id." + name + "'");
        }

        // reposition children
        removeView(mHandle);
        removeView(mContent);
        if (mPosition == TOP || mPosition == LEFT) {
            addView(mContent);
            addView(mHandle);
        } else {
            addView(mHandle);
            addView(mContent);
        }

        if (mClosedHandle != null) {
            mHandle.setBackgroundDrawable(mClosedHandle);
        }
        mContent.setClickable(true);
        mContent.setVisibility(GONE);
        if (mWeight > 0) {
            ViewGroup.LayoutParams params = mContent.getLayoutParams();
            if (mOrientation == VERTICAL) {
                params.height = ViewGroup.LayoutParams.FILL_PARENT;
            } else {
                params.width = ViewGroup.LayoutParams.FILL_PARENT;
            }
            mContent.setLayoutParams(params);
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        ViewParent parent = getParent();
        if (parent != null && parent instanceof FrameLayout) {
            mBringToFront = true;
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mWeight > 0 && mContent.getVisibility() == VISIBLE) {
            View parent = (View) getParent();
            if (parent != null) {
                if (mOrientation == VERTICAL) {
                    heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) (parent.getHeight() * mWeight), MeasureSpec.EXACTLY);
                } else {
                    widthMeasureSpec = MeasureSpec.makeMeasureSpec((int) (parent.getWidth() * mWeight), MeasureSpec.EXACTLY);
                }
            }
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        mContentWidth = mContent.getWidth();
        mContentHeight = mContent.getHeight();
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
//      String name = getResources().getResourceEntryName(getId());
//      //Log.d(TAG, name + " ispatchDraw " + mState);
        // this is why 'mState' was added:
        // avoid flicker before animation start
        if (mState == State.ABOUT_TO_ANIMATE && !mIsShrinking) {
            int delta = mOrientation == VERTICAL? mContentHeight : mContentWidth;
            if (mPosition == LEFT || mPosition == TOP) {
                delta = -delta;
            }
            if (mOrientation == VERTICAL) {
                canvas.translate(0, delta);
            } else {
                canvas.translate(delta, 0);
            }
        }
        if (mState == State.TRACKING || mState == State.FLYING) {
            canvas.translate(mTrackX, mTrackY);
        }
        super.dispatchDraw(canvas);
    }

    private float ensureRange(float v, int min, int max) {
        v = Math.max(v, min);
        v = Math.min(v, max);
        return v;
    }

    OnTouchListener touchListener = new OnTouchListener() {
        int initX;
        int initY;
        boolean setInitialPosition;
        public boolean onTouch(View v, MotionEvent event) {
            if (mState == State.ANIMATING) {
                // we are animating
                return false;
            }
//          //Log.d(TAG, "state: " + mState + " x: " + event.getX() + " y: " + event.getY());
            int action = event.getAction();
            if (action == MotionEvent.ACTION_DOWN) {
                if (mBringToFront) {
                    bringToFront();
                }
                initX = 0;
                initY = 0;
                if (mContent.getVisibility() == GONE) {
                    // since we may not know content dimensions we use factors here
                    if (mOrientation == VERTICAL) {
                        initY = mPosition == TOP? -1 : 1;
                    } else {
                        initX = mPosition == LEFT? -1 : 1;
                    }
                }
                setInitialPosition = true;
            } else {
                if (setInitialPosition) {
                    // now we know content dimensions, so we multiply factors...
                    initX *= mContentWidth;
                    initY *= mContentHeight;
                    // ... and set initial panel's position
                    mGestureListener.setScroll(initX, initY);
                    setInitialPosition = false;
                    // for offsetLocation we have to invert values
                    initX = -initX;
                    initY = -initY;
                }
                // offset every ACTION_MOVE & ACTION_UP event 
                event.offsetLocation(initX, initY);
            }
            if (!mGestureDetector.onTouchEvent(event)) {
                if (action == MotionEvent.ACTION_UP) {
                    // tup up after scrolling
                    post(startAnimation);
                }
            }
            return false;
        }
    };

    OnClickListener clickListener = new OnClickListener() {
        public void onClick(View v) {
            if (mBringToFront) {
                bringToFront();
            }
            if (initChange()) {
                post(startAnimation);
            }
        }
    };

    public boolean initChange() {
        if (mState != State.READY) {
            // we are animating or just about to animate
            return false;
        }
        mState = State.ABOUT_TO_ANIMATE;
        mIsShrinking = mContent.getVisibility() == VISIBLE;
        if (!mIsShrinking) {
            // this could make flicker so we test mState in dispatchDraw()
            // to see if is equal to ABOUT_TO_ANIMATE
            mContent.setVisibility(VISIBLE);
        }
        return true;
    }

    Runnable startAnimation = new Runnable() {
        public void run() {

            callPanListener();

            // this is why we post this Runnable couple of lines above:
            // now its save to use mContent.getHeight() && mContent.getWidth()
            TranslateAnimation animation;
            int fromXDelta = 0, toXDelta = 0, fromYDelta = 0, toYDelta = 0;
            if (mState == State.FLYING) {
                mIsShrinking = (mPosition == TOP || mPosition == LEFT) ^ (mVelocity > 0);
            }
            int calculatedDuration;
            if (mOrientation == VERTICAL) {
                int height = mContentHeight;
                if (!mIsShrinking) {
                    fromYDelta = mPosition == TOP? -height : height;
                } else {
                    toYDelta = mPosition == TOP? -height : height;
                }
                if (mState == State.TRACKING) {
                    if (Math.abs(mTrackY - fromYDelta) < Math.abs(mTrackY - toYDelta)) {
                        mIsShrinking = !mIsShrinking;
                        toYDelta = fromYDelta;
                    }
                    fromYDelta = (int) mTrackY;
                } else
                if (mState == State.FLYING) {
                    fromYDelta = (int) mTrackY;
                }
                // for FLYING events we calculate animation duration based on flying velocity
                // also for very high velocity make sure duration >= 20 ms
                if (mState == State.FLYING && mLinearFlying) {
                    calculatedDuration = (int) (1000 * Math.abs((toYDelta - fromYDelta) / mVelocity));
                    calculatedDuration = Math.max(calculatedDuration, 20);
                } else {
                    calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight;
                }
            } else {
                int width = mContentWidth;
                if (!mIsShrinking) {
                    fromXDelta = mPosition == LEFT? -width : width;
                } else {
                    toXDelta = mPosition == LEFT? -width : width;
                }
                if (mState == State.TRACKING) {
                    if (Math.abs(mTrackX - fromXDelta) < Math.abs(mTrackX - toXDelta)) {
                        mIsShrinking = !mIsShrinking;
                        toXDelta = fromXDelta;
                    }
                    fromXDelta = (int) mTrackX;
                } else
                if (mState == State.FLYING) {
                    fromXDelta = (int) mTrackX;
                }
                // for FLYING events we calculate animation duration based on flying velocity
                // also for very high velocity make sure duration >= 20 ms
                if (mState == State.FLYING && mLinearFlying) {
                    calculatedDuration = (int) (1000 * Math.abs((toXDelta - fromXDelta) / mVelocity));
                    calculatedDuration = Math.max(calculatedDuration, 20);
                } else {
                    calculatedDuration = mDuration * Math.abs(toXDelta - fromXDelta) / mContentWidth;
                }
            }

            mTrackX = mTrackY = 0;
            if (calculatedDuration == 0) {
                mState = State.READY;
                if (mIsShrinking) {
                    mContent.setVisibility(GONE);
                }
                postProcess();
                return;
            }

            animation = new TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);
            animation.setDuration(calculatedDuration);
            if (mState == State.FLYING && mLinearFlying) {
                animation.setInterpolator(new LinearInterpolator());
            } else
            if (mInterpolator != null) {
                animation.setInterpolator(mInterpolator);
            }
            startAnimation(animation);
        }
    };

    @Override
    protected void onAnimationEnd() {
        super.onAnimationEnd();
        mState = State.READY;
        if (mIsShrinking) {
            mContent.setVisibility(GONE);
        }
        postProcess();
    }

    @Override
    protected void onAnimationStart() {
        super.onAnimationStart();
        mState = State.ANIMATING;
    }

    private void postProcess() {
        if (mIsShrinking && mClosedHandle != null) {
            mHandle.setBackgroundDrawable(mClosedHandle);
        } else
        if (!mIsShrinking && mOpenedHandle != null) {
            mHandle.setBackgroundDrawable(mOpenedHandle);
        }
        // invoke listener if any
        callPanListener();
    }
    public void callPanListener()
    {
        if (panelListener != null) {
            if (mIsShrinking) {
                panelListener.onPanelClosed(Panel.this);
            } else {
                panelListener.onPanelOpened(Panel.this);
            }
        }
    }

    class PanelOnGestureListener implements OnGestureListener {
        float scrollY;
        float scrollX;
        public void setScroll(int initScrollX, int initScrollY) {
            scrollX = initScrollX;
            scrollY = initScrollY;
        }
        public boolean onDown(MotionEvent e) {
            scrollX = scrollY = 0;
            callPanListener();
            initChange();
            return true;
        }
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            mState = State.FLYING;
//          velocityX=400;
//          velocityY=400;
            mVelocity = mOrientation == VERTICAL? velocityY : velocityX;
//          mVelocity=400;
            post(startAnimation);
            return true;
        }
        public void onLongPress(MotionEvent e) {
            // not used
        }
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            mState = State.TRACKING;
            float tmpY = 0, tmpX = 0;
            if (mOrientation == VERTICAL) {
                scrollY -= distanceY;
                if (mPosition == TOP) {
                    tmpY = ensureRange(scrollY, -mContentHeight, 0);
                } else  {
                    tmpY = ensureRange(scrollY, 0, mContentHeight);
                }
            } else {
                scrollX -= distanceX;
                if (mPosition == LEFT) {
                    tmpX = ensureRange(scrollX, -mContentWidth, 0);
                } else {
                    tmpX = ensureRange(scrollX, 0, mContentWidth);
                }
            }
            if (tmpX != mTrackX || tmpY != mTrackY) {
                mTrackX = tmpX;
                mTrackY = tmpY;
                invalidate();
            }
            return true;
        }
        public void onShowPress(MotionEvent e) {
            // not used
        }
        public boolean onSingleTapUp(MotionEvent e) {
            // not used
            return false;
        }
    }
}

main.xml中

main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:panel="http://schemas.android.com/apk/res/packagename"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"">

<LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:gravity="center_horizontal" >

        <packagename.Panel
            android:id="@+id/panel_menu"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            panel:animationDuration="1000"
            panel:closedHandle="#0000FF"
            panel:content="@+id/panelContent"
            panel:handle="@+id/panelHandle"
            panel:linearFlying="false"
            panel:openedHandle="#0000FF"
            android:paddingTop="4dip"
            panel:position="bottom" >

            <Button
                android:id="@+id/panelHandle"
                android:layout_width="33dp"
                android:layout_height="33dp"
                android:layout_gravity="center_horizontal"
                android:text="^"
                android:textColor="@android:color/white" />

            <RelativeLayout
                android:id="@+id/panelContent"
                android:layout_width="fill_parent"
                android:layout_height="50dp"
                android:background="#0000FF" >
            </RelativeLayout>
        </packagename.Panel>
</RelativeLayout>

attrs.xml

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="Panel">
        <!-- Defines panel animation duration in ms. -->
        <attr name="animationDuration" format="integer" />
        <!-- Defines panel position on the screen. -->
        <attr name="position">
            <!-- Panel placed at top of the screen. -->
            <enum name="top" value="0" />
            <!-- Panel placed at bottom of the screen. -->
            <enum name="bottom" value="1" />
            <!-- Panel placed at left of the screen. -->
            <enum name="left" value="2" />
            <!-- Panel placed at right of the screen. -->
            <enum name="right" value="3" />
        </attr>
        <!-- Identifier for the child that represents the panel's handle. -->
        <attr name="handle" format="reference" />
        <!-- Identifier for the child that represents the panel's content. -->
        <attr name="content" format="reference" />
        <!-- Defines if flying gesture forces linear interpolator in animation. -->
        <attr name="linearFlying" format="boolean" />
        <!-- Defines size relative to parent (must be in form: nn%p). -->
        <attr name="weight" format="fraction" />
        <!-- Defines opened handle (drawable/color). -->
        <attr name="openedHandle" format="reference|color" />
        <!-- Defines closed handle (drawable/color). -->
        <attr name="closedHandle" format="reference|color" />
    </declare-styleable>

</resources>

要与此发挥你的活动你有

To play with this in your Activity you have

SampleActivity.java

SampleActivity.java

public class SampleActivity extends Activity implements OnPanelListener {

public Panel samplePanel;
  @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.panel_main)_layout;

        samplePanel = (Panel) findViewById(R.id.panel_id);
        samplePanel.setOnPanelListener(this);
        samplePanel.setInterpolator(new ExpoInterpolator(Type.OUT));

     }

     public void onPanelClosed(Panel panel) {}//Interface Listener
     public void onPanelOpened(Panel panel) {}//Interface Listener
}

这篇关于如何在Android中创建幻灯片版式动画?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆