ViewFlipper 实现幻灯片功能

来源:互联网 发布:成都gis软件培训班 编辑:程序博客网 时间:2024/05/20 23:29


ViewFlipper实现幻灯片非常容易,下面我们先来看看代码是怎么实现功能的.

布局也很简单:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <ViewFlipper        android:id="@+id/viewFlipper"        android:layout_width="match_parent"        android:layout_height="match_parent" >    </ViewFlipper></LinearLayout>

就一个ViewFlipper控件就好了. 代码如下:

import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.view.animation.AnimationUtils;import android.widget.ImageView;import android.widget.ImageView.ScaleType;import android.widget.ViewFlipper;import com.example.testdemo.R;public class MainActivity extends Activity implements OnClickListener {private ViewFlipper flipper;private int[] urls = { R.drawable.c, R.drawable.g, R.drawable.h,R.drawable.i, R.drawable.j, R.drawable.k, R.drawable.o };@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);flipper = (ViewFlipper) findViewById(R.id.viewFlipper);flipper.setOnClickListener(this);//启动startSlide();}private void startSlide() {//设置进入动画flipper.setInAnimation(AnimationUtils.loadAnimation(this,R.anim.slide_left_in));//设置退出动画flipper.setOutAnimation(AnimationUtils.loadAnimation(this,R.anim.slide_left_out));addFlipperView();}private void addFlipperView() {for (int i = 0; i < urls.length; i++) {ImageView iv = new ImageView(this);iv.setScaleType(ScaleType.CENTER_INSIDE);iv.setBackgroundResource(urls[i]);flipper.addView(iv);}//开始flipper.startFlipping();//指定从那个位置开始flipper.setDisplayedChild(0);}@Overridepublic void onClick(View v) {//停止幻灯片flipper.stopFlipping();//移除flipper中所有的图片flipper.removeAllViews();}}

这是这么简单,很容易的实现了换灯片功能.看看ViewFlipper源码中它继承了ViewAnimator类,

源码如下:

