Android V7包学习笔记更新中.....

关于V4 V7 V13

VX包介绍转自这里

1, Android Support V4, V7, V13是什么?

本质上就是三个java library。

2, 为什么要有support库?

如果在低版本Android平台上开发一个应用程序,而应用程序又想使用高版本才拥有的功能,就需要使用Support库。

3, 三个Support 库的区别和作用是什么?

Android Support v4 是最早(2011年4月份)实现的库。用在Android1.6 (API lever 4)或者更高版本之上。它包含了相对V4, V13大的多的功能。

例如:Fragment,NotificationCompat,LoadBroadcastManager,ViewPager,PageTabAtrip,Loader,FileProvider 等。

详细API 参考 http://developer.android.com/reference/android/support/v4/app/package-summary.html

Android Support v7: 这个包是为了考虑Android2.1(API level 7) 及以上版本而设计的,但是v7是要依赖v4这个包的,也就是如果要使用,两个包得同时 被引用。

v7支持了Action Bar。

Android Support v13:这个包的设计是为了android 3.2及更高版本的,一般我们都不常用,平板开发中能用到。



sdk\extras\android\support\samples\Support7Demos笔记

FloatingActionButton

代码分析:

Logger包

关于log:需要使用Log输出一些信息。那么我们就需要使用到Log FrameWork。使用及注释如下

  public void initializeLogging() {
        //封装android底层log框架
        LogWrapper logWrapper = new LogWrapper();
        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
        /**
         * Log的消息传递是依据一个链路依次传递的,Log传递到LogWrapper,LogWrapper传递到MessageOnlyLogFilter,MessageOnlyLogFilter传递到LogFragment
         */

        Log.setLogNode(logWrapper);

        // 过滤器
        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
        logWrapper.setNext(msgFilter);

        // On screen logging via a fragment with a TextView.
        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
                .findFragmentById(R.id.log_fragment);
        msgFilter.setNext(logFragment.getLogView());
        Log.i(TAG, "Ready");
    }

涉及到的主要的类:


package com.example.android.common.logger;

/**
 * Helper class for a list (or tree) of LoggerNodes.
 *
 * <p>When this is set as the head of the list,
 * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
 * Most of the methods in this class server only to map a method call in Log to its equivalent
 * in LogNode.</p>
 */
public class Log {
    // Grabbing the native values from Android‘s native logging facilities,
    // to make for easy migration and interop.
    public static final int NONE = -1;
    public static final int VERBOSE = android.util.Log.VERBOSE;
    public static final int DEBUG = android.util.Log.DEBUG;
    public static final int INFO = android.util.Log.INFO;
    public static final int WARN = android.util.Log.WARN;
    public static final int ERROR = android.util.Log.ERROR;
    public static final int ASSERT = android.util.Log.ASSERT;

    // Stores the beginning of the LogNode topology.
    private static LogNode mLogNode;

    /**
     * Returns the next LogNode in the linked list.
     */
    public static LogNode getLogNode() {
        return mLogNode;
    }

    /**
     * Sets the LogNode data will be sent to.
     */
    public static void setLogNode(LogNode node) {
        mLogNode = node;
    }

    /**
     * Instructs the LogNode to print the log data provided. Other LogNodes can
     * be chained to the end of the LogNode as desired.
     *
     * @param priority Log level of the data being logged. Verbose, Error, etc.
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param msg The actual message to be logged.
     * @param tr If an exception was thrown, this can be sent along for the logging facilities
     *           to extract and print useful information.
     */
    public static void println(int priority, String tag, String msg, Throwable tr) {
        if (mLogNode != null) {
            mLogNode.println(priority, tag, msg, tr);
        }
    }

    /**
     * Instructs the LogNode to print the log data provided. Other LogNodes can
     * be chained to the end of the LogNode as desired.
     *
     * @param priority Log level of the data being logged. Verbose, Error, etc.
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param msg The actual message to be logged. The actual message to be logged.
     */
    public static void println(int priority, String tag, String msg) {
        println(priority, tag, msg, null);
    }

   /**
     * Prints a message at VERBOSE priority.
     *
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param msg The actual message to be logged.
     * @param tr If an exception was thrown, this can be sent along for the logging facilities
     *           to extract and print useful information.
     */
    public static void v(String tag, String msg, Throwable tr) {
        println(VERBOSE, tag, msg, tr);
    }

    /**
     * Prints a message at VERBOSE priority.
     *
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param msg The actual message to be logged.
     */
    public static void v(String tag, String msg) {
        v(tag, msg, null);
    }

    /**
     * Prints a message at DEBUG priority.
     *
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param msg The actual message to be logged.
     * @param tr If an exception was thrown, this can be sent along for the logging facilities
     *           to extract and print useful information.
     */
    public static void d(String tag, String msg, Throwable tr) {
        println(DEBUG, tag, msg, tr);
    }

    /**
     * Prints a message at DEBUG priority.
     *
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param msg The actual message to be logged.
     */
    public static void d(String tag, String msg) {
        d(tag, msg, null);
    }

