Android添加系统级顶层窗口 和 WindowManager添加view的动画问题

 

当Dialog有编辑框时如果选择会弹菜单窗口就不要用

Context applicationContext = mainActivity.getApplicationContext();
AlertDialog.Builder dlgBuilder = new AlertDialog.Builder(applicationContext);
AlertDialog dialog = dlgBuilder.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

 

public class Dialog implements DialogInterface, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener

 

constructor

  /**
     * Create a Dialog window that uses the default dialog frame style.
     * 
     * @param context The Context the Dialog is to run it.  In particular, it
     *                uses the window manager and theme in this context to
     *                present its UI.
     */
    public Dialog(Context context) {
        this(context, 0, true);
    }

    /**
     * Create a Dialog window that uses a custom dialog style.
     * 
     * @param context The Context in which the Dialog should run. In particular, it
     *                uses the window manager and theme from this context to
     *                present its UI.
     * @param theme A style resource describing the theme to use for the 
     * window. See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style 
     * and Theme Resources</a> for more information about defining and using 
     * styles.  This theme is applied on top of the current theme in 
     * <var>context</var>.  If 0, the default dialog theme will be used.
     */
    public Dialog(Context context, int theme) {
        this(context, theme, true);
    }

    Dialog(Context context, int theme, boolean createContextThemeWrapper) {
        if (createContextThemeWrapper) {
            if (theme == 0) {
                TypedValue outValue = new TypedValue();
                context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,
                        outValue, true);
                theme = outValue.resourceId;
            }
            mContext = new ContextThemeWrapper(context, theme);
        } else {
            mContext = context;
        }

        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        Window w = PolicyManager.makeNewWindow(mContext);
        mWindow = w;
        w.setCallback(this);
        w.setWindowManager(mWindowManager, null, null);
        w.setGravity(Gravity.CENTER);
        mListenersHandler = new ListenersHandler(this);
    }

show


/** * Start the dialog and display it on screen. The window is placed in the * application layer and opaque. Note that you should not override this * method to do initialization when the dialog is shown, instead implement * that in {@link #onStart}. */ public void show() { if (mShowing) { if (mDecor != null) { if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) { mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR); } mDecor.setVisibility(View.VISIBLE); } return; } mCanceled = false; if (!mCreated) { dispatchOnCreate(null); } onStart(); mDecor = mWindow.getDecorView(); if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) { final ApplicationInfo info = mContext.getApplicationInfo(); mWindow.setDefaultIcon(info.icon); mWindow.setDefaultLogo(info.logo); mActionBar = new ActionBarImpl(this); } WindowManager.LayoutParams l = mWindow.getAttributes(); if ((l.softInputMode & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) { WindowManager.LayoutParams nl = new WindowManager.LayoutParams(); nl.copyFrom(l); nl.softInputMode |= WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; l = nl; } try { mWindowManager.addView(mDecor, l); mShowing = true; sendShowMessage(); } finally { } }

 

 

AndroidRuntime FATAL EXCEPTION

12-28 13:21:19.631: E/AndroidRuntime(8611): FATAL EXCEPTION: main
12-28 13:21:19.631: E/AndroidRuntime(8611): android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
12-28 13:21:19.631: E/AndroidRuntime(8611): at android.view.ViewRootImpl.setView(ViewRootImpl.java:571)
12-28 13:21:19.631: E/AndroidRuntime(8611): at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:246)
12-28 13:21:19.631: E/AndroidRuntime(8611): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
12-28 13:21:19.631: E/AndroidRuntime(8611): at android.widget.PopupWindow.invokePopup(PopupWindow.java:993)
12-28 13:21:19.631: E/AndroidRuntime(8611): at android.widget.PopupWindow.showAtLocation(PopupWindow.java:847)
12-28 13:21:19.631: E/AndroidRuntime(8611): at com.android.internal.policy.impl.PhoneWindow$DecorView$1.run(PhoneWindow.java:2285)
12-28 13:21:19.631: E/AndroidRuntime(8611): at android.os.Handler.handleCallback(Handler.java:725)
12-28 13:21:19.631: E/AndroidRuntime(8611): at android.os.Handler.dispatchMessage(Handler.java:92)
12-28 13:21:19.631: E/AndroidRuntime(8611): at android.os.Looper.loop(Looper.java:137)
12-28 13:21:19.631: E/AndroidRuntime(8611): at android.app.ActivityThread.main(ActivityThread.java:5041)
12-28 13:21:19.631: E/AndroidRuntime(8611): at java.lang.reflect.Method.invokeNative(Native Method)
12-28 13:21:19.631: E/AndroidRuntime(8611): at java.lang.reflect.Method.invoke(Method.java:511)
12-28 13:21:19.631: E/AndroidRuntime(8611): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
12-28 13:21:19.631: E/AndroidRuntime(8611): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
12-28 13:21:19.631: E/AndroidRuntime(8611): at dalvik.system.NativeStart.main(Native Method)



 

 

    <!-- Variant of {@link #Theme_Translucent} that has no title bar and
         no status bar -->
    <style name="Theme.Translucent.NoTitleBar.Fullscreen">
        <item name="android:windowFullscreen">true</item>
    </style>
    
    <!-- Default theme for activities that don't actually display a UI; that
         is, they finish themselves before being resumed.  -->
    <style name="Theme.NoDisplay">
        <item name="android:windowBackground">@null</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowAnimationStyle">@null</item>
        <item name="android:windowDisablePreview">true</item>
        <item name="android:windowNoDisplay">true</item>
    </style>

    <!-- Default theme for dialog windows and activities (on API level 10 and lower),
         which is used by the
         {@link android.app.Dialog} class.  This changes the window to be
         floating (not fill the entire screen), and puts a frame around its
         contents.  You can set this theme on an activity if you would like to
         make an activity that looks like a Dialog. -->
    <style name="Theme.Dialog">
        <item name="android:windowFrame">@null</item>
        <item name="android:windowTitleStyle">@android:style/DialogWindowTitle</item>
        <item name="android:windowBackground">@android:drawable/panel_background</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
        <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
        <item name="android:windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
        <item name="android:windowActionModeOverlay">true</item>

        <item name="android:colorBackgroundCacheHint">@null</item>
        
        <item name="textAppearance">@android:style/TextAppearance</item>
        <item name="textAppearanceInverse">@android:style/TextAppearance.Inverse</item>

        <item name="textColorPrimary">@android:color/primary_text_dark</item>
        <item name="textColorSecondary">@android:color/secondary_text_dark</item>
        <item name="textColorTertiary">@android:color/tertiary_text_dark</item>
        <item name="textColorPrimaryInverse">@android:color/primary_text_light</item>
        <item name="textColorSecondaryInverse">@android:color/secondary_text_light</item>
        <item name="textColorTertiaryInverse">@android:color/tertiary_text_light</item>
        <item name="textColorPrimaryDisableOnly">@android:color/primary_text_dark_disable_only</item>
        <item name="textColorPrimaryInverseDisableOnly">@android:color/primary_text_light_disable_only</item>
        <item name="textColorPrimaryNoDisable">@android:color/primary_text_dark_nodisable</item>
        <item name="textColorSecondaryNoDisable">@android:color/secondary_text_dark_nodisable</item>
        <item name="textColorPrimaryInverseNoDisable">@android:color/primary_text_light_nodisable</item>
        <item name="textColorSecondaryInverseNoDisable">@android:color/secondary_text_light_nodisable</item>
        <item name="textColorHint">@android:color/hint_foreground_dark</item>
        <item name="textColorHintInverse">@android:color/hint_foreground_light</item>
        <item name="textColorSearchUrl">@android:color/search_url_text</item>

        <item name="textAppearanceLarge">@android:style/TextAppearance.Large</item>
        <item name="textAppearanceMedium">@android:style/TextAppearance.Medium</item>
        <item name="textAppearanceSmall">@android:style/TextAppearance.Small</item>
        <item name="textAppearanceLargeInverse">@android:style/TextAppearance.Large.Inverse</item>
        <item name="textAppearanceMediumInverse">@android:style/TextAppearance.Medium.Inverse</item>
        <item name="textAppearanceSmallInverse">@android:style/TextAppearance.Small.Inverse</item>

        <item name="listPreferredItemPaddingLeft">10dip</item>
        <item name="listPreferredItemPaddingRight">10dip</item>
        <item name="listPreferredItemPaddingStart">10dip</item>
        <item name="listPreferredItemPaddingEnd">10dip</item>

        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
    </style>

    <!-- Variant of {@link Theme_Dialog} that does not include a frame (or background).
         The view hierarchy of the dialog is responsible for drawing all of
         its pixels. -->
    <style name="Theme.Dialog.NoFrame">
        <item name="windowBackground">@android:color/transparent</item>
        <item name="android:windowFrame">@null</item>
        <item name="windowContentOverlay">@null</item>
        <item name="android:windowAnimationStyle">@null</item>
        <item name="android:backgroundDimEnabled">false</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowCloseOnTouchOutside">false</item>
    </style>

    <!-- Default theme for alert dialog windows (on API level 10 and lower), which is used by the
         {@link android.app.AlertDialog} class.  This is basically a dialog
         but sets the background to empty so it can do two-tone backgrounds. -->
    <style name="Theme.Dialog.Alert">
        <item name="windowBackground">@android:color/transparent</item>
        <item name="windowTitleStyle">@android:style/DialogWindowTitle</item>
        <item name="windowContentOverlay">@null</item>
        <item name="itemTextAppearance">@android:style/TextAppearance.Large.Inverse</item>
        <item name="textAppearanceListItem">@android:style/TextAppearance.Large.Inverse</item>
        <item name="textAppearanceListItemSmall">@android:style/TextAppearance.Large.Inverse</item>
    </style>

 

        <activity
            android:name=".AlertActivity"
            android:excludeFromRecents="true"
            android:finishOnTaskLaunch="true"
            android:launchMode="singleInstance"
            android:theme="@*android:style/Theme.Dialog.Alert" >
        </activity>

 

 

package com.android.autologin;

import android.app.Activity;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.os.Bundle;

/**
 *     This is the dialog Activity used as an AlertDialog for the user to interact.
 * Requires android:launchMode="singleInstance" in your AndroidManifest to work
 * properly.
 * <p/>
 *     当Dialog有编辑框时如果选择会弹菜单窗口就不要用 AlertDialog(Application)
 * 再添加WindowManager.LayoutParams. TYPE_SYSTEM_ALERT,
 * <pre>
 *         Context applicationContext = mainActivity.getApplicationContext();
 *        AlertDialog.Builder dlgBuilder = new AlertDialog.Builder(applicationContext);
 *        EditText et = new EditText(mainActivity);
 *        dlgBuilder.setTitle(mainActivity.getTitle());
 *        dlgBuilder.setPositiveButton(android.R.string.ok, null);
 *        dlgBuilder.setNegativeButton(android.R.string.cancel, null);
 *        dlgBuilder.setIcon(android.R.drawable.ic_dialog_alert);
 *        dlgBuilder.setView(et);
 *        AlertDialog dialog = dlgBuilder.create();
 *        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
 *        dialog.show();
 * </pre>
 * 防止报错
 * attrs.token = null,
 * BadTokenException("Unable to add window -- token " + attrs.token + " is not for an application")
 * 
 * @usage
 * 
 * <i>.java</i>
 *        
 * <code><pre>
 *         Intent dialogIntent = new Intent(mContext, AlertActivity.class);
 *         dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 *         mContext.startActivity(dialogIntent);
 * </pre></code> 
 * 
 * <i>AndroidManifest.xml</i>
 * 
 * <pre>
 *         < activity
 *             android:name=".AlertActivity"
 *             android:excludeFromRecents="true"
 *             android:finishOnTaskLaunch="true"
 *             android:launchMode="singleInstance"
 *             android:theme="@android:style/Theme.Dialog" >
 *         < /activity>
 * </pre>
 * 
 * @author Sansan
 **/
public class AlertActivity extends Activity implements DialogInterface.OnClickListener, OnDismissListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // setContentView(R.layout.alertactivity);
        
        
        // Get root view from current activity
        // @see http://stackoverflow.com/questions/4486034/get-root-view-from-current-activity
        
        // //rootview
        //// check layouts in hierarchyviewer.
        
        // findViewById(android.R.id.content) is giving me the root view
        // findViewById(android.R.id.content).getRootView()
        //getWindow().getDecorView().findViewById(android.R.id.content)
        
        // //-------------------------------------------------------------------------------------------
        // //This is what I use to get the root view as found in the XML file assigned with setContentView
        // //This answer gave the view without the status bar - which is what I wanted. I was looking for 
        // //the pixel width + height of the visible part of the activity. This one works, thanks!
        //
        //This excludes ActionBar!
        //final ViewGroup viewGroup = (ViewGroup) ((ViewGroup) this.findViewById(android.R.id.content)).getChildAt(0);
        // //-------------------------------------------------------------------------------------------
        
        
        // //-------------------------------------------------------------------------------------------
        // //I tested this in android 4.0.3, only:
        //
        // getWindow().getDecorView().getRootView();
        //
        // //give the same view what we get from
        //
        // anyview.getRootView();  == com.android.internal.policy.impl.PhoneWindow$DecorView@#########
        //
        // //and
        //
        // getWindow().getDecorView().findViewById(android.R.id.content)
        
        // //giving child of its == android.widget.FrameLayout@#######
        // //Please confirm.
        // //-------------------------------------------------------------------------------------------
        
        //setVisible(true);
        //requestWindowFeature(Window.FEATURE_NO_TITLE);//去掉标题栏
        
        // //Error, if select any text to pop up a system menu view, such as
        // paste in
        // // the Dialog.
        // //@see android/view/ViewRootImpl.java
        // //case WindowManagerGlobal.ADD_NOT_APP_TOKEN: throw new
        // //WindowManager.BadTokenException("Unable to add window -- token " +
        // //attrs.token + " is not for an application");
        // Context applicationContext = this.getApplicationContext();
        // AlertDialog.Builder dlgBuilder = new
        // AlertDialog.Builder(applicationContext);

        //AlertDialog.Builder dlgBuilder = new AlertDialog.Builder(this);
        //EditText et = new EditText(this);

        //dlgBuilder.setTitle(this.getTitle());
        //dlgBuilder.setPositiveButton(android.R.string.ok, AlertActivity.this);
        //dlgBuilder.setNegativeButton(android.R.string.cancel, AlertActivity.this);
        //dlgBuilder.setIcon(android.R.drawable.ic_dialog_alert);
        //dlgBuilder.setView(et);
        //AlertDialog dialog = dlgBuilder.create();
        //dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
        //dialog.setCanceledOnTouchOutside(false);
        //dialog.setOnDismissListener(this);
        //dialog.show();
        
        
        // //DialogFragment
        // FragmentTransaction ft = getFragmentManager().beginTransaction();
        // DialogFragment newFragment = MyDialogFragment.newInstance();
        // ft.add(android.R.id.content, newFragment);
        // ft.commit();
    }

    //// @TargetApi(Build.VERSION_CODES.HONEYCOMB) 