@RemoteViewpublic class ViewFlipper extends ViewAnimator {    private static final String TAG = "ViewFlipper";    private static final boolean LOGD = false;    private static final int DEFAULT_INTERVAL = 3000;    private int mFlipInterval = DEFAULT_INTERVAL;    private boolean mAutoStart = false;    private boolean mRunning = false;    private boolean mStarted = false;    private boolean mVisible = false;    private boolean mUserPresent = true;    public ViewFlipper(Context context) {        super(context);    }    public ViewFlipper(Context context, AttributeSet attrs) {        super(context, attrs);        TypedArray a = context.obtainStyledAttributes(attrs,                com.android.internal.R.styleable.ViewFlipper);        mFlipInterval = a.getInt(                com.android.internal.R.styleable.ViewFlipper_flipInterval, DEFAULT_INTERVAL);        mAutoStart = a.getBoolean(                com.android.internal.R.styleable.ViewFlipper_autoStart, false);        a.recycle();    }    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {        @Override        public void onReceive(Context context, Intent intent) {            final String action = intent.getAction();            if (Intent.ACTION_SCREEN_OFF.equals(action)) {                mUserPresent = false;                updateRunning();            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {                mUserPresent = true;                updateRunning(false);            }        }    };    @Override    protected void onAttachedToWindow() {        super.onAttachedToWindow();        // Listen for broadcasts related to user-presence        final IntentFilter filter = new IntentFilter();        filter.addAction(Intent.ACTION_SCREEN_OFF);        filter.addAction(Intent.ACTION_USER_PRESENT);        // OK, this is gross but needed. This class is supported by the        // remote views machanism and as a part of that the remote views        // can be inflated by a context for another user without the app        // having interact users permission - just for loading resources.        // For exmaple, when adding widgets from a user profile to the        // home screen. Therefore, we register the receiver as the current        // user not the one the context is for.        getContext().registerReceiverAsUser(mReceiver, android.os.Process.myUserHandle(),                filter, null, mHandler);        if (mAutoStart) {            // Automatically start when requested            startFlipping();        }    }    @Override    protected void onDetachedFromWindow() {        super.onDetachedFromWindow();        mVisible = false;        getContext().unregisterReceiver(mReceiver);        updateRunning();    }    @Override    protected void onWindowVisibilityChanged(int visibility) {        super.onWindowVisibilityChanged(visibility);        mVisible = visibility == VISIBLE;        updateRunning(false);    }    /**     * How long to wait before flipping to the next view     *     * @param milliseconds     *            time in milliseconds     */    @android.view.RemotableViewMethod    public void setFlipInterval(int milliseconds) {        mFlipInterval = milliseconds;    }    /**     * Start a timer to cycle through child views     */    public void startFlipping() {        mStarted = true;        updateRunning();    }    /**     * No more flips     */    public void stopFlipping() {        mStarted = false;        updateRunning();    }    @Override    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {        super.onInitializeAccessibilityEvent(event);        event.setClassName(ViewFlipper.class.getName());    }    @Override    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {        super.onInitializeAccessibilityNodeInfo(info);        info.setClassName(ViewFlipper.class.getName());    }    /**     * Internal method to start or stop dispatching flip {@link Message} based     * on {@link #mRunning} and {@link #mVisible} state.     */    private void updateRunning() {        updateRunning(true);    }    /**     * Internal method to start or stop dispatching flip {@link Message} based     * on {@link #mRunning} and {@link #mVisible} state.     *     * @param flipNow Determines whether or not to execute the animation now, in     *            addition to queuing future flips. If omitted, defaults to     *            true.     */    private void updateRunning(boolean flipNow) {        boolean running = mVisible && mStarted && mUserPresent;        if (running != mRunning) {            if (running) {                showOnly(mWhichChild, flipNow);                Message msg = mHandler.obtainMessage(FLIP_MSG);                mHandler.sendMessageDelayed(msg, mFlipInterval);            } else {                mHandler.removeMessages(FLIP_MSG);            }            mRunning = running;        }        if (LOGD) {            Log.d(TAG, "updateRunning() mVisible=" + mVisible + ", mStarted=" + mStarted                    + ", mUserPresent=" + mUserPresent + ", mRunning=" + mRunning);        }    }    /**     * Returns true if the child views are flipping.     */    public boolean isFlipping() {        return mStarted;    }    /**     * Set if this view automatically calls {@link #startFlipping()} when it     * becomes attached to a window.     */    public void setAutoStart(boolean autoStart) {        mAutoStart = autoStart;    }    /**     * Returns true if this view automatically calls {@link #startFlipping()}     * when it becomes attached to a window.     */    public boolean isAutoStart() {        return mAutoStart;    }    private final int FLIP_MSG = 1;    private final Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            if (msg.what == FLIP_MSG) {                if (mRunning) {                    showNext();                    msg = obtainMessage(FLIP_MSG);                    sendMessageDelayed(msg, mFlipInterval);                }            }        }    };}

源码中我们很清楚的看出ViewFlipper中运用了广播实现了切换的交互,具体功能和设置属性可想而知是在ViewAnimator类中实现的我们来看看ViewAnimator类的源码:

public class ViewAnimator extends FrameLayout {    int mWhichChild = 0;    boolean mFirstTime = true;    boolean mAnimateFirstTime = true;    Animation mInAnimation;    Animation mOutAnimation;    public ViewAnimator(Context context) {        super(context);        initViewAnimator(context, null);    }    public ViewAnimator(Context context, AttributeSet attrs) {        super(context, attrs);        TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.ViewAnimator);        int resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_inAnimation, 0);        if (resource > 0) {            setInAnimation(context, resource);        }        resource = a.getResourceId(com.android.internal.R.styleable.ViewAnimator_outAnimation, 0);        if (resource > 0) {            setOutAnimation(context, resource);        }        boolean flag = a.getBoolean(com.android.internal.R.styleable.ViewAnimator_animateFirstView, true);        setAnimateFirstView(flag);        a.recycle();        initViewAnimator(context, attrs);    }    /**     * Initialize this {@link ViewAnimator}, possibly setting     * {@link #setMeasureAllChildren(boolean)} based on {@link FrameLayout} flags.     */    private void initViewAnimator(Context context, AttributeSet attrs) {        if (attrs == null) {            // For compatibility, always measure children when undefined.            mMeasureAllChildren = true;            return;        }        // For compatibility, default to measure children, but allow XML        // attribute to override.        final TypedArray a = context.obtainStyledAttributes(attrs,                com.android.internal.R.styleable.FrameLayout);        final boolean measureAllChildren = a.getBoolean(                com.android.internal.R.styleable.FrameLayout_measureAllChildren, true);        setMeasureAllChildren(measureAllChildren);        a.recycle();    }    /**     * Sets which child view will be displayed.     *     * @param whichChild the index of the child view to display     */    @android.view.RemotableViewMethod    public void setDisplayedChild(int whichChild) {        mWhichChild = whichChild;        if (whichChild >= getChildCount()) {            mWhichChild = 0;        } else if (whichChild < 0) {            mWhichChild = getChildCount() - 1;        }        boolean hasFocus = getFocusedChild() != null;        // This will clear old focus if we had it        showOnly(mWhichChild);        if (hasFocus) {            // Try to retake focus if we had it            requestFocus(FOCUS_FORWARD);        }    }    /**     * Returns the index of the currently displayed child view.     */    public int getDisplayedChild() {        return mWhichChild;    }    /**     * Manually shows the next child.     */    @android.view.RemotableViewMethod    public void showNext() {        setDisplayedChild(mWhichChild + 1);    }    /**     * Manually shows the previous child.     */    @android.view.RemotableViewMethod    public void showPrevious() {        setDisplayedChild(mWhichChild - 1);    }    /**     * Shows only the specified child. The other displays Views exit the screen,     * optionally with the with the {@link #getOutAnimation() out animation} and     * the specified child enters the screen, optionally with the     * {@link #getInAnimation() in animation}.     *     * @param childIndex The index of the child to be shown.     * @param animate Whether or not to use the in and out animations, defaults     *            to true.     */    void showOnly(int childIndex, boolean animate) {        final int count = getChildCount();        for (int i = 0; i < count; i++) {            final View child = getChildAt(i);            if (i == childIndex) {                if (animate && mInAnimation != null) {                    child.startAnimation(mInAnimation);                }                child.setVisibility(View.VISIBLE);                mFirstTime = false;            } else {                if (animate && mOutAnimation != null && child.getVisibility() == View.VISIBLE) {                    child.startAnimation(mOutAnimation);                } else if (child.getAnimation() == mInAnimation)                    child.clearAnimation();                child.setVisibility(View.GONE);            }        }    }    /**     * Shows only the specified child. The other displays Views exit the screen     * with the {@link #getOutAnimation() out animation} and the specified child     * enters the screen with the {@link #getInAnimation() in animation}.     *     * @param childIndex The index of the child to be shown.     */    void showOnly(int childIndex) {        final boolean animate = (!mFirstTime || mAnimateFirstTime);        showOnly(childIndex, animate);    }    @Override    public void addView(View child, int index, ViewGroup.LayoutParams params) {        super.addView(child, index, params);        if (getChildCount() == 1) {            child.setVisibility(View.VISIBLE);        } else {            child.setVisibility(View.GONE);        }        if (index >= 0 && mWhichChild >= index) {            // Added item above current one, increment the index of the displayed child            setDisplayedChild(mWhichChild + 1);        }    }    @Override    public void removeAllViews() {        super.removeAllViews();        mWhichChild = 0;        mFirstTime = true;    }    @Override    public void removeView(View view) {        final int index = indexOfChild(view);        if (index >= 0) {            removeViewAt(index);        }    }    @Override    public void removeViewAt(int index) {        super.removeViewAt(index);        final int childCount = getChildCount();        if (childCount == 0) {            mWhichChild = 0;            mFirstTime = true;        } else if (mWhichChild >= childCount) {            // Displayed is above child count, so float down to top of stack            setDisplayedChild(childCount - 1);        } else if (mWhichChild == index) {            // Displayed was removed, so show the new child living in its place            setDisplayedChild(mWhichChild);        }    }    public void removeViewInLayout(View view) {        removeView(view);    }    public void removeViews(int start, int count) {        super.removeViews(start, count);        if (getChildCount() == 0) {            mWhichChild = 0;            mFirstTime = true;        } else if (mWhichChild >= start && mWhichChild < start + count) {            // Try showing new displayed child, wrapping if needed            setDisplayedChild(mWhichChild);        }    }    public void removeViewsInLayout(int start, int count) {        removeViews(start, count);    }    /**     * Returns the View corresponding to the currently displayed child.     *     * @return The View currently displayed.     *     * @see #getDisplayedChild()     */    public View getCurrentView() {        return getChildAt(mWhichChild);    }    /**     * Returns the current animation used to animate a View that enters the screen.     *     * @return An Animation or null if none is set.     *     * @see #setInAnimation(android.view.animation.Animation)     * @see #setInAnimation(android.content.Context, int)     */    public Animation getInAnimation() {        return mInAnimation;    }    /**     * Specifies the animation used to animate a View that enters the screen.     *     * @param inAnimation The animation started when a View enters the screen.     *     * @see #getInAnimation()     * @see #setInAnimation(android.content.Context, int)     */    public void setInAnimation(Animation inAnimation) {        mInAnimation = inAnimation;    }    /**     * Returns the current animation used to animate a View that exits the screen.     *     * @return An Animation or null if none is set.     *     * @see #setOutAnimation(android.view.animation.Animation)     * @see #setOutAnimation(android.content.Context, int)     */    public Animation getOutAnimation() {        return mOutAnimation;    }    /**     * Specifies the animation used to animate a View that exit the screen.     *     * @param outAnimation The animation started when a View exit the screen.     *     * @see #getOutAnimation()     * @see #setOutAnimation(android.content.Context, int)     */    public void setOutAnimation(Animation outAnimation) {        mOutAnimation = outAnimation;    }    /**     * Specifies the animation used to animate a View that enters the screen.     *     * @param context The application's environment.     * @param resourceID The resource id of the animation.     *     * @see #getInAnimation()     * @see #setInAnimation(android.view.animation.Animation)     */    public void setInAnimation(Context context, int resourceID) {        setInAnimation(AnimationUtils.loadAnimation(context, resourceID));    }    /**     * Specifies the animation used to animate a View that exit the screen.     *     * @param context The application's environment.     * @param resourceID The resource id of the animation.     *     * @see #getOutAnimation()     * @see #setOutAnimation(android.view.animation.Animation)     */    public void setOutAnimation(Context context, int resourceID) {        setOutAnimation(AnimationUtils.loadAnimation(context, resourceID));    }    /**     * Returns whether the current View should be animated the first time the ViewAnimator     * is displayed.     *     * @return true if the current View will be animated the first time it is displayed,     * false otherwise.     *     * @see #setAnimateFirstView(boolean)     */    public boolean getAnimateFirstView() {        return mAnimateFirstTime;    }    /**     * Indicates whether the current View should be animated the first time     * the ViewAnimator is displayed.     *     * @param animate True to animate the current View the first time it is displayed,     *                false otherwise.     */    public void setAnimateFirstView(boolean animate) {        mAnimateFirstTime = animate;    }    @Override    public int getBaseline() {        return (getCurrentView() != null) ? getCurrentView().getBaseline() : super.getBaseline();    }    @Override    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {        super.onInitializeAccessibilityEvent(event);        event.setClassName(ViewAnimator.class.getName());    }    @Override    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {        super.onInitializeAccessibilityNodeInfo(info);        info.setClassName(ViewAnimator.class.getName());    }}

在ViewAnimator类中它继承了FrameLayout,这里我们就能明白他是用碎片来做切换的,源码还是比较简单的,都是一些设置属性的方法,比如setDisplayedChild(0)设置启动位置,setInAnimation()设置进入的动画,setOutAnimation()设置出去的动画等方法.看完源码我们现在是不是更清楚的知道ViewFlipper控件真的是为幻灯片连身定制的,但是有个问题就是图片多了容易报内存溢出.希望能帮助大大家.

动画效果可以自由设置,下面是从右到左的切换,先在res文件夹中创建一个anim文件夹在anim文件夹中创建xml文件选择set属性;R.anim.slide_left_in代码如下:

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" >    <!--    画面转换位置移动动画效果        开始向左动画       fromXDelta : 动画开始时 X坐标位置       toXDelta :动画结束时 X坐标位置       duration :动画持续时间      -->    <translate        android:duration="800"        android:fromXDelta="100%p"        android:toXDelta="0" /></set>

R.anim.slide_left_out代码如下:

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android" >    <translate        android:duration="800"        android:fromXDelta="0"        android:toXDelta="-100%p" /></set>







0 0
原创粉丝点击