    /**
     * Prints a message at INFO priority.
     *
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param msg The actual message to be logged.
     * @param tr If an exception was thrown, this can be sent along for the logging facilities
     *           to extract and print useful information.
     */
    public static void i(String tag, String msg, Throwable tr) {
        println(INFO, tag, msg, tr);
    }

    /**
     * Prints a message at INFO priority.
     *
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param msg The actual message to be logged.
     */
    public static void i(String tag, String msg) {
        i(tag, msg, null);
    }

    /**
     * Prints a message at WARN priority.
     *
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param msg The actual message to be logged.
     * @param tr If an exception was thrown, this can be sent along for the logging facilities
     *           to extract and print useful information.
     */
    public static void w(String tag, String msg, Throwable tr) {
        println(WARN, tag, msg, tr);
    }

    /**
     * Prints a message at WARN priority.
     *
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param msg The actual message to be logged.
     */
    public static void w(String tag, String msg) {
        w(tag, msg, null);
    }

    /**
     * Prints a message at WARN priority.
     *
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param tr If an exception was thrown, this can be sent along for the logging facilities
     *           to extract and print useful information.
     */
    public static void w(String tag, Throwable tr) {
        w(tag, null, tr);
    }

    /**
     * Prints a message at ERROR priority.
     *
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param msg The actual message to be logged.
     * @param tr If an exception was thrown, this can be sent along for the logging facilities
     *           to extract and print useful information.
     */
    public static void e(String tag, String msg, Throwable tr) {
        println(ERROR, tag, msg, tr);
    }

    /**
     * Prints a message at ERROR priority.
     *
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param msg The actual message to be logged.
     */
    public static void e(String tag, String msg) {
        e(tag, msg, null);
    }

    /**
     * Prints a message at ASSERT priority.
     *
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param msg The actual message to be logged.
     * @param tr If an exception was thrown, this can be sent along for the logging facilities
     *           to extract and print useful information.
     */
    public static void wtf(String tag, String msg, Throwable tr) {
        println(ASSERT, tag, msg, tr);
    }

    /**
     * Prints a message at ASSERT priority.
     *
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param msg The actual message to be logged.
     */
    public static void wtf(String tag, String msg) {
        wtf(tag, msg, null);
    }

    /**
     * Prints a message at ASSERT priority.
     *
     * @param tag Tag for for the log data. Can be used to organize log statements.
     * @param tr If an exception was thrown, this can be sent along for the logging facilities
     *           to extract and print useful information.
     */
    public static void wtf(String tag, Throwable tr) {
        wtf(tag, null, tr);
    }
}
/**
    内部包装了android的Log  FrameWork
 Helper class which wraps Android‘s native Log utility in the Logger interface.  This way
        * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
        */
public class LogWrapper implements LogNode {

    // For piping:  The next node to receive Log data after this one has done its work.
    private LogNode mNext;

    /**
     * Returns the next LogNode in the linked list.
     */
    public LogNode getNext() {
        return mNext;
    }

    /**
     * Sets the LogNode data will be sent to..
     */
    public void setNext(LogNode node) {
        mNext = node;
    }

    /**
     * Prints data out to the console using Android‘s native log mechanism.
     * @param priority Log level of the data being logged.  Verbose, Error, etc.
     * @param tag Tag for for the log data.  Can be used to organize log statements.
     * @param msg The actual message to be logged. The actual message to be logged.
     * @param tr If an exception was thrown, this can be sent along for the logging facilities
     *           to extract and print useful information.
     */
    @Override
    public void println(int priority, String tag, String msg, Throwable tr) {
        // There actually are log methods that don‘t take a msg parameter.  For now,
        // if that‘s the case, just convert null to the empty string and move on.
        String useMsg = msg;
        if (useMsg == null) {
            useMsg = "";
        }

        // If an exeption was provided, convert that exception to a usable string and attach
        // it to the end of the msg method.
        if (tr != null) {
            msg += "\n" + Log.getStackTraceString(tr);
        }

        // This is functionally identical to Log.x(tag, useMsg);
        // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
          /**
         * 注意这里的Log是这个包下的package android.util
         */
        Log.println(priority, tag, useMsg);

        // If this isn‘t the last node in the chain, move things along.
        if (mNext != null) {
            mNext.println(priority, tag, msg, tr);
        }
    }
}

package com.example.android.common.logger;

/**
 * Basic interface for a logging system that can output to one or more targets.
 * Note that in addition to classes that will output these logs in some format,
 * one can also implement this interface over a filter and insert that in the chain,
 * such that no targets further down see certain data, or see manipulated forms of the data.
 * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
 * it received to HTML and sent it along to the next node in the chain, without printing it
 * anywhere.
 */
public interface LogNode {

    /**
     * Instructs first LogNode in the list to print the log data provided.
     * @param priority Log level of the data being logged.  Verbose, Error, etc.
     * @param tag Tag for for the log data.  Can be used to organize log statements.
     * @param msg The actual message to be logged. The actual message to be logged.
     * @param tr If an exception was thrown, this can be sent along for the logging facilities
     *           to extract and print useful information.
     */
    public void println(int priority, String tag, String msg, Throwable tr);

}

package com.example.android.common.logger;

/**
除去一些用户并不关心的的数据
 * Simple {@link LogNode} filter, removes everything except the message.
 * Useful for situations like on-screen log output where you don‘t want a lot of metadata displayed,
 * just easy-to-read message updates as they‘re happening.
 */
public class MessageOnlyLogFilter implements LogNode {

    LogNode mNext;

    /**
     * Takes the "next" LogNode as a parameter, to simplify chaining.
     *
     * @param next The next LogNode in the pipeline.
     */
    public MessageOnlyLogFilter(LogNode next) {
        mNext = next;
    }

    public MessageOnlyLogFilter() {
    }

    @Override
    public void println(int priority, String tag, String msg, Throwable tr) {
        if (mNext != null) {
            getNext().println(Log.NONE, null, msg, null);
        }
    }

    /**
     * Returns the next LogNode in the chain.
     */
    public LogNode getNext() {
        return mNext;
    }

    /**
     * Sets the LogNode data will be sent to..
     */
    public void setNext(LogNode node) {
        mNext = node;
    }

}

最终执行输出Log代码,上边各种封装类都是作为消息传递chain:

/**
展示Log的View
Simple TextView which is used to output log data received through the LogNode interface.
*/
public class LogView extends TextView implements LogNode {

    public LogView(Context context) {
        super(context);
    }

    public LogView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public LogView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * Formats the log data and prints it out to the LogView.
     * @param priority Log level of the data being logged.  Verbose, Error, etc.
     * @param tag Tag for for the log data.  Can be used to organize log statements.
     * @param msg The actual message to be logged. The actual message to be logged.
     * @param tr If an exception was thrown, this can be sent along for the logging facilities
     *           to extract and print useful information.
     */
    @Override
    public void println(int priority, String tag, String msg, Throwable tr) {

        String priorityStr = null;

        // For the purposes of this View, we want to print the priority as readable text.
        switch(priority) {
            case android.util.Log.VERBOSE:
                priorityStr = "VERBOSE";
                break;
            case android.util.Log.DEBUG:
                priorityStr = "DEBUG";
                break;
            case android.util.Log.INFO:
                priorityStr = "INFO";
                break;
            case android.util.Log.WARN:
                priorityStr = "WARN";
                break;
            case android.util.Log.ERROR:
                priorityStr = "ERROR";
                break;
            case android.util.Log.ASSERT:
                priorityStr = "ASSERT";
                break;
            default:
                break;
        }

        // Handily, the Log class has a facility for converting a stack trace into a usable string.
        String exceptionStr = null;
        if (tr != null) {
            exceptionStr = android.util.Log.getStackTraceString(tr);
        }

        // Take the priority, tag, message, and exception, and concatenate as necessary
        // into one usable line of text.
        final StringBuilder outputBuilder = new StringBuilder();

        String delimiter = "\t";
        appendIfNotNull(outputBuilder, priorityStr, delimiter);
        appendIfNotNull(outputBuilder, tag, delimiter);
        appendIfNotNull(outputBuilder, msg, delimiter);
        appendIfNotNull(outputBuilder, exceptionStr, delimiter);

        // In case this was originally called from an AsyncTask or some other off-UI thread,
        // make sure the update occurs within the UI thread.
        ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
            @Override
            public void run() {
                // Display the text we just generated within the LogView.
                appendToLog(outputBuilder.toString());
            }
        })));

        if (mNext != null) {
            mNext.println(priority, tag, msg, tr);
        }
    }

    public LogNode getNext() {
        return mNext;
    }

    public void setNext(LogNode node) {
        mNext = node;
    }

    /** Takes a string and adds to it, with a separator, if the bit to be added isn‘t null. Since
     * the logger takes so many arguments that might be null, this method helps cut out some of the
     * agonizing tedium of writing the same 3 lines over and over.
     * @param source StringBuilder containing the text to append to.
     * @param addStr The String to append
     * @param delimiter The String to separate the source and appended strings. A tab or comma,
     *                  for instance.
     * @return The fully concatenated String as a StringBuilder
     */
    private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
        if (addStr != null) {
            if (addStr.length() == 0) {
                delimiter = "";
            }

            return source.append(addStr).append(delimiter);
        }
        return source;
    }

    // The next LogNode in the chain.
    LogNode mNext;

    /** Outputs the string as a new line of log data in the LogView. */
    public void appendToLog(String s) {
        append("\n" + s);
    }

}

floatingactionbuttonbasic包代码分析:

说明:FloatingActionButton 这个View其实类似于一个CheckBox,当点击的时候记录当前的状态(选中或没选中),根据当期的状态来改变背景图片。背景图片是一个Selecter,状态改变自己会切换图片。这样就基本实现了FloatingActionButton 。但是,还没有让View悬浮起来。这个是5.0的一个新特性。及支持设置View在Z轴的位置。android:elevation这个属性就是设置Z轴位置的。当Z轴位置大于0时那么这个View就悬浮在其他View的上边了。

/**

* A Floating Action Button is a {@link android.widget.Checkable} view distinguished by a circled

* icon floating above the UI, with special motion behaviors.

* 继承自FrameLayout,实现了Checkable接口

*/

public class FloatingActionButton extends FrameLayout implements Checkable {

/**
 * Interface definition for a callback to be invoked when the checked state
 * of a compound button changes.
 */
public static interface OnCheckedChangeListener {

    /**
     * Called when the checked state of a FAB has changed.
     *
     * @param fabView   The FAB view whose state has changed.
     * @param isChecked The new checked state of buttonView.
     */
    void onCheckedChanged(FloatingActionButton fabView, boolean isChecked);
}

/**
 * An array of states.
 */
private static final int[] CHECKED_STATE_SET = {
        android.R.attr.state_checked
};

private static final String TAG = "FloatingActionButton";

// A boolean that tells if the FAB is checked or not.
private boolean mChecked;

// A listener to communicate that the FAB has changed it‘s state
private OnCheckedChangeListener mOnCheckedChangeListener;

public FloatingActionButton(Context context) {
    this(context, null, 0, 0);
}

public FloatingActionButton(Context context, AttributeSet attrs) {
    this(context, attrs, 0, 0);
}

public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
    this(context, attrs, defStyleAttr, 0);
}

public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr,
        int defStyleRes) {
    super(context, attrs, defStyleAttr);

    setClickable(true);

    // Set the outline provider for this view. The provider is given the outline which it can
    // then modify as needed. In this case we set the outline to be an oval fitting the height
    // and width.
    //给这个View设置outline provider。这个provider提供的outline是可以改变的。在这种情况下我们这支这个边框为填充高度和宽度
    setOutlineProvider(new ViewOutlineProvider() {
        @Override
        public void getOutline(View view, Outline outline) {
            outline.setOval(0, 0, getWidth(), getHeight());
        }
    });

    // Finally, enable clipping to the outline, using the provider we set above
    //最后,设置一下使得outline可以点击
    setClipToOutline(true);
}

/**
 * Sets the checked/unchecked state of the FAB.
 * @param checked
 */
public void setChecked(boolean checked) {
    // If trying to set the current state, ignore.
    if (checked == mChecked) {
        return;
    }
    mChecked = checked;

    // Now refresh the drawable state (so the icon changes)
    refreshDrawableState();

    if (mOnCheckedChangeListener != null) {
        mOnCheckedChangeListener.onCheckedChanged(this, checked);
    }
}

/**
 * Register a callback to be invoked when the checked state of this button
 * changes.
 *
 * @param listener the callback to call on checked state change
 */
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {
    mOnCheckedChangeListener = listener;
}

@Override
public boolean isChecked() {
    return mChecked;
}

@Override
public void toggle() {
    setChecked(!mChecked);
}

/**
 * Override performClick() so that we can toggle the checked state when the view is clicked
 * 当点击的时候会出发这个方法,super.performClick() 会抛出这个异常throw new RuntimeException("Stub!");打印Log
 */
@Override
public boolean performClick() {
    toggle();
    return super.performClick();
}

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    // As we have changed size, we should invalidate the outline so that is the the
    // correct size
    invalidateOutline();
}

/**
 *
 * @param extraSpace  如果不为extraSpace不为0,表示返回的int[]数组会在原始数组基础上添加额外的extraSpace个位置,在这些位置上你可以添加自己的一些额外信息
 * @return
 */
@Override
protected int[] onCreateDrawableState(int extraSpace) {
    final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
    if (isChecked()) {
        /**
         *  mergeDrawableStates专门用来在onCreateDrawableState返回的数组上添加一个额外的属性
         */
        mergeDrawableStates(drawableState, CHECKED_STATE_SET);
    }
    return drawableState;
}

}


package com.example.android.floatingactionbuttonbasic;

import com.example.android.common.logger.Log;

import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**

这个Fragment将包含俩个FloatingActionButton,并监听点击事件。使用上边的Log包下的工具输出Log信息。
 * This fragment inflates a layout with two Floating Action Buttons and acts as a listener to
 * changes on them.
 */
public class FloatingActionButtonBasicFragment extends Fragment implements FloatingActionButton.OnCheckedChangeListener{

    private final static String TAG = "FloatingActionButtonBasicFragment";

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.fab_layout, container, false);

        // Make this {@link Fragment} listen for changes in both FABs.
        FloatingActionButton fab1 = (FloatingActionButton) rootView.findViewById(R.id.fab_1);
        fab1.setOnCheckedChangeListener(this);
        FloatingActionButton fab2 = (FloatingActionButton) rootView.findViewById(R.id.fab_2);
        fab2.setOnCheckedChangeListener(this);
        return rootView;
    }

    @Override
    public void onCheckedChanged(FloatingActionButton fabView, boolean isChecked) {
        // When a FAB is toggled, log the action.
        switch (fabView.getId()){
            case R.id.fab_1:
                Log.d(TAG, String.format("FAB 1 was %s.", isChecked ? "checked" : "unchecked"));
                break;
            case R.id.fab_2:
                Log.d(TAG, String.format("FAB 2 was %s.", isChecked ? "checked" : "unchecked"));
                break;
            default:
                break;
        }
    }
}

使用:

package com.example.android.floatingactionbuttonbasic;

import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ViewAnimator;

import com.example.android.common.activities.SampleActivityBase;
import com.example.android.common.logger.Log;
import com.example.android.common.logger.LogFragment;
import com.example.android.common.logger.LogWrapper;
import com.example.android.common.logger.MessageOnlyLogFilter;

/**
 * A simple launcher activity containing a summary sample description, sample log and a custom
 * {@link android.support.v4.app.Fragment} which can display a view.
 * <p/>
 * For devices with displays with a width of 720dp or greater, the sample log is always visible,
 * on other devices it‘s visibility is controlled by an item on the Action Bar.
 */
public class MainActivity extends SampleActivityBase {

    public static final String TAG = "MainActivity";

    // Whether the Log Fragment is currently shown
    private boolean mLogShown;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            FloatingActionButtonBasicFragment fragment = new FloatingActionButtonBasicFragment();
            transaction.replace(R.id.sample_content_fragment, fragment);
            transaction.commit();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
        logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
        logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);

        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_toggle_log:
                mLogShown = !mLogShown;
                ViewAnimator output = (ViewAnimator) findViewById(R.id.sample_output);
                if (mLogShown) {
                    output.setDisplayedChild(1);
                } else {
                    output.setDisplayedChild(0);
                }
                supportInvalidateOptionsMenu();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /**
     * Create a chain of targets that will receive log data
     * 初始化Log工具
     */
    @Override
    public void initializeLogging() {
        //封装android底层log框架
        LogWrapper logWrapper = new LogWrapper();
        // Using Log, front-end to the logging chain, emulates android.util.log method signatures.
        /**
         * Log的消息传递是依据一个链路依次传递的,Log传递到LogWrapper,LogWrapper传递到MessageOnlyLogFilter,MessageOnlyLogFilter传递到LogFragment
         */

        Log.setLogNode(logWrapper);

        // Filter strips out everything except the message text.
        MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter();
        logWrapper.setNext(msgFilter);

        // On screen logging via a fragment with a TextView.
        LogFragment logFragment = (LogFragment) getSupportFragmentManager()
                .findFragmentById(R.id.log_fragment);
        msgFilter.setNext(logFragment.getLogView());
        Log.i(TAG, "Ready");
    }
}

布局文件

<?xml version="1.0" encoding="UTF-8"?>
<!--
 Copyright 2014, The Android Open Source 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
 这里还涉及到一些动画,这里不再说明。
-->
<FrameLayout android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="match_parent" >
<!--elevation  Z轴方向的距离  这个属性是android5.0系统支持的-->
    <com.example.android.floatingactionbuttonbasic.FloatingActionButton
            android:id="@+id/fab_1"
            android:layout_width="@dimen/fab_size"
            android:layout_height="@dimen/fab_size"
            android:layout_marginTop="16dp"
            android:elevation="@dimen/fab_elevation"
            android:background="@drawable/fab_background"
            android:stateListAnimator="@animator/fab_anim"
            android:layout_gravity="center_horizontal">
        <!--duplicateParentState表示当前View的DrawableState直接从其父View获取,而不是从他自己获取-->
        <ImageView
                android:layout_width="@dimen/fab_icon_size"
                android:layout_height="@dimen/fab_icon_size"
                android:src="@drawable/fab_icons"
                android:layout_gravity="center"

                android:duplicateParentState="true"/>

    </com.example.android.floatingactionbuttonbasic.FloatingActionButton>

    <com.example.android.floatingactionbuttonbasic.FloatingActionButton
            android:id="@+id/fab_2"
            android:layout_width="@dimen/fab_size_small"
            android:layout_height="@dimen/fab_size_small"
            android:layout_marginTop="128dp"
            android:elevation="@dimen/fab_elevation"
            android:background="@drawable/fab_background"
            android:stateListAnimator="@animator/fab_anim"
            android:layout_gravity="center_horizontal">

        <ImageView
                android:layout_width="@dimen/fab_icon_size"
                android:layout_height="@dimen/fab_icon_size"
                android:src="@drawable/fab_icons"
                android:layout_gravity="center"
                android:duplicateParentState="true"/>

    </com.example.android.floatingactionbuttonbasic.FloatingActionButton>
</FrameLayout>

XML文件的预览效果:

代码下载需要5.0系统

RecyclerView

效果图

代码分析:

Log输出同FloatingActionButton完全相同。这里不再分析。

View的创建过程分析:



package com.example.android.recyclerview;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RadioButton;

/**
 * 使用Fragment加载一个RecyclerView
 * Demonstrates the use of {@link RecyclerView} with a {@link LinearLayoutManager} and a
 * {@link GridLayoutManager}.
 */
public class RecyclerViewFragment extends Fragment {

    private static final String TAG = "RecyclerViewFragment";
    private static final String KEY_LAYOUT_MANAGER = "layoutManager";
    private static final int SPAN_COUNT = 2;
    private static final int DATASET_COUNT = 60;

    private enum LayoutManagerType {
        GRID_LAYOUT_MANAGER,
        LINEAR_LAYOUT_MANAGER
    }

    protected LayoutManagerType mCurrentLayoutManagerType;

    protected RadioButton mLinearLayoutRadioButton;
    protected RadioButton mGridLayoutRadioButton;

    protected RecyclerView mRecyclerView;
    protected CustomAdapter mAdapter;
    protected RecyclerView.LayoutManager mLayoutManager;
    protected String[] mDataset;

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

        // Initialize dataset, this data would usually come from a local content provider or
        // remote server.
        //初始化数据
        initDataset();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.recycler_view_frag, container, false);
        rootView.setTag(TAG);

        // BEGIN_INCLUDE(initializeRecyclerView)
        mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerView);

        // LinearLayoutManager is used here, this will layout the elements in a similar fashion
        // to the way ListView would layout elements. The RecyclerView.LayoutManager defines how
        // elements are laid out.
        //使用LinearLayoutManager来初始化RecyclerView.LayoutManager,RecyclerView.LayoutManager决定recyclerView如何布局
        mLayoutManager = new LinearLayoutManager(getActivity());

        mCurrentLayoutManagerType = LayoutManagerType.LINEAR_LAYOUT_MANAGER;

        if (savedInstanceState != null) {
            // Restore saved layout manager type.
            mCurrentLayoutManagerType = (LayoutManagerType) savedInstanceState
                    .getSerializable(KEY_LAYOUT_MANAGER);
        }
        setRecyclerViewLayoutManager(mCurrentLayoutManagerType);

        mAdapter = new CustomAdapter(mDataset);
        // .RecyclerView设置适配器
        mRecyclerView.setAdapter(mAdapter);
        // END_INCLUDE(initializeRecyclerView)
        //改变布局方式
        mLinearLayoutRadioButton = (RadioButton) rootView.findViewById(R.id.linear_layout_rb);
        mLinearLayoutRadioButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setRecyclerViewLayoutManager(LayoutManagerType.LINEAR_LAYOUT_MANAGER);
            }
        });

        mGridLayoutRadioButton = (RadioButton) rootView.findViewById(R.id.grid_layout_rb);
        mGridLayoutRadioButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                setRecyclerViewLayoutManager(LayoutManagerType.GRID_LAYOUT_MANAGER);
            }
        });

        return rootView;
    }

    /**
     * Set RecyclerView‘s LayoutManager to the one given.
     * 设置recyclerView的布局管理
     *
     * @param layoutManagerType Type of layout manager to switch to.
     */
    public void setRecyclerViewLayoutManager(LayoutManagerType layoutManagerType) {
        int scrollPosition = 0;

        // If a layout manager has already been set, get current scroll position.
        //如果当前的布局管理已近设置了,那么获得当前滑动的位置
        if (mRecyclerView.getLayoutManager() != null) {
            scrollPosition = ((LinearLayoutManager) mRecyclerView.getLayoutManager())
                    .findFirstCompletelyVisibleItemPosition();
        }
        //设置布局管理
        switch (layoutManagerType) {
            case GRID_LAYOUT_MANAGER:
                mLayoutManager = new GridLayoutManager(getActivity(), SPAN_COUNT);
                mCurrentLayoutManagerType = LayoutManagerType.GRID_LAYOUT_MANAGER;
                break;
            case LINEAR_LAYOUT_MANAGER:
                mLayoutManager = new LinearLayoutManager(getActivity());
                mCurrentLayoutManagerType = LayoutManagerType.LINEAR_LAYOUT_MANAGER;
                break;
            default:
                mLayoutManager = new LinearLayoutManager(getActivity());
                mCurrentLayoutManagerType = LayoutManagerType.LINEAR_LAYOUT_MANAGER;
        }
        //滑动到上次的位置
        mRecyclerView.setLayoutManager(mLayoutManager);
        mRecyclerView.scrollToPosition(scrollPosition);
    }

    @Override
    public void onSaveInstanceState(Bundle savedInstanceState) {
        // Save currently selected layout manager.
        //保存当前的布局管理对象
        savedInstanceState.putSerializable(KEY_LAYOUT_MANAGER, mCurrentLayoutManagerType);
        super.onSaveInstanceState(savedInstanceState);
    }

    /**
     * Generates Strings for RecyclerView‘s adapter. This data would usually come
     * from a local content provider or remote server.
     * 生成数据
     */
    private void initDataset() {
        mDataset = new String[DATASET_COUNT];
        for (int i = 0; i < DATASET_COUNT; i++) {
            mDataset[i] = "This is element #" + i;
        }
    }
}

布局文件

<?xml version="1.0" encoding="UTF-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <RadioGroup
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal"
        android:orientation="horizontal"
        android:checkedButton="@+id/linear_layout_rb">
        <RadioButton android:id="@+id/linear_layout_rb"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/linear_layout_manager"/>
        <RadioButton android:id="@+id/grid_layout_rb"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/grid_layout_manager"/>
    </RadioGroup>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

适配器:



package com.example.android.recyclerview;

import com.example.android.common.logger.Log;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * Provide views to RecyclerView with data from mDataSet.
 * 自定义的RecyclerView数据适配器
 */
public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
    private static final String TAG = "CustomAdapter";

    private String[] mDataSet;

    // BEGIN_INCLUDE(recyclerViewSampleViewHolder)
    /**
     * Provide a reference to the type of views that you are using (custom ViewHolder)
     * 提供一个指向自定义View的应用
     */
    public static class ViewHolder extends RecyclerView.ViewHolder {
        /**
         * 这里不只可以是textView还可以是其他的View
         */
        private final TextView textView;

        public ViewHolder(View v) {
            super(v);
            // Define click listener for the ViewHolder‘s View.
            //定义每一个View的点击事件
            v.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.d(TAG, "Element " + getPosition() + " clicked.");
                }
            });
            textView = (TextView) v.findViewById(R.id.textView);
        }

        public TextView getTextView() {
            return textView;
        }
    }
    // END_INCLUDE(recyclerViewSampleViewHolder)

    /**
     * Initialize the dataset of the Adapter.
     *
     * @param dataSet String[] containing the data to populate views to be used by RecyclerView.
     */
    public CustomAdapter(String[] dataSet) {
        mDataSet = dataSet;
    }

    // BEGIN_INCLUDE(recyclerViewOnCreateViewHolder)
    // Create new views (invoked by the layout manager)
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        // Create a new view.创建一个View
        View v = LayoutInflater.from(viewGroup.getContext())
                .inflate(R.layout.text_row_item, viewGroup, false);

        return new ViewHolder(v);
    }
    // END_INCLUDE(recyclerViewOnCreateViewHolder)

    // BEGIN_INCLUDE(recyclerViewOnBindViewHolder)
    // Replace the contents of a view (invoked by the layout manager)
    //由layout manager调用,替换ViewHolder的内容.在滑动的时候会不断调用这个方法来跟新视图
    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position) {
        Log.d(TAG, "Element " + position + " set.");

        // Get element from your dataset at this position and replace the contents of the view
        // with that element
        //这里得到的是ViewHolder创建时传递进去的可以自定义的View
        viewHolder.getTextView().setText(mDataSet[position]);
    }
    // END_INCLUDE(recyclerViewOnBindViewHolder)

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return mDataSet.length;
    }
}

说明:为什么要使用RecyclerView

从效果上说,RecyclerView和ListView是差不多的,都是列表。

①但是RecyclerViwe支持多种布局方式,可以通过设置不同的布局方式实现不同效果,这一点比较灵活。

②直接省去了当初的convertView.setTag(holder)和convertView.getTag()这些繁琐的步骤。

因为RecyclerView帮我们封装了Holder,所以我们自己写的ViewHolder就需要继承RecyclerView.ViewHolder,只有这样,RecyclerView才能帮你去管理这个ViewHolder类。

③以前的getView方法的渲染数据部分的代码相当于onBindViewHolder(),所以如果调用adapter.notifyDataSetChanged()方法,应该也会重新调用onBindViewHolder()方法才对吧?实验后,果然如此!

除了adapter.notifyDataSetChanged()这个方法之外,新的Adapter还提供了其他的方法,如下:

public final void notifyDataSetChanged()
        public final void notifyItemChanged(int position)
        public final void notifyItemRangeChanged(int positionStart, int itemCount)
        public final void notifyItemInserted(int position)
        public final void notifyItemMoved(int fromPosition, int toPosition)
        public final void notifyItemRangeInserted(int positionStart, int itemCount)
        public final void notifyItemRemoved(int position)
        public final void notifyItemRangeRemoved(int positionStart, int itemCount)

第一个方法没什么好讲的,跟以前一样。

notifyItemChanged(int position),position数据发生了改变,那调用这个方法,就会回调对应position的onBindViewHolder()方法了,当然,因为ViewHolder是复用的,所以如果position在当前屏幕以外,也就不会回调了,因为没有意义,下次position滚动会当前屏幕以内的时候同样会调用onBindViewHolder()方法刷新数据了。其他的方法也是同样的道理。

public final void notifyItemRangeChanged(int positionStart, int itemCount),顾名思义,可以刷新从positionStart开始itemCount数量的item了(这里的刷新指回调onBindViewHolder()方法)。

public final void notifyItemInserted(int position),这个方法是在第position位置被插入了一条数据的时候可以使用这个方法刷新,注意这个方法调用后会有插入的动画,这个动画可以使用默认的,也可以自己定义。

public final void notifyItemMoved(int fromPosition, int toPosition),这个方法是从fromPosition移动到toPosition为止的时候可以使用这个方法刷新

public final void notifyItemRangeInserted(int positionStart, int itemCount),显然是批量添加。