//    public static class MyDialogFragment extends DialogFragment {
//        static MyDialogFragment newInstance() {
//            return new MyDialogFragment();
//        }
//
//        @Override
//        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//            //View v = inflater.inflate(R.layout.alertdialog, container, false);
//            getActivity().getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
//            return new EditText(getActivity());
//        }
//    }
    
    /**
     * meanwhile, finish the AlertActivity.
     */
    @Override
    public void onDismiss(DialogInterface dialog) {
        //finish();
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {

    }
}

 

 

Context applicationContext = mainActivity.getApplicationContext();
        WindowManager applicationWindowManager = (WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE);
        AlertDialog.Builder dlgBuilder = new AlertDialog.Builder(mainActivity);
        EditText et = new EditText(mainActivity);

        // Dialog界面
        dlgBuilder.setTitle(mainActivity.getTitle());
        dlgBuilder.setPositiveButton(android.R.string.ok, null);
        dlgBuilder.setNegativeButton(android.R.string.cancel, null);
        dlgBuilder.setIcon(android.R.drawable.ic_dialog_alert);
        dlgBuilder.setView(et);
        AlertDialog dialog = dlgBuilder.create();
        // dialog.getWindow().getAttributes().token = mainActivity.getWindow().getAttributes().token;
        //
        try {
            Field mWindowManagerField = Dialog.class.getDeclaredField("mWindowManager");
            mWindowManagerField.setAccessible(true);
            mWindowManagerField.set(dialog, applicationWindowManager);
        } catch (NoSuchFieldException e) {
            // TODO Auto-generated catch block
            Alog.w(TAG, e.toString());
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            Alog.w(TAG, e.toString());
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            Alog.w(TAG, e.toString());
        }

        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
        // dialog.getWindow().addFlags(android.R.attr.windowIsFloating);
        dialog.show();

 

 

public abstract class Window

    /**
     * Return whether this window is being displayed with a floating style
     * (based on the {@link android.R.attr#windowIsFloating} attribute in
     * the style/theme).
     *
     * @return Returns true if the window is configured to be displayed floating
     * on top of whatever is behind it.
     */
    public abstract boolean isFloating();

    /**
     * Set the width and height layout parameters of the window.  The default
     * for both of these is MATCH_PARENT; you can change them to WRAP_CONTENT
     * or an absolute value to make a window that is not full-screen.
     *
     * @param width The desired layout width of the window.
     * @param height The desired layout height of the window.
     *
     * @see ViewGroup.LayoutParams#height
     * @see ViewGroup.LayoutParams#width
     */
    public void setLayout(int width, int height) {
        final WindowManager.LayoutParams attrs = getAttributes();
        attrs.width = width;
        attrs.height = height;
        if (mCallback != null) {
            mCallback.onWindowAttributesChanged(attrs);
        }
    }

    /**
     * Set the gravity of the window, as per the Gravity constants.  This
     * controls how the window manager is positioned in the overall window; it
     * is only useful when using WRAP_CONTENT for the layout width or height.
     *
     * @param gravity The desired gravity constant.
     *
     * @see Gravity
     * @see #setLayout
     */
    public void setGravity(int gravity)
    {
        final WindowManager.LayoutParams attrs = getAttributes();
        attrs.gravity = gravity;
        if (mCallback != null) {
            mCallback.onWindowAttributesChanged(attrs);
        }
    }

    /**
     * Set the type of the window, as per the WindowManager.LayoutParams
     * types.
     *
     * @param type The new window type (see WindowManager.LayoutParams).
     */
    public void setType(int type) {
        final WindowManager.LayoutParams attrs = getAttributes();
        attrs.type = type;
        if (mCallback != null) {
            mCallback.onWindowAttributesChanged(attrs);
        }
    }

    /**
     * Set the format of window, as per the PixelFormat types.  This overrides
     * the default format that is selected by the Window based on its
     * window decorations.
     *
     * @param format The new window format (see PixelFormat).  Use
     *               PixelFormat.UNKNOWN to allow the Window to select
     *               the format.
     *
     * @see PixelFormat
     */
    public void setFormat(int format) {
        final WindowManager.LayoutParams attrs = getAttributes();
        if (format != PixelFormat.UNKNOWN) {
            attrs.format = format;
            mHaveWindowFormat = true;
        } else {
            attrs.format = mDefaultWindowFormat;
            mHaveWindowFormat = false;
        }
        if (mCallback != null) {
            mCallback.onWindowAttributesChanged(attrs);
        }
    }

    /**
     * Specify custom animations to use for the window, as per
     * {@link WindowManager.LayoutParams#windowAnimations
     * WindowManager.LayoutParams.windowAnimations}.  Providing anything besides
     * 0 here will override the animations the window would
     * normally retrieve from its theme.
     */
    public void setWindowAnimations(int resId) {
        final WindowManager.LayoutParams attrs = getAttributes();
        attrs.windowAnimations = resId;
        if (mCallback != null) {
            mCallback.onWindowAttributesChanged(attrs);
        }
    }

    /**
     * Specify an explicit soft input mode to use for the window, as per
     * {@link WindowManager.LayoutParams#softInputMode
     * WindowManager.LayoutParams.softInputMode}.  Providing anything besides
     * "unspecified" here will override the input mode the window would
     * normally retrieve from its theme.
     */
    public void setSoftInputMode(int mode) {
        final WindowManager.LayoutParams attrs = getAttributes();
        if (mode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            attrs.softInputMode = mode;
            mHasSoftInputMode = true;
        } else {
            mHasSoftInputMode = false;
        }
        if (mCallback != null) {
            mCallback.onWindowAttributesChanged(attrs);
        }
    }
    
    /**
     * Convenience function to set the flag bits as specified in flags, as
     * per {@link #setFlags}.
     * @param flags The flag bits to be set.
     * @see #setFlags
     * @see #clearFlags
     */
    public void addFlags(int flags) {
        setFlags(flags, flags);
    }

    /** @hide */
    public void addPrivateFlags(int flags) {
        setPrivateFlags(flags, flags);
    }
    
    /**
     * Convenience function to clear the flag bits as specified in flags, as
     * per {@link #setFlags}.
     * @param flags The flag bits to be cleared.
     * @see #setFlags
     * @see #addFlags
     */
    public void clearFlags(int flags) {
        setFlags(0, flags);
    }

    /**
     * Set the flags of the window, as per the
     * {@link WindowManager.LayoutParams WindowManager.LayoutParams}
     * flags.
     * 
     * <p>Note that some flags must be set before the window decoration is
     * created (by the first call to
     * {@link #setContentView(View, android.view.ViewGroup.LayoutParams)} or
     * {@link #getDecorView()}:
     * {@link WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN} and
     * {@link WindowManager.LayoutParams#FLAG_LAYOUT_INSET_DECOR}.  These
     * will be set for you based on the {@link android.R.attr#windowIsFloating}
     * attribute.
     *
     * @param flags The new window flags (see WindowManager.LayoutParams).
     * @param mask Which of the window flag bits to modify.
     * @see #addFlags
     * @see #clearFlags
     */
    public void setFlags(int flags, int mask) {
        final WindowManager.LayoutParams attrs = getAttributes();
        attrs.flags = (attrs.flags&~mask) | (flags&mask);
        if ((mask&WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0) {
            attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY;
        }
        mForcedWindowFlags |= mask;
        if (mCallback != null) {
            mCallback.onWindowAttributesChanged(attrs);
        }
    }

    private void setPrivateFlags(int flags, int mask) {
        final WindowManager.LayoutParams attrs = getAttributes();
        attrs.privateFlags = (attrs.privateFlags & ~mask) | (flags & mask);
        if (mCallback != null) {
            mCallback.onWindowAttributesChanged(attrs);
        }
    }

    /**
     * Set the amount of dim behind the window when using
     * {@link WindowManager.LayoutParams#FLAG_DIM_BEHIND}.  This overrides
     * the default dim amount of that is selected by the Window based on
     * its theme.
     *
     * @param amount The new dim amount, from 0 for no dim to 1 for full dim.
     */
    public void setDimAmount(float amount) {
        final WindowManager.LayoutParams attrs = getAttributes();
        attrs.dimAmount = amount;
        mHaveDimAmount = true;
        if (mCallback != null) {
            mCallback.onWindowAttributesChanged(attrs);
        }
    }

    /**
     * Specify custom window attributes.  <strong>PLEASE NOTE:</strong> the
     * layout params you give here should generally be from values previously
     * retrieved with {@link #getAttributes()}; you probably do not want to
     * blindly create and apply your own, since this will blow away any values
     * set by the framework that you are not interested in.
     *
     * @param a The new window attributes, which will completely override any
     *          current values.
     */
    public void setAttributes(WindowManager.LayoutParams a) {
        mWindowAttributes.copyFrom(a);
        if (mCallback != null) {
            mCallback.onWindowAttributesChanged(mWindowAttributes);
        }
    }

    /**
     * Retrieve the current window attributes associated with this panel.
     *
     * @return WindowManager.LayoutParams Either the existing window
     *         attributes object, or a freshly created one if there is none.
     */
    public final WindowManager.LayoutParams getAttributes() {
        return mWindowAttributes;
    }

 

public static class

WindowManager.LayoutParams

extends ViewGroup.LayoutParams
implements Parcelable
java.lang.Object
   ? android.view.ViewGroup.LayoutParams
     ? android.view.WindowManager.LayoutParams
 WindowManager.LayoutParams 是 WindowManager 接口的嵌套类;它继承于 ViewGroup.LayoutParams; 它用于向WindowManager描述Window的管理策略。
主要成员常量
Window flag系列
该系列主要用于对Window的flag进行设置。设置Window的flag,可以直接对Window的getAttributes()得到其 WindowManager.LayoutParams对象,然后直接对它flag变量操作。也可以Window的addFlags(int flags)方法,setFlags(int flags, int mask)方法,clearFlags(int flags)方法进行操作。
比如设置全屏:
 Window window = getWindow(); 
 WindowManager.LayoutParams winParams = win.getAttributes();
 winParams.flags=winParams.flags|WindowManager.LayoutParams.FLAG_FULLSCREEN;
 或
 window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
 或
 window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); 
 取消全屏
 Window window = getWindow(); 
 winParams.flags=winParams.flags&~WindowManager.LayoutParams.FLAG_FULLSCREEN;
 或
 window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
 或
window.setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN);
所有Window flag如下:

Window.addFlags(int flag)

final Window win = getWindow();
         win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);//覆盖在屏幕锁之上。
          PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
         if (!pm.isScreenOn()) {//屏幕时候保持高亮
             win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                     | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                     | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
                     | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
         }

 

 

一些Flag的介绍 
窗口之后的内容变暗。 
public static final int FLAG_DIM_BEHIND       = 0x00000002; 

窗口之后的内容变模糊。 
public static final int FLAG_BLUR_BEHIND       = 0x00000004; 

不许获得焦点。 
不能获得按键输入焦点,所以不能向它发送按键或按钮事件。那些时间将发送给它后面的可以获得焦点的窗口。此选项还会设置FLAG_NOT_TOUCH_MODAL选项。设置此选项,意味着窗口不能与软输入法进行交互,所以它的Z序独立于任何活动的输入法(换句话说,它可以全屏显示,如果需要的话,可覆盖输入法窗口)。要修改这一行为,可参考FLAG_ALT_FOCUSALBE_IM选项。 
public static final int FLAG_NOT_FOCUSABLE     = 0x00000008; 

不接受触摸屏事件。 
public static final int FLAG_NOT_TOUCHABLE     = 0x00000010; 

当窗口可以获得焦点(没有设置FLAG_NOT_FOCUSALBE选项)时,仍然将窗口范围之外的点设备事件(鼠标、触摸屏)发送给后面的窗口处理。否则它将独占所有的点设备事件,而不管它们是不是发生在窗口范围之内。 
public static final int FLAG_NOT_TOUCH_MODAL   = 0x00000020; 

如果设置了这个标志,当设备休眠时,点击触摸屏,设备将收到这个第一触摸事件。 
通常第一触摸事件被系统所消耗,用户不会看到他们点击屏幕有什么反应。 
public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040; 

当此窗口为用户可见时,保持设备常开,并保持亮度不变。 
public static final int FLAG_KEEP_SCREEN_ON    = 0x00000080; 

窗口占满整个屏幕,忽略周围的装饰边框(例如状态栏)。此窗口需考虑到装饰边框的内容。 
public static final int FLAG_LAYOUT_IN_SCREEN   =0x00000100; 

允许窗口扩展到屏幕之外。 
public static final int FLAG_LAYOUT_NO_LIMITS   =0x00000200; 

窗口显示时,隐藏所有的屏幕装饰(例如状态条)。使窗口占用整个显示区域。 
public static final int FLAG_FULLSCREEN     = 0x00000400; 

此选项将覆盖FLAG_FULLSCREEN选项,并强制屏幕装饰(如状态条)弹出。 
public static final int FLAG_FORCE_NOT_FULLSCREEN   =0x00000800; 

抖动。指的是对半透明的显示方法。又称“点透”。图形处理较差的设备往往用“点透”替代Alpha混合。 
public static final int FLAG_DITHER           = 0x00001000; 

不允许屏幕截图。 
public static final int FLAG_SECURE           = 0x00002000; 

一种特殊模式,布局参数用于指示显示比例。 
public static final int FLAG_SCALED           = 0x00004000; 

当屏幕有可能贴着脸时,这一选项可防止面颊对屏幕造成误操作。 
public static final int FLAG_IGNORE_CHEEK_PRESSES   = 0x00008000; 

当请求布局时,你的窗口可能出现在状态栏的上面或下面,从而造成遮挡。当设置这一选项后,窗口管理器将确保窗口内容不会被装饰条(状态栏)盖住。 
public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000; 

反转FLAG_NOT_FOCUSABLE选项。 
如果同时设置了FLAG_NOT_FOCUSABLE选项和本选项,窗口将能够与输入法交互,允许输入法窗口覆盖; 
如果FLAG_NOT_FOCUSABLE没有设置而设置了本选项,窗口不能与输入法交互,可以覆盖输入法窗口。 
public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000; 

如果你设置了FLAG_NOT_TOUCH_MODAL,那么当触屏事件发生在窗口之外事,可以通过设置此标志接收到一个MotionEvent.ACTION_OUTSIDE事件。注意,你不会收到完整的down/move/up事件,只有第一次down事件时可以收到ACTION_OUTSIDE。 
public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000; 

当屏幕锁定时,窗口可以被看到。这使得应用程序窗口优先于锁屏界面。可配合FLAG_KEEP_SCREEN_ON选项点亮屏幕并直接显示在锁屏界面之前。可使用FLAG_DISMISS_KEYGUARD选项直接解除非加锁的锁屏状态。此选项只用于最顶层的全屏幕窗口。 
public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000; 

请求系统墙纸显示在你的窗口后面。窗口必须是半透明的。 
public static final int FLAG_SHOW_WALLPAPER = 0x00100000; 

窗口一旦显示出来,系统将点亮屏幕,正如用户唤醒设备那样。 
public static final int FLAG_TURN_SCREEN_ON = 0x00200000; 

解除锁屏。只有锁屏界面不是加密的才能解锁。如果锁屏界面是加密的,那么用户解锁之后才能看到此窗口,除非设置了FLAG_SHOW_WHEN_LOCKED选项。 
public static final int FLAG_DISMISS_KEYGUARD = 0x00400000; 

锁屏界面淡出时,继续运行它的动画。 
public static final int FLAG_KEEP_SURFACE_WHILE_ANIMATING =0x10000000; 

以原始尺寸显示窗口。用于在兼容模式下运行程序。 
public static final int FLAG_COMPATIBLE_WINDOW = 0x20000000; 

用于系统对话框。设置此选项的窗口将无条件获得焦点。 
public static final int FLAG_SYSTEM_ERROR = 0x40000000; 

 

type 的取值:
      应用程序窗口。
      public static final int FIRST_APPLICATION_WINDOW = 1;   
 
      所有程序窗口的“基地”窗口,其他应用程序窗口都显示在它上面。    
      public static final int TYPE_BASE_APPLICATION   =1;
        
      普通应用功能程序窗口。token必须设置为Activity的token,以指出该窗口属谁。
      public static final int TYPE_APPLICATION       = 2;
 
       用于应用程序启动时所显示的窗口。应用本身不要使用这种类型。
      它用于让系统显示些信息,直到应用程序可以开启自己的窗口。  
      public static final int TYPE_APPLICATION_STARTING = 3;
      
      应用程序窗口结束。
      public static final int LAST_APPLICATION_WINDOW = 99;
 
      子窗口。子窗口的Z序和坐标空间都依赖于他们的宿主窗口。
      public static final int FIRST_SUB_WINDOW       = 1000;
 
      面板窗口,显示于宿主窗口上层。
      public static final int TYPE_APPLICATION_PANEL  = FIRST_SUB_WINDOW;
 
      媒体窗口,例如视频。显示于宿主窗口下层。
      public static final int TYPE_APPLICATION_MEDIA  = FIRST_SUB_WINDOW+1;
 
      应用程序窗口的子面板。显示于所有面板窗口的上层。(GUI的一般规律,越“子”越靠上)
      public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW +2;
 
      对话框。类似于面板窗口,绘制类似于顶层窗口,而不是宿主的子窗口。
      public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW +3;
 
      媒体信息。显示在媒体层和程序窗口之间,需要实现透明(半透明)效果。(例如显示字幕)
      public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW +4;
 
      子窗口结束。( End of types of sub-windows )
      public static final int LAST_SUB_WINDOW        = 1999;
 
      系统窗口。非应用程序创建。
      public static final int FIRST_SYSTEM_WINDOW    = 2000;
 
      状态栏。只能有一个状态栏;它位于屏幕顶端,其他窗口都位于它下方。
      public static final int TYPE_STATUS_BAR        =  FIRST_SYSTEM_WINDOW;
 
      搜索栏。只能有一个搜索栏;它位于屏幕上方。
      public static final int TYPE_SEARCH_BAR        = FIRST_SYSTEM_WINDOW+1;
 
      电话窗口。它用于电话交互(特别是呼入)。它置于所有应用程序之上,状态栏之下。
      public static final int TYPE_PHONE            = FIRST_SYSTEM_WINDOW+2;
 
      系统提示。它总是出现在应用程序窗口之上。
      public static final int TYPE_SYSTEM_ALERT      =  FIRST_SYSTEM_WINDOW +3;
 
      锁屏窗口。
      public static final int TYPE_KEYGUARD          = FIRST_SYSTEM_WINDOW +4;
 
      信息窗口。用于显示toast。
      public static final int TYPE_TOAST            = FIRST_SYSTEM_WINDOW +5;
 
      系统顶层窗口。显示在其他一切内容之上。此窗口不能获得输入焦点,否则影响锁屏。
      public static final int TYPE_SYSTEM_OVERLAY    =  FIRST_SYSTEM_WINDOW +6;
 
      电话优先,当锁屏时显示。此窗口不能获得输入焦点,否则影响锁屏。
      public static final int TYPE_PRIORITY_PHONE    =  FIRST_SYSTEM_WINDOW +7;
 
      系统对话框。(例如音量调节框)。
      public static final int TYPE_SYSTEM_DIALOG     =  FIRST_SYSTEM_WINDOW +8;
 
      锁屏时显示的对话框。
      public static final int TYPE_KEYGUARD_DIALOG   =  FIRST_SYSTEM_WINDOW +9;
 
      系统内部错误提示,显示于所有内容之上。
      public static final int TYPE_SYSTEM_ERROR      =  FIRST_SYSTEM_WINDOW +10;
 
      内部输入法窗口,显示于普通UI之上。应用程序可重新布局以免被此窗口覆盖。
      public static final int TYPE_INPUT_METHOD      =  FIRST_SYSTEM_WINDOW +11;
 
      内部输入法对话框,显示于当前输入法窗口之上。
      public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW +12;
 
      墙纸窗口。
      public static final int TYPE_WALLPAPER         = FIRST_SYSTEM_WINDOW +13;
 
      状态栏的滑动面板。
      public static final int TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW +14;
 
      系统窗口结束。
      public static final int LAST_SYSTEM_WINDOW     = 2999;

 

 

关于Window的类型,主要有三种:
1 Application Windows:取值在 FIRST_APPLICATION_WINDOW 和 LAST_APPLICATION_WINDOW 之间。
是通常的、顶层的应用程序窗口。必须将token设置成activity的token。
2 Sub Windows:取值在 FIRST_SUB_WINDOW 和 LAST_SUB_WINDOW 之间。
与顶层窗口相关联,token必须设置为它所附着的宿主窗口的token。
3 System Windows:取值在 FIRST_SYSTEM_WINDOW 和 LAST_SYSTEM_WINDOW 之间。
用于特定的系统功能。它不能用于应用程序,使用时需要特殊权限,在manifest.xml中添加如下声明:

 
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

这三种类型的图层顺序是一次增高,即Application Windows在对底层,System Windows在最上层。看到这里我们再来看一下上面的代码,其中这样一句:

 
mWindowLayoutParams.type = android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;

 Dialog是属于Sub Windows类型的,Toast是System Windows类型

 

Android WindowManager及其动画问题

来源:wangjinyu501的专栏

一、概述 开发中发现在WindowManager上像在Activity中使用动画效果无效,比如下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
ImageView iv = new ImageView(this);
iv.setImageResource(R.drawable.ic_launcher);
TranslateAnimation animation = new TranslateAnimation(
        Animation.ABSOLUTE, 20, Animation.ABSOLUTE, 300,
        Animation.ABSOLUTE, 100, Animation.ABSOLUTE, 400);
animation.setDuration(1000);
animation.setFillAfter(false);
iv.setAnimation(animation);
 
WindowManager mWindowManager = (WindowManager) this
        .getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
mLayoutParams.x = 20;
mLayoutParams.y = 100;
mLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
mLayoutParams.gravity = Gravity.TOP;
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
mWindowManager.addView(iv, mLayoutParams);
 
animation.start();

二、分析 为什么会不执行动画呢,原因在于:the view which is going to be animated must not be directly added to the top window, because top window of android is not a real ViewGroup. so the view must be added to a ViewGroup like FrameLayout first and then this ViewGroup be added to the top window.意思是说动画执行的条件是不能直接添加到最顶层的Window,而是需要一个容器。比如,在xml中定义的控件就可以使用动画。 后来发现一种解决方案是WindowManager.LayoutParams有一个动画属性:windowAnimations,可以这样使用

1
2
3
4
5
6
7
8
9
10
11
lp = new WindowManager.LayoutParams(LayoutParams.WRAP_CONTENT,
                 LayoutParams.WRAP_CONTENT,
                 WindowManager.LayoutParams.TYPE_PHONE,
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                           | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                           | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                 PixelFormat.RGBA_8888);
       lp.gravity = Gravity.LEFT |Gravity.TOP;
       lp.windowAnimations = R.style.anim_view;//动画
       wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
       wm.addView(view, lp);

但是,这是对整个View的一个动画,而不是View中某个控件的动画。而且,使用的时候需要在View状态改变的时候才会出现动画效果。比如消失/出现的时候才会有动画效果。因此这个方案也是行不通的。 既然WindowManager不是一个ViewGroup,那么就构造一个容器来装载WindowManager,可以如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/**
*
*/
package com.kince.apus.widget;
 
import com.kince.apus.R;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
 
/**
* @author kince
* @category Windowmanager在Layout中的应用
*
*
*/
public class GuideLayout extends FrameLayout {
 
     private WindowManager wManager;
     private WindowManager.LayoutParams wmParams;
     private View addView;
 
     private TextView mTextView;
     private ImageView mImageView;
 
     private boolean isAddView;
     private AnimatorSet mShowAnimatorSet, mHideAnimatorSet;
 
     private Handler mHandler = new Handler() {
          public void handleMessage(android.os.Message msg) {
               super.handleMessage(msg);
 
               switch (msg.what) {
               case 1:
                    showAnimator();
                    break;
 
               default:
                    break;
               }
          };
     };
 
     /**
     * @param context
     */
     public GuideLayout(Context context) {
          this(context, null);
          // TODO Auto-generated constructor stub
     }
 
     /**
     * @param context
     * @param attrs
     */
     public GuideLayout(Context context, AttributeSet attrs) {
          this(context, attrs, 0);
          // TODO Auto-generated constructor stub
     }
 
     /**
     * @param context
     * @param attrs
     * @param defStyle
     */
     public GuideLayout(Context context, AttributeSet attrs, int defStyle) {
          super(context, attrs, defStyle);
          addView = LayoutInflater.from(context).inflate(R.layout.guide_layout,
                    this);
          mTextView = (TextView) addView.findViewById(R.id.tv);
          mImageView = (ImageView) addView.findViewById(R.id.iv);
          mTextView.setVisibility(View.GONE);
          mImageView.setVisibility(View.GONE);
          setAnimator();
          getWindowManager(context);
     }
 
     /**
     * @category 实例化WindowManager 初次模拟位置时候使用
     * @param context
     */
     private void getWindowManager(final Context context) {
          wManager = (WindowManager) context.getApplicationContext()
                    .getSystemService(Context.WINDOW_SERVICE);
          wmParams = new WindowManager.LayoutParams();
          wmParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
          wmParams.format = PixelFormat.TRANSPARENT;
          wmParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
          wmParams.gravity = 17;
          wmParams.width = WindowManager.LayoutParams.MATCH_PARENT;
          wmParams.height = WindowManager.LayoutParams.MATCH_PARENT;
     }
 
     private void setAnimator() {
          mShowAnimatorSet = new AnimatorSet();
          Animator[] showAnimator = new Animator[2];
          showAnimator[0] = ObjectAnimator.ofFloat(mTextView, "alpha",
                    new float[] { 0.0F, 1.0F });
          showAnimator[1] = ObjectAnimator.ofFloat(mImageView, "alpha",
                    new float[] { 0.0F, 1.0F });
          mShowAnimatorSet.playTogether(showAnimator);
          mShowAnimatorSet.setDuration(1500l);
 
          mHideAnimatorSet = new AnimatorSet();
          Animator[] hideAnimator = new Animator[2];
          hideAnimator[0] = ObjectAnimator.ofFloat(mTextView, "alpha",
                    new float[] { 1.0F, 0.0F });
          hideAnimator[1] = ObjectAnimator.ofFloat(mImageView, "alpha",
                    new float[] { 1.0F, 0.0F });
          mHideAnimatorSet.playTogether(hideAnimator);
          mHideAnimatorSet.setDuration(1500l);
     }
 
     public void showAnimator() {
          mTextView.setVisibility(View.VISIBLE);
          mImageView.setVisibility(View.VISIBLE);
          mShowAnimatorSet.start();
          isAddView=true;
     }
 
     public void hideAnimator() {
          mHideAnimatorSet.start();
          mHideAnimatorSet.addListener(new AnimatorListener() {
 
               @Override
               public void onAnimationStart(Animator animation) {
                    // TODO Auto-generated method stub
 
               }
 
               @Override
               public void onAnimationRepeat(Animator animation) {
                    // TODO Auto-generated method stub
 
               }
 
               @Override
               public void onAnimationEnd(Animator animation) {
                    // TODO Auto-generated method stub
                    mTextView.setVisibility(View.INVISIBLE);
                    mImageView.setVisibility(View.INVISIBLE);
               }
 
               @Override
               public void onAnimationCancel(Animator animation) {
                    // TODO Auto-generated method stub
 
               }
          });
 
     }
 
     public void sendMessage() {
          if (isAddView) {
               wManager.removeView(this);
               mHandler.removeMessages(1);
               isAddView=false;
          }
          mHandler.sendEmptyMessage(1);
          wManager.addView(this, wmParams);
     }
 
}

这样一来,就可以实现在WindowManager上的动画效果了。其实,造成这种现象的原因在于对AndroidAPI以及其体系的理解不够深刻。忽略了动画执行所需要的基本条件,影射的问题就是考虑问题不够全面。所以,不论开发哪种功能,使用哪个API,前期的规划、调研很重要。知己知彼,仅此而已。

posted @ 2014-12-28 09:24  山岚的一缺  阅读(11711)  评论(0编辑  收藏  举报
喜欢
评论
收藏
顶部