Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android V7包學習筆記更新中.....

Android V7包學習筆記更新中.....

編輯:關於android開發

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.
 *
 * 

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.

*/ 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.
 * 

* 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"); } }

布局文件



<frameLayout android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="match_parent" >

    
        
        

    


    

        

    
</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;
        }
    }
}

布局文件





    
        
        
    

    

適配器:



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 {
    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場景切換)

要求:5.0系統
這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述
MainActivity

package com.example.android.activityscenetransitionbasic;

import com.squareup.picasso.Picasso;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ActivityOptionsCompat;
import android.support.v4.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import android.widget.TextView;

/**
 * Our main Activity in this sample. Displays a grid of items which an image and title. When the
 * user clicks on an item, {@link DetailActivity} is launched, using the Activity Scene Transitions
 * framework to animatedly do so.
 * 

* 當用戶點擊Gridview的時候,會使用Activity Scene Transitions framework(activity 場景切換框架)動畫啟動DetailActivity。 */ public class MainActivity extends Activity implements AdapterView.OnItemClickListener { private GridView mGridView; private GridAdapter mAdapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.grid); // Setup the GridView and set the adapter mGridView = (GridView) findViewById(R.id.grid); mGridView.setOnItemClickListener(this); mAdapter = new GridAdapter(); mGridView.setAdapter(mAdapter); } /** * Called when an item in the {@link android.widget.GridView} is clicked. Here will launch the * {@link DetailActivity}, using the Scene Transition animation functionality. */ @Override public void onItemClick(AdapterView adapterView, View view, int position, long id) { Item item = (Item) adapterView.getItemAtPosition(position); // Construct an Intent as normal常見一個普通的Intent Intent intent = new Intent(this, DetailActivity.class); intent.putExtra(DetailActivity.EXTRA_PARAM_ID, item.getId()); // BEGIN_INCLUDE(start_activity) /** * Now create an {@link android.app.ActivityOptions} instance using the * {@link ActivityOptionsCompat#makeSceneTransitionAnimation(Activity, Pair[])} factory * method. * * 使用ActivityOptionsCompat#makeSceneTransitionAnimation(Activity, Pair[])工廠方法來創建一個ActivityOptions * 實例 */ ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation( this, // Now we provide a list of Pair items which contain the view we can transitioning // from, and the name of the view it is transitioning to, in the launched activity new Pair(view.findViewById(R.id.imageview_item), DetailActivity.VIEW_NAME_HEADER_IMAGE), new Pair(view.findViewById(R.id.textview_name), DetailActivity.VIEW_NAME_HEADER_TITLE)); // Now we can start the Activity, providing the activity options as a bundle ActivityCompat.startActivity(this, intent, activityOptions.toBundle()); // END_INCLUDE(start_activity) } /** * {@link android.widget.BaseAdapter} which displays items. */ private class GridAdapter extends BaseAdapter { @Override public int getCount() { return Item.ITEMS.length; } @Override public Item getItem(int position) { return Item.ITEMS[position]; } @Override public long getItemId(int position) { return getItem(position).getId(); } @Override public View getView(int position, View view, ViewGroup viewGroup) { if (view == null) { view = getLayoutInflater().inflate(R.layout.grid_item, viewGroup, false); } final Item item = getItem(position); // Load the thumbnail image加載縮略圖 ImageView image = (ImageView) view.findViewById(R.id.imageview_item); Picasso.with(image.getContext()).load(item.getThumbnailUrl()).into(image); // Set the TextView's contents TextView name = (TextView) view.findViewById(R.id.textview_name); name.setText(item.getName()); return view; } } }

數據:

/*
 * Copyright (C) 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.
 */

package com.example.android.activityscenetransitionbasic;

/**
 * Represents an Item in our application. Each item has a name, id, full size image url and
 * thumbnail url.
 */
public class Item {
    //大圖網址
    private static final String LARGE_BASE_URL = "http://storage.googleapis.com/androiddevelopers/sample_data/activity_transition/large/";
    //縮略圖網址
    private static final String THUMB_BASE_URL = "http://storage.googleapis.com/androiddevelopers/sample_data/activity_transition/thumbs/";

    public static Item[] ITEMS = new Item[]{
            new Item("Flying in the Light", "Romain Guy", "flying_in_the_light.jpg"),
            new Item("Caterpillar", "Romain Guy", "caterpillar.jpg"),
            new Item("Look Me in the Eye", "Romain Guy", "look_me_in_the_eye.jpg"),
            new Item("Flamingo", "Romain Guy", "flamingo.jpg"),
            new Item("Rainbow", "Romain Guy", "rainbow.jpg"),
            new Item("Over there", "Romain Guy", "over_there.jpg"),
            new Item("Jelly Fish 2", "Romain Guy", "jelly_fish_2.jpg"),
            new Item("Lone Pine Sunset", "Romain Guy", "lone_pine_sunset.jpg"),
    };

    public static Item getItem(int id) {
        for (Item item : ITEMS) {
            if (item.getId() == id) {
                return item;
            }
        }
        return null;
    }