public final void notifyItemRemoved(int position),第position个被删除的时候刷新,同样会有动画。

public final void notifyItemRangeRemoved(int positionStart, int itemCount),批量删除。

源码下载地址

ActivitySceneTransitionBasic(Activity场景切换)

时间: 2024-10-18 06:52:23

Android V7包学习笔记更新中.....的相关文章

[Android学习笔记]ListView中含有Button导致无法响应onItemClick回调的解决办法

转自:http://www.cnblogs.com/eyu8874521/archive/2012/10/17/2727882.html 问题描述: 当ListView的Item中的控件只是一些展示类控件时(比如TextView),注册ListView的监听setOnItemClickListener之后,当点击Item时候会触发onItemClick回调. 但是,当Item中存在Button(继承于Button)的控件时,onItemClick回调不会被触发. 解决方案: 在Item的布局文件

Samurai Framework 学习笔记--samurai中的宏魔法(待更新)

Samurai Framework 学习笔记–samurai中的宏魔法 文件 Samurai_Predefine.h Samurai里的一些预设宏 // 这3个宏是在定义属性 @prop_assign( NSInteger, page IN)的时候标记这个数据流的方向时用的. #define IN #define OUT #define INOUT // 函数属性限定符: __attribute__((unused)) 这个限定符属性禁止编译器在未引用该函数时生成警告 // 这里先用__unus

android 浮动窗口学习笔记及个人理解(仿360手机助手)

非常感谢原文作者 http://blog.csdn.net/guolin_blog/article/details/8689140 经自己理解 程序运行界面如下图: 1.程序入口界面 2.小浮动窗口 3.大浮动窗口 由上图可看出,可以看出我们基本需要: 1.一个主Activity 2.小浮动窗口view界面 3.大浮动窗口view界面 对于浮动窗口的管理我们还需要 4.一个Service(在后台监控管理浮动窗口的状态) 5.窗口管理类(创建/消除浮动窗口) 代码: package com.ww.

[Android游戏开发学习笔记]View和SurfaceView

本文为阅读http://blog.csdn.net/xiaominghimi/article/details/6089594的笔记. 在Android游戏中充当主要角色的,除了控制类就是显示类.而在Android中涉及到显示的是View类,及继承自它的SurfaceView类和SurfaceView的其他子类等. 这里先只说View和SurfaceView.SurfaceView的直接子类有GLSurfaceView和VideoView,可以看出GL和视频播放以及CAmera摄像头一般均使用Su

Android Socket编程学习笔记

通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄.在Internet上的主机一般运行了多个服务软件,同时提供几种服务.每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务. 网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket.Socket通常用来实现客户方和服务方的连接.Socket是TCP/IP协议的一个十分流行的编程界面,一个Socket由一个IP地址和一个端口号唯一确定. 在java中,Socke

AspectJ学习笔记2-Eclipse中AspectJ插件AJDT的正确安装方法

接着之前一篇日志.这个事情也挺无语的,简单记录一下. 在这里:http://www.eclipse.org/ajdt/ 可以下载最新的Eclipse Plugin,下载解压之后,一般来说,直接把解压后文件夹下的features和plugins放到Eclipse的文件夹下就行了.不过我这样做以后,启动Eclipse,发现没什么作用.才参考网上有人介绍的第二种方法,也就是Help--Install New Software--Add--Local这种方式选择刚才的解压文件夹,但是这样操作以后会报像下

Android自定义View学习笔记04

Android自定义View学习笔记04 好长时间没有写相关的博客了,前几周在帮学姐做毕设,所以博客方面有些耽误.过程中写了一个类似wp的磁贴的view,想再写个配套的layout,所以昨天看了一下自定义viewGroup的相关知识-晚上睡觉想了一下可行性不是很高-代码量还不如直接自己在xml上写来得快,速度上也是个问题.今天看了一下张鸿洋老师的Android 自定义View (三) 圆环交替 等待效果这篇博文,再加上前一段时间看到的一幅图,结合之前写的一个圆形imageView的实现博文And

Android自定义view学习笔记02

Android自定义view学习笔记02 本文代码来自于张鸿洋老师的博客之Android 自定义View (二) 进阶 学习笔记,对代码进行些许修改,并补充一些在coding过程中遇到的问题.学习的新东西. 相关代码 //CustomImageView.java package mmrx.com.myuserdefinedview.textview; import android.content.Context; import android.content.res.TypedArray; im

《Cocos2d-x游戏开发实战精解》学习笔记3--在Cocos2d-x中播放声音

<Cocos2d-x游戏开发实战精解>学习笔记1--在Cocos2d中显示图像 <Cocos2d-x游戏开发实战精解>学习笔记2--在Cocos2d-x中显示一行文字 之前的内容主要都是介绍如何在屏幕上显示图像,事实上除了图像之外,音乐的播放也可以被理解为一种显示的方式,本节将学习在Cocos2d-x中播放声音的方法. (1)在HelloWorld.h中对HelloWorld类进行如下定义: class HelloWorld : public Cocos2d::Layer { pu