lorensiuswlt / NewQuickAction3D

Gallery3D like quickaction
http://www.londatiga.net/it/how-to-create-quickaction-dialog-in-android/
Apache License 2.0
400 stars 236 forks source link

Inflate actions from XML file #6

Open mariotaku opened 12 years ago

mariotaku commented 12 years ago

Hi! I used your code in my own project. I'd like to contribute some code for you! This code is QuickActionInflater, use it as MenuInflater, example:

QuickActionInflater mInflater = new QuickActionInflater(this);
mQuickAction = new QuickAction(this, QuickAction.VERTICAL);
mInflater.inflate(R.menu.options_menu_playback, mQuickAction);

Source code:

/*
 * Copyright (C) 2012 The MusicMod Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.londatiga.android;

import java.io.IOException;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.app.Activity;
import android.content.Context;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
import android.view.InflateException;

/**
 * This class is used to instantiate menu XML files into Menu objects.
 * <p>
 * For performance reasons, menu inflation relies heavily on pre-processing of
 * XML files that is done at build time. Therefore, it is not currently possible
 * to use MenuInflater with an XmlPullParser over a plain XML file at runtime;
 * it only works with an XmlPullParser returned from a compiled resource (R.
 * <em>something</em> file.)
 */
public class QuickActionInflater {
    /** Menu tag name in XML. */
    private static final String XML_MENU = "menu";

    /** Item tag name in XML. */
    private static final String XML_ITEM = "item";

    /** Namespaces to read attributes */
    private static final String ANDROID_NS = "http://schemas.android.com/apk/res/android";

    /** Attribute names */
    private static final String ATTR_ID = "id";
    private static final String ATTR_TITLE = "title";
    private static final String ATTR_ICON = "icon";

    private Context mContext;

    /**
     * Constructs a menu inflater.
     * 
     * @see Activity#getMenuInflater()
     */
    public QuickActionInflater(Context context) {
        mContext = context;
    }

    /**
     * Inflate a menu hierarchy from the specified XML resource. Throws
     * {@link InflateException} if there is an error.
     * 
     * @param menuRes Resource ID for an XML layout resource to load (e.g.,
     *            <code>R.menu.main_activity</code>)
     * @param menu The Menu to inflate into. The items and submenus will be
     *            added to this Menu.
     */
    public void inflate(int menuRes, QuickAction action) {
        XmlResourceParser parser = null;
        try {
            parser = mContext.getResources().getLayout(menuRes);
            AttributeSet attrs = Xml.asAttributeSet(parser);

            parseMenu(parser, attrs, action);
        } catch (XmlPullParserException e) {
            throw new InflateException("Error inflating menu XML", e);
        } catch (IOException e) {
            throw new InflateException("Error inflating menu XML", e);
        } finally {
            if (parser != null) parser.close();
        }
    }

    /**
     * Called internally to fill the given menu. If a sub menu is seen, it will
     * call this recursively.
     */
    private void parseMenu(XmlPullParser parser, AttributeSet attrs, QuickAction action)
            throws XmlPullParserException, IOException {
        QuickActionState quickActionState = new QuickActionState(action);

        int eventType = parser.getEventType();
        String tagName;
        boolean lookingForEndOfUnknownTag = false;
        String unknownTagName = null;

        // This loop will skip to the menu start tag
        do {
            if (eventType == XmlPullParser.START_TAG) {
                tagName = parser.getName();
                if (tagName.equals(XML_MENU)) {
                    // Go to next tag
                    eventType = parser.next();
                    break;
                }

                throw new RuntimeException("Expecting menu, got " + tagName);
            }
            eventType = parser.next();
        } while (eventType != XmlPullParser.END_DOCUMENT);

        boolean reachedEndOfMenu = false;
        while (!reachedEndOfMenu) {
            switch (eventType) {
                case XmlPullParser.START_TAG:
                    if (lookingForEndOfUnknownTag) {
                        break;
                    }
                    tagName = parser.getName();
                    if (tagName.equals(XML_ITEM)) {
                        quickActionState.readItem(attrs);
                    } else {
                        lookingForEndOfUnknownTag = true;
                        unknownTagName = tagName;
                    }
                    break;
                case XmlPullParser.END_TAG:
                    tagName = parser.getName();
                    if (lookingForEndOfUnknownTag && tagName.equals(unknownTagName)) {
                        lookingForEndOfUnknownTag = false;
                        unknownTagName = null;
                    } else if (tagName.equals(XML_ITEM)) {
                        // Add the item if it hasn't been added (if the item was
                        // a submenu, it would have been added already)
                        if (!quickActionState.hasAddedItem()) {
                            quickActionState.addItem();
                        }
                    } else if (tagName.equals(XML_MENU)) {
                        reachedEndOfMenu = true;
                    }
                    break;

                case XmlPullParser.END_DOCUMENT:
                    throw new RuntimeException("Unexpected end of document");
            }

            eventType = parser.next();
        }
    }

    /**
     * State for the current menu.
     * <p>
     * Groups can not be nested unless there is another menu (which will have
     * its state class).
     */
    private class QuickActionState {
        private QuickAction action;

        private boolean itemAdded;
        private int itemId;
        private String itemTitle;
        private Drawable itemIcon;

        public QuickActionState(final QuickAction action) {
            this.action = action;

        }

        /**
         * Called when the parser is pointing to an item tag.
         */
        public void readItem(AttributeSet attrs) {
            // Inherit attributes from the group as default value
            Log.d("QuickActionInflater", "item read! itemId = " + itemId);
            itemId = attrs.getAttributeResourceValue(ANDROID_NS, ATTR_ID, 0);
            itemTitle = mContext.getString(attrs.getAttributeResourceValue(ANDROID_NS, ATTR_TITLE, 0));
            itemIcon = mContext.getResources().getDrawable(attrs.getAttributeResourceValue(ANDROID_NS, ATTR_ICON, android.R.color.transparent));
            itemAdded = false;
        }

        private ActionItem setItem() {
            return new ActionItem(itemId,itemTitle,itemIcon);
        }

        public void addItem() {
            itemAdded = true;
            action.addActionItem(setItem());
        }

        public boolean hasAddedItem() {
            return itemAdded;
        }
    }

}