    private final String mName;
    private final String mAuthor;
    private final String mFileName;

    Item(String name, String author, String fileName) {
        mName = name;
        mAuthor = author;
        mFileName = fileName;
    }

    public int getId() {
        return mName.hashCode() + mFileName.hashCode();
    }

    public String getAuthor() {
        return mAuthor;
    }

    public String getName() {
        return mName;
    }

    public String getPhotoUrl() {
        return LARGE_BASE_URL + mFileName;
    }

    public String getThumbnailUrl() {
        return THUMB_BASE_URL + mFileName;
    }

}

跳轉過來的第二個Activity



package com.example.android.activityscenetransitionbasic;

import com.squareup.picasso.Picasso;

import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.view.ViewCompat;
import android.transition.Transition;
import android.widget.ImageView;
import android.widget.TextView;

/**
 * Our secondary Activity which is launched from {@link MainActivity}. Has a simple detail UI
 * which has a large banner image, title and body text.
 */
public class DetailActivity extends Activity {

    // Extra name for the ID parameter
    public static final String EXTRA_PARAM_ID = "detail:_id";

    // View name of the header image. Used for activity scene transitions
    public static final String VIEW_NAME_HEADER_IMAGE = "detail:header:image";

    // View name of the header title. Used for activity scene transitions
    public static final String VIEW_NAME_HEADER_TITLE = "detail:header:title";

    private ImageView mHeaderImageView;
    private TextView mHeaderTitle;

    private Item mItem;

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

        // Retrieve the correct Item instance, using the ID provided in the Intent
        //接收上一個Activity中傳遞過來的值
        mItem = Item.getItem(getIntent().getIntExtra(EXTRA_PARAM_ID, 0));

        mHeaderImageView = (ImageView) findViewById(R.id.imageview_header);
        mHeaderTitle = (TextView) findViewById(R.id.textview_title);

        // BEGIN_INCLUDE(detail_set_view_name)
        /**
         * Set the name of the view's which will be transition to, using the static values above.
         * This could be done in the layout XML, but exposing it via static variables allows easy
         * querying from other Activities
         * 使用上邊定義的常亮設置前一個Activity中的View對應當前Activity中的那個View
         *因為場景切換其實是這倆個Activity中的場景有連貫性,所以在2個activity切換過程中向做到View也看起來是連貫的
         * 切換過來的效果,所以要做這樣的對應關系。
         */
        ViewCompat.setTransitionName(mHeaderImageView, VIEW_NAME_HEADER_IMAGE);
        ViewCompat.setTransitionName(mHeaderTitle, VIEW_NAME_HEADER_TITLE);
        // END_INCLUDE(detail_set_view_name)

        loadItem();
    }

    private void loadItem() {
        // Set the title TextView to the item's name and author
        mHeaderTitle.setText(getString(R.string.image_header, mItem.getName(), mItem.getAuthor()));
        //如果當前系統是5.0以上的系統並添加了場景切換效果的監聽事件
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && addTransitionListener()) {
            // If we're running on Lollipop and we have added a listener to the shared element
            // transition, load the thumbnail. The listener will load the full-size image when
            // the transition is complete.

            loadThumbnail();
        } else {
            // If all other cases we should just load the full-size image now
            loadFullSizeImage();
        }
    }

    /**
     * Load the item's thumbnail image into our {@link ImageView}.
     */
    private void loadThumbnail() {
        Picasso.with(mHeaderImageView.getContext())
                .load(mItem.getThumbnailUrl())
                .noFade()
                .into(mHeaderImageView);
    }

    /**
     * Load the item's full-size image into our {@link ImageView}.
     */
    private void loadFullSizeImage() {
        Picasso.with(mHeaderImageView.getContext())
                .load(mItem.getPhotoUrl())
                .noFade()
                .noPlaceholder()
                .into(mHeaderImageView);
    }

    /**
     * Try and add a {@link Transition.TransitionListener} to the entering shared element
     * {@link Transition}. We do this so that we can load the full-size image after the transition
     * has completed.
     *
     * @return true if we were successful in adding a listener to the enter transition
     */
    private boolean addTransitionListener() {
        //PAI 21
        final Transition transition = getWindow().getSharedElementEnterTransition();

        if (transition != null) {
            // There is an entering shared element transition so add a listener to it
            transition.addListener(new Transition.TransitionListener() {
                @Override
                public void onTransitionEnd(Transition transition) {
                    // As the transition has ended, we can now load the full-size image
                    loadFullSizeImage();

                    // Make sure we remove ourselves as a listener
                    transition.removeListener(this);
                }

                @Override
                public void onTransitionStart(Transition transition) {
                    // No-op
                }

                @Override
                public void onTransitionCancel(Transition transition) {
                    // Make sure we remove ourselves as a listener
                    transition.removeListener(this);
                }

                @Override
                public void onTransitionPause(Transition transition) {
                    // No-op
                }

                @Override
                public void onTransitionResume(Transition transition) {
                    // No-op
                }
            });
            return true;
        }

        // If we reach here then we have not added a listener
        return false;
    }

}

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved