Android实例剖析笔记(四)

 NoteEditor深入分析

首先来弄清楚“日志编辑“的状态转换,通过上篇文章的 方法来做下面这样一个实验,首先进入“日志编辑“时会触发onCreate和onResume,然后用户通过Option Menu选择”Edit title”后,会触发onSaveInstanceState和onPause,最后,用户回到编辑界面,则再次触发onResume。

最终通过LogCat可以得到下图:

那么下面就按照上述顺序对此类进行剖析。首先是onCreate方法,一开始先获取导致进入“日志编辑”界面的intent,分析其操作类型可得知是“编辑日志”还是“新增日志”。

       final Intent intent = getIntent();
// Do some setup based on the action being performed.
final String action = intent.getAction();

若是“编辑日志”,则设置当前状态为“编辑”,并保存待编辑日志的URI.

             mState = STATE_EDIT;
mUri = intent.getData();

若是“新增日志”,则设置当前状态为“新增”,并通过content provider向数据库中新增一个“空白日志”,后者返回“空白日志”的URI.

          mState = STATE_INSERT;
mUri = getContentResolver().insert(intent.getData(), null);

然后不管是“编辑”或“新增”,都需要从数据库中读取日志信息(当然,若是“新增”,读出来的肯定是空数据)。

mCursor = managedQuery(mUri, PROJECTION, null, null, null);

最后,类似于web应用中使用的Session,这里也将日志文本保存在InstanceState中,因此,若此activity的实例此前是处于stop状态,则我们可以从它那取出它原本的文本数据.

        if (savedInstanceState != null)
{
mOriginalContent = savedInstanceState.getString(ORIGINAL_CONTENT);
}

第二个来分析onResume函数,首先把游标置于第一行(也只有一行)

            mCursor.moveToFirst();

然后取出“正文”字段,这时有一个比较有趣的技巧,“设置文本”并不是调用 setText,而是调用的setTextKeepState,后者相对于前者有一个优点,就是当界面此前stop掉,现在重新resume回来,那么此 前光标所在位置仍然得以保存。而若使用setText,则光标会重置到行首。

             String note = mCursor.getString(COLUMN_INDEX_NOTE);
mText.setTextKeepState(note);

最后,将当前编辑的正文保存到一个字符串变量中,用于当activity被暂停时使用。

            if (mOriginalContent == null)
{
mOriginalContent = note;
}

通过前面的图可以得知,activity被暂停时,首先调用的是onSaveInstanceState函数。

outState.putString(ORIGINAL_CONTENT, mOriginalContent);

这里就仅仅将当前正编辑的正文保存到InstanceState中(类似于Session)。最后来看onPause函数,这里首先要考虑的是若activity正要关闭,并且编辑区没有正文,则将此日志删除。

            if (isFinishing() && (length == 0) && !mNoteOnly)
{
setResult(RESULT_CANCELED);
deleteNote();
}

否则的话,就更新日志信息

                ContentValues values = new ContentValues();
if (!mNoteOnly)
{
values.put(Notes.MODIFIED_DATE, System.currentTimeMillis());
if (mState == STATE_INSERT)
{
String title = text.substring(0, Math.min(30, length));
if (length > 30)
{
int lastSpace = title.lastIndexOf(‘ ‘);
if (lastSpace > 0)
{
title = title.substring(0, lastSpace);
}
}
values.put(Notes.TITLE, title);
}
}
values.put(Notes.NOTE, text);
getContentResolver().update(mUri, values, null, null);
}
}

在生成Option Menu的函数onCreateOptionsMenu中,我们再一次看到下面这段熟悉的代码了:

Intent intent = new Intent(null, getIntent().getData());
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0,
new ComponentName(this, NoteEditor.class), null, intent, 0, null);

这种生成动态菜单的机制在Android实例剖析笔记(二)这 篇文章中已经介绍过了,就不赘述了。最后,来看下放弃日志和删除日志的实现,由于还没有接触到底层的content provider,这里都是通过getContentResolver()提供的update,delete,insert来向底层的content provider发出请求,由后者完成实际的数据库操作。

    private final void cancelNote()
{
if (mCursor != null)
{
if (mState == STATE_EDIT)
{
// Put the original note text back into the database
mCursor.close();
mCursor = null;
ContentValues values = new ContentValues();
values.put(Notes.NOTE, mOriginalContent);
getContentResolver().update(mUri, values, null, null);
}
else if (mState == STATE_INSERT)
{
// We inserted an empty note, make sure to delete it
deleteNote();
}
}
setResult(RESULT_CANCELED);
finish();
}
private final void deleteNote()
{
if (mCursor != null)
{
mCursor.close();
mCursor = null;
getContentResolver().delete(mUri, null, null);
mText.setText(“”);
}
}

  剖析NotePadProvider

NotePadProvider就是所谓的content provider,它继承自android.content.ContentProvider,也是负责数据库层的核心类,主要提供五个功能:

1)查询数据

2)修改数据

3)添加数据

4)删除数据

5)返回数据类型

这五个功能分别对应下述五个可以重载的方法:

public int delete(Uri uri, String selection, String[] selectionArgs)
{
return 0;
}
public String getType(Uri uri)
{
return null;
}
public Uri insert(Uri uri, ContentValues values)
{
return null;
}
public boolean onCreate()
{
return false;
}
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder)
{
return null;
}
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs)
{
return 0;
}

这些都要你自己实现,不同的实现就是对应不同的content-provider。但是activity使用content-provider不是直接创建一个对象,然后调用这些具体方法。

而是调用managedQuery,getContentResolver().delete,update等来实现,这些函数其实是先找到符合条 件的content-provider,然后再调用具体content-provider的函数来实现,那又是怎么找到content- provider,就是通过uri中的authority来找到content-provider,这些都是通过系统完成,应用程序不用操心,这样就达到 了有效地隔离应用和内容提供者的具体实现的目的。

有了以上初步知识后,我们来看NotePadProvider是如何为上层提供数据库层支持的。下面这三个字段指明了数据库名称,数据库版本,数据表名称。

private static final String DATABASE_NAME = “note_pad.db”;
private static final int DATABASE_VERSION = 2;
private static final String NOTES_TABLE_NAME = “notes”;

实际的数据库操作其实都是通过一个私有静态类DatabaseHelper实现的,其构造函数负责创建指定名称和版本的数据库,onCreate函数则创建指定名称和各个数据域的数据表(就是简单的建表SQL语句)。onUpgrade负责删除数据表,再重新建表。

private static class DatabaseHelper extends SQLiteOpenHelper
{
DatabaseHelper(Context context)
{
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db)
{
db.execSQL(“CREATE TABLE ” + NOTES_TABLE_NAME + ” (”
+ Notes._ID + ” INTEGER PRIMARY KEY,”
+ Notes.TITLE + ” TEXT,”
+ Notes.NOTE + ” TEXT,”
+ Notes.CREATED_DATE + ” INTEGER,”
+ Notes.MODIFIED_DATE + ” INTEGER”
+ “);”);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
Log.w(TAG, “Upgrading database from version ” + oldVersion + ” to ”
+ newVersion + “, which will destroy all old data”);
db.execSQL(“DROP TABLE IF EXISTS notes”);
onCreate(db);
}
}

Android实例剖析笔记(一)这篇文章中我们已经见识到了getType函数的用处了,也正是通过它的解析,才能区分开到底是对全部日志还是对某一条日志进行操作。

public String getType(Uri uri)
{
switch (sUriMatcher.match(uri))
{
case NOTES:
return Notes.CONTENT_TYPE;
case NOTE_ID:
return Notes.CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException(“Unknown URI ” + uri);
}
}

上面的sUriMatcher.match是用来检测uri是否能够被处理,而sUriMatcher.match(uri)返回值其实是由下述语句决定的。

        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(NotePad.AUTHORITY, “notes”, NOTES);
sUriMatcher.addURI(NotePad.AUTHORITY, “notes/#”, NOTE_ID);

sNotesProjectionMap这个私有字段是用来在上层应用使用的字段和底层数据库字段之间建立映射关系的,当然,这个程序里两处对应的字段都是一样(但并不需要一样)。

private static HashMap<String, String> sNotesProjectionMap;
static
{
sNotesProjectionMap = new HashMap<String, String>();
sNotesProjectionMap.put(Notes._ID, Notes._ID);
sNotesProjectionMap.put(Notes.TITLE, Notes.TITLE);
sNotesProjectionMap.put(Notes.NOTE, Notes.NOTE);
sNotesProjectionMap.put(Notes.CREATED_DATE, Notes.CREATED_DATE);
sNotesProjectionMap.put(Notes.MODIFIED_DATE, Notes.MODIFIED_DATE);
}

数据库的增,删,改,查操作基本都一样,具体可以参考官方文档,这里就仅仅以删除为例进行说明。一般可以分为三步来完成,首先打开数据库

        SQLiteDatabase db = mOpenHelper.getWritableDatabase();

然后根据URI指向的是日志列表还是某一篇日志,到数据库中执行删除动作

    switch (sUriMatcher.match(uri)) {
case NOTES:
count = db.delete(NOTES_TABLE_NAME, where, whereArgs);
break;
case NOTE_ID:
String noteId = uri.getPathSegments().get(1);
count = db.delete(NOTES_TABLE_NAME, Notes._ID + “=” + noteId
+ (!TextUtils.isEmpty(where) ? ” AND (” + where + ‘)’ : “”), whereArgs);
break;
}

最后,一定记得通知上层:其传递下来的URI在底层数据库中已经发生了变化。

        getContext().getContentResolver().notifyChange(uri, null);

  对NotePad的改进

首先我想指出NotePad的一个bug,其实这个小bug在2月份就有人向官方报告了,参见http://code.google.com/p/android/issues/detail?id=1909。NoteEditor类中的变量mNoteOnly根本就是没有用处的,因为它始终都是false,没有任何变化,所以可以删除掉。第二点是在NoteEditor类中,有下面这样的语句:

setResult(RESULT_OK, (new Intent()).setAction(mUri.toString()));
setResult(RESULT_CANCELED);

可到底想展示什么技术呢?实际上并没有完整展现出来,这里我对其进行修改后来指明。参见http://code.google.com/p/android/issues/detail?id=1671)。首先在NotesList类中增加一个变量

private static final int REQUEST_INSERT = 100;//请求插入标识符

然后修改onOptionsItemSelected函数如下:

   @Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case MENU_ITEM_INSERT:
this.startActivityForResult(new Intent(Intent.ACTION_INSERT, getIntent().getData()), REQUEST_INSERT);
return true;
}
return super.onOptionsItemSelected(item);
}

最后重载onActivityResult函数来处理接收到的activity result。

    protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if(requestCode == REQUEST_INSERT)
{
if(resultCode==RESULT_OK)
{
Log.d(TAG, “OK!!!”);
}
else if(resultCode==RESULT_CANCELED)
{
Log.d(TAG, “CANCELED!!!”);
}
}
}

试试,当你在NoteEditor中保存或放弃日志时,观察LogCat,你可以看到下面这样的画面:

Android实例剖析笔记(三)

Activity的生命周期

Activity类中有许多onXXX形式的函数可以重载,比如 onCreate,onStart,onStop,onPause,那么它们的调用顺序到底是如何的呢?下面就通过一个实验来进行分析。在做这个实验之 前,我们先得知道如何在Android中进行Log输出的。我们要使用的是android.util.log类,这个类相当的简单易用,因为它提供的全是 一些静态方法:

Log.v(String tag, String msg);        //VERBOSE
Log.d(String tag, String msg);       //DEBUG
Log.i(String tag, String msg);        //INFO
Log.w(String tag, String msg);     //WARN
Log.e(String tag, String msg);      //ERROR

前面的tag是由我们定义的一个标识,一般可以用“类名_方法名“来定义。要在Eclipse中查看输出的log信息,需要打开Logcat(WindowàShow ViewàotheràAndroidàLogCat即可打开)

  实验一

我们要做的实验非常简单,就是有两个Activity(我这里分别叫做frmLogin和hello2),t它们各自有一个button,可以 从第一个跳到第二个,也可以从第二个跳回到第一个。配置文件AndroidManifest.xml非常简单,第二个activity并没有多余的信息需 要指定。

    <application android:icon=”@drawable/icon” android:label=”@string/app_name”>
<activity android:name=”.frmLogin”
android:label=”@string/app_name”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
<activity android:name=”hello2″ android:label=”@string/app_name”>
</activity>
</application>

第一个activity的代码如下:

public class frmLogin extends Activity
{
private final static String TAG = “FrmLogin”;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Log.v(TAG,”onCreate”);
setContentView(R.layout.main);
this.setViewOneCommand();
}

public void setViewOneCommand()
{
Button btn = (Button)findViewById(R.id.btnGo);
btn.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
Intent intent = new Intent();
intent.setClass(frmLogin.this, hello2.class);
startActivity(intent);
finish();
}
});
Button btnExit=(Button)findViewById(R.id.btnExit);
btnExit.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
frmLogin.this.finish();
}
});
}

@Override
protected void onDestroy()
{
super.onDestroy();
Log.v(TAG,”onDestroy”);
}

@Override
protected void onPause()
{
super.onPause();
Log.v(TAG,”onPause”);

}

@Override
protected void onRestart()
{
super.onRestart();
Log.v(TAG,”onRestart”);
}

@Override
protected void onResume()
{
super.onResume();
Log.v(TAG,”onResume”);
}

@Override
protected void onStart()
{
super.onStart();
Log.v(TAG,”onStart”);
}

@Override
protected void onStop()
{
super.onStop();
Log.v(TAG,”onStop”);
}
}

我在每个onXXX方法中都加入了log方法,值得注意的一点是按钮单击事件处理函数中,在最后我调用了finish();待会我会将此行注释 掉进行对比实验。第二个activity的代码和第一个完全一样,只是将setClass的两个参数反一下,这样就可以简单地实现在两个Activity 界面中来回切换的功能了。下面开始实验,第一个实验室从第一个activity跳到第二个activity(此时第一个关闭),然后从第二个跳回第一个 (此时第二个关闭)。运行后观察LogCat,得到如下画面:

 

然后来进行第二个实验,对代码进行调整,我们把第一个activity中的finish()注释掉,从第一个activity跳到第二个(此时第一个没有关闭),然后第二个直接关闭(则第一个会重新来到前端),结果如图所示,可以看出调用了FrmLogin的onRestart而不是onStart,因为第一个activity只是stop,而并没有被destory掉。

 

前面两个实验都很好理解,可第三个实验就让我不明白了,过程如下:从第一个activity跳到第二个activity(此时第一个不关闭), 然后第二个跳回第一个(此时第二个也不关闭),然后第一个再跳回第二个(此时第一个不关闭),照上面来推断,应该还是会调用onRestart才对,可实 际上它调用的却是onStart,why???
这里先不讨论例子了,来看看官方文档对Activity生命周期的介绍。

1. Android用Activity Stack来管理多个Activity,所以呢,同一时刻只会有最顶上的那个Activity是处于active或者running状态。其它的Activity都被压在下面了。

2. 如果非活动的Activity仍是可见的(即如果上面压着的是一个非全屏的Activity或透明的Activity),它是处于paused状态的。在 系统内存不足的情况下,paused状态的Activity是有可被系统杀掉的。只是不明白,如果它被干掉了,界面上的显示又会变成什么模样?看来下回有 必要研究一下这种情况了。

3. 几个事件的配对可以比较清楚地理解它们的关系。Create与Destroy配成一对,叫entrie lifetime,在创建时分配资源,则在销毁时释放资源;往上一点还有Start与Stop一对,叫visible lifetime,表达的是可见与非可见这么一个过程;最顶上的就是Resume和Pause这一对了,叫foreground lifetime,表达的了是否处于激活状态的过程。

4. 因此,我们实现的Activity派生类,要重载两个重要的方法:onCreate()进行初始化操作,onPause()保存当前操作的结果。除了Activity Lifecycle以外,Android还有一个Process Lifecycle的说明:

在内存不足的时候,Android是会主动清理门户的,那它又是如何判断哪个process是可以清掉的呢?文档中也提到了它的重要性排序:

1. 最容易被清掉的是empty process,空进程是指那些没有Activity与之绑定,也没有任何应用程序组件(如Services或者IntentReceiver)与之绑定 的进程,也就是说在这个process中没有任何activity或者service之类的东西,它们仅仅是作为一个cache,在启动新的 Activity时可以提高速度。它们是会被优先清掉的。因此建议,我们的后台操作,最好是作成Service的形式,也就是说应该在Activity中 启动一个Service去执行这些操作。

2. 接下来就是background activity了,也就是被stop掉了那些activity所处的process,那些不可见的Activity被清掉的确是安全的,系统维持着一个 LRU列表,多个处于background的activity都在这里面,系统可以根据LRU列表判断哪些activity是可以被清掉的,以及其中哪一 个应该是最先被清掉。不过,文档中提到在这个已被清掉的Activity又被重新创建的时候,它的onCreate会被调用,参数就是onFreeze时 的那个Bundle。不过这里有一点不明白的是,难道这个Activity被killed时,Android会帮它保留着这个Bundle吗?

3. 然后就轮到service process了,这是一个与Service绑定的进程,由startService方法启动。虽然它们不为用户所见,但一般是在处理一些长时间的操作(例如MP3的播放),系统会保护它,除非真的没有内存可用了。

4. 接着又轮到那些visible activity了,或者说visible process。前面也谈到这个情况,被Paused的Activity也是有可能会被系统清掉,不过相对来说,它已经是处于一个比较安全的位置了。

5. 最安全应该就是那个foreground activity了,不到迫不得已它是不会被清掉的。这种process不仅包括resume之后的activity,也包括那些 onReceiveIntent之后的IntentReceiver实例。在Android Application的生命周期的讨论中,文档也提到了一些需要注意的事项:因为Android应用程序的生存期并不是由应用本身直接控制的,而是由 Android系统平台进行管理的,所以,对于我们开发者而言,需要了解不同的组件Activity、Service和IntentReceiver的生 命,切记的是:如果组件的选择不当,很有可能系统会杀掉一个正在进行重要工作的进程。

  自定义控件

这里主要介绍下“编辑日志”中使用的一个自定义EditText控件,它的效果如下图:

主要功能就是在文本语句之间绘制分割线。

  public static class LinedEditText extends EditText
{
private Rect mRect;
private Paint mPaint;
// we need this constructor for LayoutInflater
public LinedEditText(Context context, AttributeSet attrs)
{
super(context, attrs);
mRect = new Rect();
mPaint = new Paint();
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(0x800000FF);
}
@Override
protected void onDraw(Canvas canvas)
{
int count = getLineCount();
Rect r = mRect;
Paint paint = mPaint;
for (int i = 0; i < count; i++)
{
int baseline = getLineBounds(i, r);
canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint);
}
super.onDraw(canvas);
}
}

主要工作就是重载onDraw方法,利用从TextView继承下来的getLineCount函数获取文本所占的行数,以及 getLineBounds来获取特定行的基准高度值,而且这个函数第二个参数会返回此行的“外包装”值。再利用这些值绘制这一行的线条。为了让界面的 View使用自定义的EditText类,必须在配置文件中进行设置

<view xmlns:android=”http://schemas.android.com/apk/res/android”
class=”com.example.android.notepad.NoteEditor$LinedEditText”
android:id=”@+id/note”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
android:background=”@android:color/transparent”
android:padding=”5dip”
android:scrollbars=”vertical”
android:fadingEdge=”vertical”
android:gravity=”top”
android:textSize=”22sp”
android:capitalize=”sentences”
/>

这里class=”com.example.android.notepad.NoteEditor$LinedEditText”就指明了应当使用自定义的LinedEditText类。

0
0

Android实例剖析笔记(二)

简介

android提供了三种菜单类型,分别为options menu,context menu,sub menu。

options menu就是通过按home键来显示,context menu需要在view上按上2s后显示。这两种menu都有可以加入子菜单,子菜单不能种不能嵌套子菜单。options menu最多只能在屏幕最下面显示6个菜单选项,称为iconmenu,icon menu不能有checkable选项。多于6的菜单项会以more icon menu来调出,称为expanded menu。options menu通过activity的onCreateOptionsMenu来生成,这个函数只会在menu第一次生成时调用。任何想改变options menu的想法只能在onPrepareOptionsMenu来实现,这个函数会在menu显示前调用。onOptionsItemSelected 用来处理选中的菜单项。

context menu是跟某个具体的view绑定在一起,在activity种用registerForContextMenu来为某个view注册context menu。context menu在显示前都会调用onCreateContextMenu来生成menu。onContextItemSelected用来处理选中的菜单项。

android还提供了对菜单项进行分组的功能,可以把相似功能的菜单项分成同一个组,这样就可以通过调用setGroupCheckable,setGroupEnabled,setGroupVisible来设置菜单属性,而无须单独设置。

  Options Menu

Notepad中使用了options menu和context menu两种菜单。首先来看生成options menu的onCreateOptionsMenu函数。

  menu.add(0, MENU_ITEM_INSERT, 0, R.string.menu_insert)
.setShortcut(‘3’, ‘a’)
.setIcon(android.R.drawable.ic_menu_add);

这是一个标准的插入一个菜单项的方法,菜单项的id为MENU_ITEM_INSERT。有意思的是下面这几句代码:

 Intent intent = new Intent(null, getIntent().getData());
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0,
new ComponentName(this, NotesList.class), null, intent, 0, null);

这到底有何用处呢?其实这是一种动态菜单技术(也有点像插件机制),若某一个activity,其类型 是”android.intent.category.ALTERNATIVE”,数据 是”vnd.android.cursor.dir/vnd.google.note”的话,系统就会为这个activity增加一个菜单项。在 androidmanfest.xml中查看后发现,没有一个activity符合条件,所以这段代码并没有动态添加出任何一个菜单项。

为了验证上述分析,我们可以来做一个实验,在androidmanfest.xml中进行修改,看是否会动态生成出菜单项。

实验一

首先我们来创建一个新的activity作为目标activity,名为HelloAndroid,没有什么功能,就是显示一个界面。

public class HelloAndroid extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
}
}

它所对应的布局界面XML文件如下:

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:orientation=”vertical”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
>
<TextView
android:layout_width=”fill_parent”
android:layout_height=”wrap_content” android:id=”@+id/TextView01″/>

<Button android:id=”@+id/Button01″ android:layout_height=”wrap_content” android:layout_width=”fill_parent” android:text=”@string/txtInfo”></Button>
</LinearLayout>

然后修改androidmanfest.xml,加入下面这段配置,让HelloAndroid满足上述两个条件:

    <activity android:name=”HelloAndroid” android:label=”@string/txtInfo”>
<intent-filter>
<action android:name=”com.android.notepad.action.HELLO_TEST” />
<category android:name=”android.intent.category.ALTERNATIVE”/>
<data android:mimeType=”vnd.android.cursor.dir/vnd.google.note” />
</intent-filter>
</activity>

好了,运行下试试,哎,还是没有动态菜单项加入呀!怎么回事呢?查看代码后发现,原来是onPrepareOptionsMenu搞的鬼!这个 函数在onCreateOptionsMenu之后运行,下面这段代码中,由于Menu.CATEGORY_ALTERNATIVE是指向同一个组,所以 把onCreateOptionsMenu中设置的菜单项给覆盖掉了,而由于onPrepareOptionsMenu没有给 Menu.CATEGORY_ALTERNATIVE附新值,故Menu.CATEGORY_ALTERNATIVE还是为空。

   Intent intent = new Intent(null, uri);
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, specifics, intent, 0,items);

好的,那我们暂时把上面这几句给注释掉,当然,也可以不注释这几句,在onCreateOptionsMenu中改groupid号,即将Menu.CATEGORY_ALTERNATIVE改为Menu.first,其他的也行,但注意不要改为menu.none,这样会覆盖掉。

menu.add(0, MENU_ITEM_INSERT, 0, R.string.menu_insert)
.setShortcut(‘3’, ‘a’)
.setIcon(android.R.drawable.ic_menu_add);

添加的菜单。因为menu.none也为0。运行后就可以看到动态菜单出来了!

上面这个options menu是在NotesList界面上没有日志列表选中的情况下生成的,若先选中一个日志,然后再点”menu”,则生成的options menu是下面这样的:

哎,又动态增加了两个菜单项”Edit note”和”Edit title”,这又是如何动态加入的呢?这就是onPrepareOptionsMenu的功劳了。

    Uri uri = ContentUris.withAppendedId(getIntent().getData(), getSelectedItemId());

首先获取选中的日志(若没有选择,则uri为空)

  Intent[] specifics = new Intent[1];
specifics[0] = new Intent(Intent.ACTION_EDIT, uri);
MenuItem[] items = new MenuItem[1];

然后为选中的日志创建一个intent,操作类型为Intent.ACTION_EDIT,数据为选中日志的URI.于是会为选中的日志创建一个”Edit note”菜单项。

 Intent intent = new Intent(null, uri);
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
menu.addIntentOptions(Menu.CATEGORY_ALTERNATIVE, 0, 0, null, specifics, intent, 0,
items);

这几句和上面onCreateOptionsMenu函数中类似,用于动态增加菜单项,若某一个activity,其类型是”android.intent.category.ALTERNATIVE”,数据是”vnd.android.cursor.item/vnd.google.note”的话,系统就会为这个activity增加一个菜单项。在androidmanfest.xml中查看后发现,TitleEditor这个activity符合条件,于是系统就为TitleEditor这个activity动态添加一个菜单项”Edit title”。

else {
menu.removeGroup(Menu.CATEGORY_ALTERNATIVE);
}

若日志列表为空,则从菜单中删除组号为Menu.CATEGORY_ALTERNATIVE的菜单项,只剩下”Add note”菜单项。

  处理“选中菜单项”事件

菜单项选中事件的处理非常简单,通过onOptionsItemSelected来完成,这里只是简单地调 用 startActivity(new Intent(Intent.ACTION_INSERT, getIntent().getData()));这个intent的操作类型为Intent.ACTION_INSERT,数据为日志列表的URI, 即”content:// com.google.provider.NotePad/notes”

     @Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case MENU_ITEM_INSERT:
// Launch activity to insert a new item
startActivity(new Intent(Intent.ACTION_INSERT, getIntent().getData()));
return true;
}
return super.onOptionsItemSelected(item);
}

  Context Menu

下面介绍另一种菜单—上下文菜单,这通过重载onCreateContextMenu函数实现。首先确认已经选中了日志列表中的一个日志,若没选择,则直接返回。Cursor指向选中的日志项。

   Cursor cursor = (Cursor) getListAdapter().getItem(info.position);
if (cursor == null) {
// For some reason the requested item isn’t available, do nothing
return;
}

然后,设置上下文菜单的标题为日志标题

        // Setup the menu header
menu.setHeaderTitle(cursor.getString(COLUMN_INDEX_TITLE));

最后为上下文菜单增加一个菜单项

        // Add a menu item to delete the note
menu.add(0, MENU_ITEM_DELETE, 0, R.string.menu_delete);

对于上下文菜单项选中的事件处理,是通过重载onContextItemSelected实现的。

        switch (item.getItemId()) {
case MENU_ITEM_DELETE: {
// Delete the note that the context menu is for
Uri noteUri = ContentUris.withAppendedId(getIntent().getData(), info.id);
getContentResolver().delete(noteUri, null, null);
return true;
}
}
return false;
}

对于日志的删除,首先调用ContentUris.withAppendedId(getIntent().getData(), info.id);来拼接出待删除日志的URI.然后getContentResolver().delete(noteUri, null, null);调用下层的Content Provider去删除此日志。

  实验二

来做个简单实验,在上述代码基础上增加一个上下文菜单项。首先在onCreateContextMenu函数中增加一个上下文菜单项:

menu.add(0,MENU_ITEM_INSERT,0,R.string.menu_insert);

然后为其在onContextItemSelected函数中增加一个处理过程:

case MENU_ITEM_INSERT:
{
new AlertDialog.Builder(this).setIcon(R.drawable.app_notes)
.setTitle(R.string.app_name).setMessage(R.string.error_message).setPositiveButton(R.string.button_ok, new OnClickListener(){

public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub

}

}).show();
return true;
}

实验结果如下:


Android实例剖析笔记(一)

开卷语

俗话说,“熟读唐诗三百首,不会作诗也会吟”。最近收集了很多Android的示例代码,从这些代码的阅读和实验中学习到很多知识,从而产生写这个系列的打算,目标就是一步步跟着实例进行动手实作,真正从“做”中体会和学习Android开发。

本文是这个系列的第一篇,目标是Android自带的一个范例程序:记事本,将分为四篇文章进行详细介绍。

  预备知识

搭建开发环境,尝试编写”Hello World”,了解Android的基本概念,熟悉Android的API(官方文档中都有,不赘述)。

  程序截图

先来简单了解下程序运行的效果

  程序入口点 

类似于win32程序里的WinMain函数,Android自然也有它的程序入口点。它通过在AndroidManifest.xml文件中配置来指明,可以看到名为NotesList的activity节点下有这样一个intent-filter,其action为android.intent.action.MAIN, Category指定为 android.intent.category.LAUNCHER,这就指明了这个activity是作为入口activity,系统查找到它后,就会创建这个activity实例来运行,若未发现就不启动(你可以把MAIN改名字试试)。

[code lang=”xml”]
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
[/code]

  NotesList详解

就从入口点所在的activity(见图1)开始,可以看到这个activity最重要的功能就是显示日志列表。这个程序的日志都存放在Sqlite数据库中,因此需要读取出所有的日志记录并显示。先来看两个重要的私有数据,第一个PROJECTION字段指明了“日志列表“所关注的数据库中的字段(即只需要ID和Title就可以了)。

[java]
private static final String[] PROJECTION = new String[] {
Notes._ID, // 0
Notes.TITLE, // 1
};
[/java]

第二个字段COLUMN_INDEX_TITLE指明title字段在数据表中的索引。

private static final int COLUMN_INDEX_TITLE = 1;

然后就进入第一个调用的函数onCreate。

[java]</div>
<div>Intent intent = getIntent();
if (intent.getData() == null)
{
intent.setData(Notes.CONTENT_URI);
}</div>
<div>[/java]

因为NotesList这个activity是系统调用的,此时的intent是不带数据和操作类型的,系统只是在其中指明了目标组件是Notelist,所以这里把”content:// com.google.provider.NotePad/notes”保存到intent里面,这个URI地址指明了数据库中的数据表名(参见以后的NotePadProvider类),也就是保存日志的数据表notes。

        Cursor cursor = managedQuery(getIntent().getData(), PROJECTION, null, null, Notes.DEFAULT_SORT_ORDER);

然后调用managedQuery函数查询出所有的日志信息,这里第一个参数就是上面设置的” content:// com.google.provider.NotePad/notes”这个URI,即notes数据表。PROJECTION 字段指明了结果中所需要的字段,Notes.DEFAULT_SORT_ORDER 指明了结果的排序规则。实际上managedQuery并没有直接去查询数据库,而是通过Content Provider来完成实际的数据库操作,这样就实现了逻辑层和数据库层的分离。

 SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.noteslist_item, cursor,
new String[] { Notes.TITLE }, new int[] { android.R.id.text1 });
setListAdapter(adapter);

查询出日志列表后,构造一个CursorAdapter,并将其作为List View的数据源,从而在界面上显示出日志列表。可以看到,第二个参数是R.layout.noteslist_item,打开对应的noteslist_item.xml文件,

[xml]</div>
<div><TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="center_vertical"
android:paddingLeft="5dip"
android:singleLine="true"
/></div>
<div>[/xml]

就是用来显示一条日志记录的TextView,最后两个字段指明了实际的字段映射关系,通过这个TextView来显示一条日志记录的title字段。

  处理“选择日志”事件

既然有了“日志列表”,就自然要考虑如何处理某一条日志的单击事件,这通过重载onListItemClick方法来完成,

[java]</div>
<div>@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Uri uri = ContentUris.withAppendedId(getIntent().getData(), id);String action = getIntent().getAction();
if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action)) {
// The caller is waiting for us to return a note selected by
// the user.  The have clicked on one, so return it now.
setResult(RESULT_OK, new Intent().setData(uri));
} else {
// Launch activity to view/edit the currently selected item
startActivity(new Intent(Intent.ACTION_EDIT, uri));
}
}</div>
<div>[/java]

首先通过”content:// com.google.provider.NotePad/notes”和日志的id 号拼接得到选中日志的真正URI,然后创建一个新的Intent,其操作类型为Intent.ACTION_EDIT,数据域指出待编辑的日志URI(这里只分析else块)。

  Intent深度剖析

那么,上面这句startActivity(new Intent(Intent.ACTION_EDIT, uri))执行后会发生什么事情呢?这时候Android系统就跳出来接管了,它会根据intent中的信息找到对应的activity,在这里找到的是NoteEditor这个activity,然后创建这个activity的实例并运行。

那么,Android又是如何找到NoteEditor这个对应的activity的呢?这就是intent发挥作用的时刻了。

new Intent(Intent.ACTION_EDIT, uri)

这里的Intent.ACTION_EDIT=” android.intent.action.EDIT”,另外通过设置断点,我们看下这里的uri值:

可以看到选中的日志条目的URI是:content://com.google.provider.NotePad/notes/1。然后我们再来看下Androidmanfest.xml,其中有这个provider

<provider android:name=”NotePadProvider”
android:authorities=”com.google.provider.NotePad”
/>

发现没有?它也有com.google.provider.NotePad,这个是content://com.google.provider.NotePad/notes/1的一部分,同时

    <activity android:name=”NoteEditor”
android:theme=”@android:style/Theme.Light”
android:label=”@string/title_note”
android:screenOrientation=”sensor”
android:configChanges=”keyboardHidden|orientation”
>
<!– This filter says that we can view or edit the data of
a single note –>
<intent-filter android:label=”@string/resolve_edit”>
<action android:name=”android.intent.action.VIEW” />
<action android:name=”android.intent.action.EDIT” />
<action android:name=”com.android.notepad.action.EDIT_NOTE” />
<category android:name=”android.intent.category.DEFAULT” />
<data android:mimeType=”vnd.android.cursor.item/vnd.google.note” />
</intent-filter>
<!– This filter says that we can create a new note inside
of a directory of notes. –>
<intent-filter>
<action android:name=”android.intent.action.INSERT” />
<category android:name=”android.intent.category.DEFAULT” />
<data android:mimeType=”vnd.android.cursor.dir/vnd.google.note” />
</intent-filter>
</activity>

上面第一个intent-filter中有一个action 名为android.intent.action.EDIT,而前面我们创建的Intent也正好是Intent.ACTION_EDIT=” android.intent.action.EDIT”,想必大家已经明白是怎么回事了吧。

下面就进入activity选择机制了:

系统从intent中获取道uri,得到了content://com.google.provider.NotePad/notes/1,去掉开始的content:标识,得到com.google.provider.NotePad/notes/1,然后获取前面的com.google.provider.NotePad,然后就到Androidmanfest.xml中找到authorities为com.google.provider.NotePad的provider,这个就是后面要讲的contentprovider,然后就加载这个content provider。

        <provider android:name=”NotePadProvider”
android:authorities=”com.google.provider.NotePad”
/>

在这里是NotePadProvider,然后调用NotePadProvider的gettype函数,并把上述URI传给这个函数,函数返回URI所对应的类型(这里返回Notes.CONTENT_ITEM_TYPE,代表一条日志记录,而CONTENT_ITEM_TYPE = ” vnd.android.cursor.item/vnd.google.note “)。

   @Override
public String getType(Uri uri) {
switch (sUriMatcher.match(uri)) {
case NOTES:
return Notes.CONTENT_TYPE;
case NOTE_ID:
return Notes.CONTENT_ITEM_TYPE;
default:
throw new IllegalArgumentException(“Unknown URI ” + uri);
}
}

上面的sUriMatcher.match是用来检测uri是否能够被处理,而sUriMatcher.match(uri)返回值其实是由决定的。

        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
sUriMatcher.addURI(NotePad.AUTHORITY, “notes”, NOTES);
sUriMatcher.addURI(NotePad.AUTHORITY, “notes/#”, NOTE_ID);

然后系统使用获得的” vnd.android.cursor.item/vnd.google.note “和”android.intent.action.EDIT”到androidmanfest.xml中去找匹配的activity.

  <intent-filter android:label=”@string/resolve_edit”>
<action android:name=”android.intent.action.VIEW” />
<action android:name=”android.intent.action.EDIT” />
<action android:name=”com.android.notepad.action.EDIT_NOTE” />
<category android:name=”android.intent.category.DEFAULT” />
<data android:mimeType=”vnd.android.cursor.item/vnd.google.note” />
</intent-filter>

正好NoteEditor这个activity的intent-filter满足上述条件,这样就找到了NoteEditor。于是系统加载这个类并实例化,运行,然后就到了NoteEditor的OnCreate函数中(见后续文章)。

  小技巧

1,在命令行中使用”adb shell”命令进入系统中,然后”cd app”进入应用程序所在目录,”rm XXX”就可以删除你指定的apk,从而去掉其在系统顶层界面占据的图标,若两次”cd data”则可以进入应用程序使用的数据目录,你的数据可以保存在这里,例如Notepad就是把其数据库放在它的databases目录下,名为note_pad.db.

2,第一次启动模拟器会比较慢,但以后就别关闭模拟器了,修改代码,调试都不需要再次启动的,直接修改后run或debug就是。

0
0

关于Activity中各个方法的调用

程序正常启动:onCreate()->onStart()->onResume();
正常退出:onPause()->onStop()->onDestory()

一个Activity启动另一个Activity: onPause()->onStop(), 再返回:onRestart()->onStart()->onResume()

程序按back 退出: onPause()->onStop()->onDestory(),再进入:onCreate()->onStart()->onResume();
程序按home 退出: onPause()->onStop(),再进入:onRestart()->onStart()->onResume();

针对开发者的20款移动开发框架

本文收集了20款针对开发者的移动开发框架,以帮助他们为移动爱好者开发出新颖、有用、有趣味的应用。

1.Fries

Fries是一款稳定的HTML-CSS-JS框架,用于在实际项目和原型设计中创造类似于Android的原生UI界面。该框架包含所有的重要组 件,比如Form、工具栏、列表、按钮、下拉列表及标签。它还专门针对PhoneGap进行了优化,能容易地转换为本地应用。

源代码

2. Appium

Appium是一款开源自动化测试工具。可对任何语言的iOS应用和Android应用进行测试,测试可使用Java、Objective-C、 JavaScript、PHP、Python、Ruby、C#、Clojure、Perl等众多语言编写。目前只针对Mac OS X ,且需要有 Node.js来支撑。

源代码

3. Junior

Junior为前端框架,用来构建基于HTML5的移动Web应用,外观与行为跟本地应用相似。它采用针对移动性能优化的CSS3转换,支持旋转灯箱 效果,包含多样的Ratchet UI组件。整个框架使用Zepto(类似jQuery语法的轻量级移动设备js类库),且整合了backbone.js 的视图和路由。Junior十分易于使用,且提供详细的文档及案例,便于学习。

源代码

4. Enyo

Enyo,为JavaScript开发框架,最初发布于HP TouchPad的webOS之上。现在发布了2.0版本,成为跨平台框架,不再只针对 webOS(1.0版本只针webOS)。新版本的Enyo支持桌面与移动,可工作于所有主流浏览器,拥有丰富的跨平台UI组件,以及构建应用所需的强大 的布局库。

源代码

5. Sidetap

Sidetap是一款简洁轻量级的移动Web应用开发框架(缩减压缩后只有2KB)。它专注于提供类似于Facebook移动应用这样的侧导航形式。导航部分解决后,利用它创建简单的移动Web应用就变得相当简单了。

源代码

6. Mobello

Mobello是一个开源JavaScript UI框架,目的是简化移动Web应用的开发过程。利用该框架,可在移动端提供与本地应用相似的体验。 它针对触控事件进行了优化,并提供20多种广泛应用的UI组件。它还提供了集成开发环境Mobello Studio,在其中可利用HTML5、CSS和 Mobello框架开发移动应用。

源代码

7. Moobile

Moobile是基于MooTools的移动Web应用框架,是一个新项目。它专注于提供类iOS的体验,并对按钮、图片、列表等提供较好的控制。它 还支持各种过渡样式,比如淡入淡出、幻灯片等,并可显示类本地应用的提示框(alert)。Moobile所创建的界面更具有弹性,可很好地工作于 iPhone和iPad上。

源代码

8. Spine Mobile

Spine Mobile是一个构建在SpineJS之上的JavaScript框架,用于构建看起来外观像本地应用的移动Web应用。该框架带有专用控制器、面板布局、硬件加速的转换和触摸事件。

源代码

9. Zoey

它是一个采用HTML5-CSS3技术实现的框架,用于构建移动应用。它基于Zepto.js构建,轻量,压缩后只有6kb。Zoey拥有的大量UI 控件,比如:导航、列表、按纽、控件分组、表单、表格。这个框架支持iOS和Android,并自带一个覆盖所有功能的程序骨架。

源代码

10. iUI

iUI为移动Web框架。该框架包含JavaScript库、CSS和图片集,用于开发可触摸Web应用。它所创建的应用有着iPhone SDK构建的本机应用程序那样的外观和感觉,可运行于大部分智能手机和平板电脑上,只要它包含一个符合标准的Web浏览器。

源代码

11. Lungo.js

Lungo.jS是一个使用HTML5、CSS3和 JavaScript技术的移动Web开发框架。所创建应用可运行于所有流行平台之上(iOS、 Android、Blackberry和WebOS)。它支持触控事件,如单击、双击和滑动。无需使用图片,全部采用向量声称。

源代码

12. Wink Toolkit

Wink Toolkit为JavaScript框架,用来创建移动Web应用。该框架的核心提供了开发移动应用应具备的所有基础功能,从触摸事件处理到DOM操作和CSS转换等。此外,它还提供非常多的UI控件来帮助改进Web应用的外观。

源代码

13. The M Project

The M Project是一款HTML5 JS框架,可构建跨平台的移动Web应用(如OS、Android、Palm webOS、BlackBerry平 台)。其JavaScript部分采用 jQuery,并包含所有jQuery UI核心文件,如离线支持、国际化等。The-M-Project并不是独立的,它需要引入nodeJS和一个称 为Espresso!的构建工具,该工具可使你更容易地结构化代码、构建并运行在内嵌服务器上。

源代码

14. DHTMLX Touch

DHTMLX Touch为JavaScript库,基于HTML5,用于创建移动Web应用。它不只是一组UI小工具,而是一个完整的框架,可以针 对移动和触摸设备创建跨平台的Web应用。它兼容主流的Web浏览器,用它创建的应用,可在iPad、iPhone、Android智能手机等上面流畅运 行。

源代码

15. Zepto.js

Zepto.js是支持移动WebKit浏览器的JavaScript框架,具有与jQuery兼容的语法。轻量级,大小为2-5k的库,通过不错的API处理绝大多数的基本工作。

源代码

16. jQuery Mobile

jQuery Mobile是 jQuery发布的针对手机和平板设备、经过触控优化的Web框架。它基于jQuery,在不同移动设备平台上可提供统一的用户界面。该框架基于渐近增强技术,并利用HTML5和CSS3特性。

源代码

17. Jo

Jo为基于HTML5的开源移动应用框架。该框架提供丰富的平台支持,包括webOS、iOS、Android、Symbian、Safari、 Chrome甚至是 Mac OS®X Dashboard小部件。Jo也兼容PhoneGap。Jo 的简单性和轻量级与 PhoneGap的强大功能 相结合,最终将生成一个有效的工具,可以针对广泛的平台开发丰富的移动本地应用程序。

源代码

18. Sencha Touch

它是一款HTML5移动应用框架。通过它可以创建Web应用,在外观和感觉上与Apple iOS 和Google Android本地应用十分相像。它利用HTML5发布音频/视频,进行本地存储;利用CSS3提供圆角、背景渐变、阴影等广泛使用的样式。

源代码

19. WebApp.Net

WebApp.Net是一款基于Ajax技术的JavaScript框架,用于构建移动Web应用。它提供了一整套组件(开关按钮、单选按钮组等),可帮助开发者创建外观和行为与本地移动应用十分相似的网站。

源代码

20. Helios

Helios为开源框架,为iOS应用提供必要的后台服务,从数据同步、推送通知,到应用内购买、passbook继承。它可帮助开发人员在数分钟的时间内构建出一个包含客户端和服务器端的应用。

源代码

 

原文链接: http://www.admin10000.com/document/2355.html

从新手到高手!一步到位!【Mac 操作指南 完全说明 】

在登陆系统之前需要了解Mac操作中的手势都有哪些

鼠标指针的变化:
①鼠标指针,日常移动;②I 型光标:进行文本的交互;③“风火轮”:表示当前‘忙’的状态;④不可行:不可完成当前的任务;⑤添加:直接拷贝/添加到指定处

依次表示“关闭窗口(不是退出)”   “最小化到Dock”   “最适合观看(不是最大化)”

    首先,先看到是桌面
底下的是Dock,一些快捷打开的程序或正在运行的程序会显示在上面
其中正在运行的程序下方会有小灯亮起(如果没有灯,可以在‘系统偏好设置’程序里的‘Dock’“显示已打开的应用程序指示灯”中勾选)
Mac不像Win那样,按住左上角关闭按钮就是退出程序,在Mac中‘关闭’的涵义只是关闭窗口,想要 退出程序 需要在菜单栏中或Dock右键“退出”程序
退出程序快捷键是⌘command+Q; 关闭窗口快捷键是⌘command+W; 最小化窗口快捷键是⌘command+M

点击此处 查看Apple官方 桌面 说明

Launchpad

如果某款程序不在 Dock 上,你也能在 Launchpad 中找到它,拇指或其它三指合拢可激活 Launchpad
在Launchpad中可以任意拖动程序,已达到自己想要的排列顺序,在App Store中安装的程序(APP)可在Launchpad中直接删除卸载
调整 Launchpad的背景可视化特效可按control+option+command+B

Mission Control

Mission Control 是可以让你了解所有打开的窗口,以便切换你需要的窗口
左上角是Dashboard ,里面有很多Widget小插件,比如天气、汇率、时钟等…
右上角是桌面缩略图,可以新建多个桌面或全屏打开的程序
可以四指或三指(根据自己设置)在各桌面或全屏程序中切换…
点击获取更多Widget小插件

想要关闭多余的桌面可按X关闭

  Dock
Dock,与win下的‘开始’的地位同等重要(但win8已经把它抛弃了~),可以自定顺序,把不常用的程序用鼠标单击不放拖到Dock以外的区域就可以让它在Dock中消失,当然 也可以把常用的程序拖到Dock里,以便捷打开。
Dock左端有不可移动的Finder和一些常用软件,中右段是正在运行的程序,右侧也有不可移动的废纸篓和‘堆栈’,那么什么是‘堆栈’呢?堆栈就是‘可以使用它快速访问常用的文件或文件夹’  补充:将项目拖到 Dock 上时,该项目的替身被放置到 Dock 中。原始项目没有被移动。

制作堆栈也十分简单,只需把文件夹拖到到Dock右端即可,比如 将‘应用程序’文件夹拖到dock上,就形成了堆栈,利用堆栈可以快捷访问里面的文件/程序(十分怀念雪豹里的自带堆栈)

更改堆栈里的视图大小也十分简单,按command+(加号)就是放大图标,按command-就是缩小图标

更改堆栈的显示效果可以‘右键’,可以按排列方式显示方式等查看

Finder

Finder 相当于windows下的‘我的电脑’ 资源管理器,文件和程序可以从Finder 中管理

‘系统’文件夹中就是系统文件(新手不要乱动哦);‘应用程序’就是本电脑的app程序所在文件夹;‘用户’文件夹顾名思义就是你个人的文件夹;‘资源库’是一些本机程序所需的运行文件和素材。拷贝(复制)的快捷键是command+c;粘贴 command+v;一些文字的剪贴是command+x
点击此处查看Apple官方Finder说明

选择多个项目时,除了用鼠标指针画一个选框 和全选的command+A之外,还有就是选择无序或散落的文件,在Mac中 选多个文件项目需要边按住command键鼠标指针边选择文件;而选择很多文件时只需选中第一个文件,按下shift键再点击顺序的最后一个文件,即 这个范围的文件项目全部选中

在Finder的标题栏里‘右键’选择‘自定工具栏…’,可以根据个人喜好或需要程度来自定 工具,当然 也可以把最常用的文件夹拖到工具栏里 达到快捷打开的目的…

‘前往文件夹…’功能可以仅凭地址 来打开文件夹,在前往复杂深邃的文件时相当有用,前往文件夹的快捷键 shift+command+G

在‘Finder’偏好设置中可以根据自己需求设定自己所需在边栏中显示的项目,推荐把‘外置磁盘’选项的对勾划上,因为 插硬盘的时候查看十分方便

当你要查看一个文件夹或app程序的‘属性’时,需要在‘文件’里选择‘显示简介’或者按下快捷键command+i便出来一个信息框,看要查看项目大小/修改日期/权限等
在这个信息框里 你可以更改这个项目的属性,比如更改图标  只需把icn图标文件直接拖到 信息框左上角的图标中,即可替换/更改图标,要还原按下delete即可还原原状
也可以更改使用权限,比如这个文件你只想读,不想写的话,在底部方框中 选择‘读或写’的要求,也可以设成不可访问的文件…

新建智能文件夹
新建智能文件夹,是可以根据用户自己所需量身打造‘文件夹’,这不是传统意义上的‘文件夹’里面没有实体的文件,只是把用户需要的变量和因素来查找符合条件的文件 在其中,当然 这里面可以实时删除文件的。里面有非常多的变量让用户选择,Mac会根据你的条件查找整机里符合的文件来分类,比如只有MP3格式的文件/今天创建的文件等…

当你运行的运行程序出现未响应的状况或卡死的状况时,按下‘退出’键也无法退出时,不妨试一下 option+command+esc 选择你要退出的程序,强制退出,十分管用~

在点击菜单栏之后,按不同的功能键会出现不同的效果,比如按shift键的时候,菜单中的‘强制退出…’就变成了‘强制退出当前的程序’;比如按option键的时候,菜单中的执行命令可立即执行,关机不再等待/确认,就可以立即关机,当然 还有很多奥秘

Dock中也是如此

废纸篓
废纸篓不用多说,和win下的回收站一样
想要清空废纸篓就可以右键废纸篓选择‘清倒废纸篓’,如果想‘倒’的干净点 在标题栏中的‘Finder’中选择‘安全清倒废纸篓…’,
陈冠希老师当年就没有选择安全清倒废纸篓~

关于废纸篓的小技巧:把移动硬盘或U盘或光盘等一些外部设备 拖到到废纸篓的时候,这时候废纸篓变成‘推出’的样子,这样就可以安全推出设备,是不是很方便?

预览
预览也是Mac中很强大但也很日常的软件,凭借预览,能轻松地阅读便携式文件格式文件(PDF)并打开常见图像文件……
查看和处理图像
适用于预览的手势
三指滑动:可以查看上一张图片或下一张
缩小放大:可以缩小放大查看图片
双指选择:可以以90°旋转图片,并可以保存

使用预览可以查看图像、编辑图像、将图像转换为另一种格式或以幻灯片显示照片。
点击查看Apple官方 预览 说明
如果想要缩小图片的尺寸,首先要选择你要打开的图片或文稿,多选或单选,双击文件 即可打开预览

在预览窗口里,可以调整图片

在左侧的图片的缩略图中按下⌘A,选择需要的调整大小的图片,在菜单栏中选择‘工具’—‘调整大小’

接着,会出来一个窗口,询问调整大小的数值,有具体尺寸,也有百分比调整,它会自动保存图片

     恢复文件
当我想要恢复原状怎么办??因为Mac中自带的一些软件在修改之后是自动保存的,没有询问是否保存的选项,那么即使修改错了也是可以恢复的
就以‘预览’为例子。不小心图片成这样了,怎么办?!!如果没有关闭预览 可以按command+z来撤销步骤

打开文件,默认是‘预览’程序,在菜单栏中选择‘文件’ —‘复原到’—“上次打开”或“浏览所有版本”

接着选择‘浏览所有版本’,神奇的一幕出现了,屏幕界面变成了在银河中穿梭,如同时光机里一样,可以查看这张图片之前的历史记录

找到你要回到目标文件的样子之后,点击‘恢复’  ,文件便回到初识状态,并自动保存上

这是“文本编辑”程序的‘时光机’,同样iWork套件也是有‘时光机’的

强大的搜索“善用搜索”
Mac中的Spotlight搜索也十分强悍,你几乎能用它搜到任何文件(系统文件除外),算术题它也会~
在Mac中搜索的快捷键是command+f,在不同的程序中 搜索会不同,比如在Safari中按下⌘f 会搜索当前网页的关键字…在Finder中就是搜索文件……

强悍的快速预览
在Mac中你可以不用打开文件即可快速查看文件,十分强大,只要合理文件都可以快速预览,只需选中项目 按下空格键即可 或者用三指单击项目文件也可以快速预览
快速预览支持的文件十分多,也支持第三方程序的扩展;用手势放大或点击右上方全屏功能即可全屏,甚至可以多选项目 按空格来 快速预览

万能的截图
在Mac中自带了 最‘完美’的截图功能:
全屏截图:按下Command+Shift+3 ,截取全屏图像将以PNG透明格式保存到桌面上。
区域截图:按下Command+Shift+4,鼠标变成十字准星,单击划出你想要的截图范围,自动保存到桌面上,想要取消截图按esc,想要移动选区按空格键即可
窗口截图:按下Command+Shift+4后,再按下空格键,这时鼠标变成’小相机’,点击想要的部件,就可以以PNG透明格式存在桌面上

懒得打字?动动嘴就行~
Mountain Lion中自带 听写功能,懒得打字?动动嘴就行!
只要在你需要键入/打字的地方,你都可以用说话的方式输入。听写功能可将你说的话 通过联网 转换成文本。
说出“逗号”或“感叹号”时,听写功能会为你加上标点‘,’‘!’。默认按键是按两下fn(在键盘左下角)即可唤出 听写功能。
设置在‘系统偏好设置’中的‘听写与语音’
  点击此处 查看Apple官方 听写 说明


音量/键盘灯/屏幕亮度 调整
关于调节屏幕亮度/键盘灯亮度/音量大小 我相信不用说
分享一个小技巧,就是微调,所谓微调就是以¼的量调整,按住Shift+Option+f1就是降暗,Shift+Option+f2就是缓亮,其它键盘灯和音量大小也可以组合Shift+Option来按
还有一个小技巧,就是在调节音量大小时候不发出“嘟嘟嘟”的声音,首先按shift不放,再按f11/f12,这样调节音量就是无声了,也可以组合上面的微调键

  快捷键

快捷键在Mac的操作中 有着举足轻重的地位,一些繁琐的操作 仅凭快捷键就可以完成
在菜单中,右侧的字符便是快捷键的方式

⌘  Command ‘花’键- 在部分 Apple 键盘上可能印有
⌃  Control
⌥  Option 键-“Alt”也可能会在此键上显示
⇧  Shift
⇪  Caps Lock 键- 切换大写字母锁定开或关
Fn  功能键;组合fx键
⏎ return -回车键/确定键
⌫ delete -删除;组合command+delete可删除文件

由于快捷键十分繁多,就不一一举例
详情 点击此处查看Apple快捷键 大全

系统编好设置
系统偏好设置与win下的控制面板功能相同,但Mac的控制面板逻辑性/归类方法要比win的控制面板简洁明了,新手上门也会很快。
首先打开‘系统偏好设置’,从中可以看到如何你想设置的一切,这个面板也可以扩展,后续会讲到…

首先先要根据个人情况设置触控板/鼠标

新上手的机子,肯定有不少人抱怨触控板默认下无法‘轻拍’,单击需要使劲按下“嘎嘣嘎嘣”十分不方便也十分心疼这样按
打开‘触控板’下面红框的就是‘轻拍来点按’把划上即可轻拍…

有些新手一直以为在Mac中没有右键的说法,其实右键是有的,但唤出方式与Win不同,Mac下的右键需要双指点按,当然  如果习惯了win   也可以设置成右键的方式
下拉选框,选择你习惯的方式即可……其他手势功能和鼠标手势 根据自己习惯自己设置,百变不离其踪,设置 十分方便

双击标题即可最小化
在win下 双击标题即可最小化,这是十分方便的一向功能,Mac中也可以设置~
首先打开‘系统偏好设置’,找到‘Dock’项目,‘连按窗口的标题栏以将窗口最小化’√划上

⬆另外,在这里用户可以调节Dock的大小、Dock的自动隐藏,最小化缩到图标里…或者缩放的动画效果,还有之前提到的“显示已打开的程序的指示灯”也是在这里设置

另外,再向大家推荐一个功能—触发角,触发角就是可以根据鼠标指针接触屏幕四角而达成一些快捷功能
比如,当鼠标指针滑到屏幕左上角时 活动窗口滑向四边,显示桌面;当鼠标指针滑到左下角的时候  唤醒Mission Control  以切换窗口,指针滑到右下角 屏幕熄灭但机器运行…
这一切都要在‘Mission Control ’中设置,左下角找到‘触发角…’

四角用户根据自己习惯自定,如果不习惯或感觉麻烦也可以空着不设置

如果在设置过程中按下⌘⌥⌃等 功能键,那么在触发四角的时候也要搭配 功能键使用,这样可以防止误触到四角


部分 有锋友抱怨 不知为什么在登陆界面莫名多了一个“客人账户”,那么改如何删除呢?
首先‘系统偏好设置’,找到‘用户与群组’,左侧候选栏里选中‘客人账户’,再单击左下角小锁 输入用户设定的密码解锁 权限 ,如果没有密码 直接空着不填点‘确定’
在“允许客人登陆到这台电脑”的选项中把取消即可关闭‘客人账号’,需要的时候可以再开启…

这个是‘登陆选项’用户可以设定 登陆时的选项,不如是直接登陆用户账户还是显示登陆界面后在登陆用户等,根据个人需要设定吧…

或者,有些程序莫名的随机启动,和win下‘启动’菜单一个道理,自己可以设定哪些程序可以自动随机启动(按下方+号),哪些不要随机启动(下方-号)
点击‘当前用户’选择‘登陆项’中 你可以看到哪些程序是随机开启启动的…自己设定

安全性与隐私’这是决定你mac安全性的一扇大门,在安全与隐私中的‘通用’里用户可以设定/修改 用户登陆密码
“我 从其他网站下的软件为什么不能安装呢?”从‘安全性与隐私’中可以设定,设定你允许的应用程序的来源,app应用程序一般可划分为‘随机自带程 序’‘App Store中下载的程序’‘从其他网上上下载的程序’。一般Mac默认的是‘App Store和被认可的开发者’ 这类软件通常为收费或必备软件。当然 我们要设定成‘任何来源’,这样从网站下的软件就可以成功安装上了。

安全性与隐私’的‘隐私’中,是可以设定你允许程序访问的内容,就如同iPhone设置中隐私,可以设定‘定位’‘访问通讯录’(用量与诊断是Mac向Apple不定期的发送你机子使用 情况与问题,如果你比较反感这个 可以把对勾取消,不发送)

另一个十分常用的功能就是—让Mac成为WIFI热点
如果用的是有线网络,不是无线网络,那么可以让你的Mac成为WIFI热点,把有线网络形成WIFI的形成发散出去,供 手机或一些设备利用电脑的网络上网
打开‘系统偏好设置’—找到“共享”,在左侧选择选择你要‘共享’的内容,之后在右侧选择你要‘共享’的方式,如下图所示,就可以让你的Mac成为WIFI热点

“共享”还有很多功能,WIFI热点只是一个典型例子,其他 共享 也很精彩~自己尝试一下。
关于系统偏好设置先讲到这里,其它功能大家可以自己体验体验

蓝牙文件交换
这个程序是非常好用的!当手头上没有数据线,要想给手机传图片/歌曲/文件 就可以用‘蓝牙文件交换’这个程序搞定!
(注意!有些手机是不支持的!主要以智能手机为主,不支持iPhone)
首先在“应用程序”—“实用工具”中找到“蓝牙文件交换”这个程序
传输文件的方式有两种
先说第一种,是类似发送信息的方式把文件发送出去(类似与手机与手机直接传歌);
①首先打开程序会出来文件选择窗口,选择你要传输的文件

②找到手机,点击后 会出现配对设置,在手机中输入电脑出现的配对码 即可配对,之后再传输就不用再配对了

③手机支持!这样就可以传输文件了,手机会以信息的提示 收到文件

另一种是直接访问手机的文件管理器  可以直接把文件放到手机需要的目录下即可
①点击选择‘文件’—‘浏览设备…’

②与上面的②相同,需要手机配对

③出来一个窗口,这样就可以访问手机里的储存空间,可以把需要的文件拖到想要的目录下

字典
‘字典’这个应用程序虽然不起眼,但内容十分强大
这个就是‘字典’程序,command+(逗号)即可唤出当前程序的偏好设置,选择你所需要的词库~(Mac自带的词库非常少,下面部分我会补充词库)


字典’这个程序在浏览网页时非常方便,当有不认识的单词或不明白的术语,都可以 “用三个手指轻按(在系统偏好设置中设置)” 可唤出字典功能


扩充自带的词库!
  首先,引用我之前教大家的“前往文件夹…”的功能
打开 Finder,在 Mac 屏幕顶部菜单栏选择 “前往” — “前往文件夹”。在弹出窗口里粘入下面这个路径 /Library/Dictionaries

然后就转到Mac系统资源库的‘字典文件夹’,把字典包拖进去就行了(如果弹出个警告框,点击 “鉴定”,然后输入密码就行)
扩展后再打开‘字典’程序,⌘,偏好设置中√你需要的字典即可

以下是几个常用的扩展词库

点击下载 115网盘 英-汉字典词库
点击下载 115网盘 汉-英字典词库
点击查看 扩展更多词库

   Safari
Safari是Mac中自带的网页浏览器,通过 iCloud 令你的 Mac、iPad、iPhone 协作得更有默契
Safari 是第一个支持 HTML5音频和视频标签的浏览器和第一个支持 CSS3 动画的浏览器。
首先,也是了解一下在Safari中常用的手势都有哪些
①双指轻扫,用于网页中的后退/前进 ②双指缩小,在多标签中转换标签 ③双指扩大,放大查看网页


点击查看Apple官方Safari说明

top sites功能是Mac Safari独有的一项功能,它能都打开网页开始,方便查看一些常用网页,还会提示有哪些网页已经更新

我打开Safari为什么没有发现top sites?
首先在使用Safari之前,需要设置一下你需要的功能,打开Safari的偏好设置⌘(逗号),会出来Safari的偏好设置,从中可以设置任何你需要的一切
‘Safari的打开方式’就是你启动Safari第一眼所看到的是什么,根据个人设置,可以是某个网页,可以使书签,也可以是top sites

偏好设置中的功能
通用:设置基本用户操作方式,包括主页,历史记录,下载目标文件等…
书签:书签功能 能设置在顶部书签栏中要显示的项目,以及联系人的个人主页等
标签页:标签页用于 当你点击某个连接时 标签页显示的状态
自动填充:自动填充Web表单,比如在填表的时候,只需之前设置你的个人信息,它会记住 自动当你填充
密码:这个功能很强大但也很脆弱!它能记住你邮箱/微博/论坛等的用户名和密码,帮助你下次不用重复繁琐的输入密码。但是!它能查看你的密码,所以在把电脑借给朋友的时候 一定要设置一下用户密码,不然 你邮箱/微博等用户名和密码 一览无余 全部都知道
安全性:网页安全,总之打开为好
隐私:里面存储的cookie和一些网站的数据,与win下的道理相似
通知:用于网站消息的通知,比如微博/邮件受到新消息 它会提醒你,但目前我一条还没有受到= =,比较鸡肋
扩展:功能强大!能够扩展Safari的功能,比如下载器的联动插件,Google翻译等,还有一个很强大的屏蔽视频网站广告的插件 下面讲到
高级:所谓的高级 其实就是其它的补充内容,在中可以可以设置字体,编码等

有一个技巧,就是不用Flash插件 用HTML5观看视频,如同iPhone和iPad那样,发热量小
在‘高级’中的‘在显示栏里显示‘开发’菜单’

这样,再打开视频网址的时候选择‘用.户.代.理.’就可以显示的是移动版的网页 和iOS上观看的一样,用完之后关闭 或 选回‘默认(自动选取)’

默认搜索引擎  就根据各位的习惯和所在地域设置吧,需要搜索的时候 直接在地址栏里打入关键字即可搜索

收藏网址
只需把地址栏中的地址 拖拽到下面的收藏栏里即可,或者也可以按照紫色箭头拖到top sites中显示。

下载太慢?
不如把下载地址拷贝了,到下载器中去下载,找到项目右键’拷贝地址’再到下载程序中新建项目即可

其它Safari神奇的扩展功能
点击 查看 谷歌翻译/视频下载 扩展部件下 载
点击 查看 OpenGG 视频网址屏蔽广告 说明
点击 Adobe官方 Flash播放器 下载

下载 app应用程序
下载来说目前就有两个渠道,一个是从 App Store里下载,里面的软件都是需要购买的(俗称 正版),当然比如QQ、PPS、迅雷等常用软件都是免费的,
需要Apple ID来购买,和iTunes里的Store是一样的,账户可以共用,如果经济条件允许的话 我们还是推荐在App Store里安装程序
在Store里,按下‘安装’,程序就会自动的安装到Mac上,不用安装包,一切都是自动的,它也会更新已安装的软件,卸载程序也非常简单,直接把程序图标拖到废纸篓里就是删除程序⌘⌫

我着重讲另一种渠道,因为这种渠道是最常用的,不为别的,就为它基本是免费的。
在威锋上就可以下载Mac软件,都是免费的,大部分也是破解版的,就体验上来说与‘正版’一样,只不过初期安装 要费脑筋(是因为在Store里安软件太白痴了,用多了人会变傻~)
1.Wefiler网盘上下载软件,但是需要邀请码,邀请码在235点我 直达235楼
2.Mac综合区或软件游戏分享区里会有帖子分享 程序
3.从其他网站上下载,比如MacX、MacApp等网站,度娘一下,你就知道

我从网站上下完了程序,该怎么安装呢?
下载完后,在‘下载’文件夹中可以看到你下载的安装包,安装包大致分为两类,一个是dmg格式,一个是pkg格式,没有win的exe文件
dmg是压缩镜像文件,相当于在Win上常见的iso文件;pkg格式属于系统级软件的安装程序,目前以dmg格式居多


dmg
首先是dmg安装文件,双击打开文件会出现一个窗口,程序就在里面,安装方法也比较简单,就是直接把程序图标拖到‘应用程序’文件夹里就行了(尽量都放在应用程序文件夹里)
相当于拷贝/解压的过程,拷贝完之后  就安装完毕了~是不是很简单

另外,在安装完毕后,记得推出 dmg安装包,之后这个安装包就没什么作用了,可以删除了⌘⌫(也可以留着 供下次或给朋友安装…)

新手可能疑问了,就这样复制到文件夹里就是安装程序?
是的,因为Mac使用的是linux的文件分区格式和存储方式,运行文件都包含在‘程序’包里,没有win所谓的程序文件和快捷方式启动,mac一般不存在文件碎片和磁盘整理的问题

如果要查看app程序 里的程序文件夹,选择程序 右键‘显示包内容’,里面就是这个程序所需的运行文件,全部包含在里面,是一个整体!因此要删除程序的话只需拖到废纸篓
  

pkg
接下来是pkg安装包,与dmg不同,pkg需要’安装器‘这个程序安装,一般pkg程序比较大型。安装方式和win差不多,按照一步一步的顺序就能安装完毕了

pkg安装后的程序想要卸载,需要卸载器或卸载程序 来卸载,因为在’资源库‘里也会有文件,故 直接拖到废纸篓里是删除不干净的

iTunes
自它诞生之日起 就背负着‘复兴苹果’的伟大 重任,如今经过10代的洗礼
用iTunes的用户不用多说,再熟悉不过了,这里我不着重讲解怎么操作,喜欢iTunes的人 恨不得抱着电脑,恨iTunes的人恨不得砸电脑
点击查看具体Apple官方iTunes说明
这是iTunes11,与之前的iTunes有了很大的改观,风格变得清淡,与iPhone5传达的感觉 一样,但取消了cover flow模式 很多人不爽(包括我)
如果不习惯iTunes11没有左侧边栏 是可以打开的,在菜单栏里找到“显示”—‘显示边栏’即可,快捷键是command+option+s,剩下的一切与之前 无异

这里 告诉一下我使用iTunes后的心得,打开‘偏好设置’⌘(逗号),在iTunes中也分成各个项目来设置,但有些在天.朝是无法使用的……
在通用设置里,是可以勾选你需要显示的项目。视图 就是显示窗口的效果,‘插入CD时…’这个后面会讲到


有些用户在使用过一段iTunes之后 发现电脑的容量急剧缩小,可能有人知道为何如此,就是因为iTunes的一个‘贴心’设计
我和大多数用户都喜欢和习惯把‘音乐‘放在一个文件夹里,建一个音乐库,这个’文件夹‘都是音乐文件,而在iTunes的世界中有一个叫做‘iTunes Media’的文件夹
‘iTunes Media’文件夹的主要任务就是把用户拖入的媒体文件(音乐/视频)拷贝一份到iTunes里,理论上 是直接可以把拖完的音乐文件删除的
但我们大家的习惯都是自己‘手动’的建一个‘音乐库’(文件夹)。所以,这就造成了同一个歌曲在电脑里有两份,iTunes Media文件夹一份,我们自己建的音乐库一份
这就造成了电脑的容量 减少/下降,当然,是可以关闭 拷贝iTunes Media文件夹 这个功能的。
在偏好设置中找到‘高级’下的“将添加到资料库时将文件拷贝到itunes media文件夹”这一项的√去掉。

iTunes‘导入设置’ 是可以把CD里的歌曲转换格式拷贝到Mac上,‘导入设置’就是设置CD转换成的格式;需要翻刻的时候只需选中你要翻刻的项目,右键 “创建XXX版本…”即可
CD中的数字音乐比特率约为1410kbps (简单来说数字越大 音质越好) ,一个3分钟的音乐 大约30MB
AAC编码格式16~320kbps :AAC相对于mp3,AAC格式的音质更佳,文件更小 ,在iTunes音乐商店下载的歌曲一般为 256Kbps AAC ,一个3分钟的音乐 大约6MB
AIFF编码格式:与CD的编码率相同,主要适用于电子音响设备,大小有CD音源决定
Apple Lossless:与CD的编码率相同,苹果研发的无损音频压缩编码格式,在苹果设备中听高音质音乐 Apple Lossless最为合适
Mp3编码格式64~320kbps:大众最熟悉不过的格式,就是因为使用的人多,才让它保持生命,一个3分钟的音乐 大约8MB
WAV编码格式:目前公认最好的音频格式  最接近CD的音质,虽然苹果设备是支持WAV格式的,但不支持歌词/插图,所以在苹果上编辑不如Apple Lossless完整

在Dock中显示iTunes播放专辑封面
这是一个小插件,可以让Dock中的iTunes图标显示成正在播放专辑的封面
点击此处查看/下载 插件

Remote
Remote是可以使iOS设备当做Mac的‘遥控器’来使用,首先是在iPhone或iPad中安装
点击此处查看Apple官方Remote说明
点击下载iOS设备Remote的app

在iOS设备上安装Remote完毕后 ,在iTunes中输入 iOS屏幕显示的适配码即可配对(同一个局域网内)

操作方式如同iOS自带音乐播放器一样,只是声音是从Mac上播放的…躺在床上也可以换歌~

Quick Time
Quick Time是Mac中的视频播放器,但由于它内置编码很少,一些电影不支持播放  我们用第三方的播放软件,所以Quick Time的亮点不在于‘播放电影’而是录制/剪辑
使用Quick Time录制‘影片(电脑摄像头录制)’ ‘录音’‘屏幕录制’

影片录制,首先,点击上方菜单栏中的‘文件’-‘新建影片录制’,出来一个窗口,随之摄像头便开启


录制完后,它会储存在Mac上,如果喜欢也可以分享到优酷/土豆/邮件/信息上

音频录制,也是点击上方菜单栏中的‘文件’-‘新建音频录制’,出来一个窗口,电脑内置的麦克风会开启,也可以选择外置麦克风

屏幕录制,点击上方菜单栏中的‘文件’-‘新建屏幕录制’,屏幕录制就是 可以录制整个屏幕的操作,一些视频电脑教程就是这样录制的

修剪视频,如果喜欢一个电影片段而不像保留整个,那么可以使用剪辑,把需要的部分保留下来,点击菜单栏‘编辑’—‘修剪’,快捷键是⌘T

接着,拖动两端的黄色选框边缘,选框内即是需要保留的片段,按下‘修剪’,黄框之外的片段便被剪掉

修剪音频,有一首歌,想制作成铃声,但时间太长怎么办?也可以使用Qiuck Time中的修剪功能
先把要修剪的歌曲拖到Qiuck Time中播放,点击菜单栏‘编辑’—‘修剪’,快捷键是⌘T
拖动两端的黄色选框边缘,选框内即是需要保留的音频,按下‘修剪’,黄框之外的音频便被剪掉

iCloud
iCloud 不仅可存储你的内容,还可让你在所有设备上访问你的照片、日历、通讯录、文档以及更多内容。十分方便,在Mac下编辑好的通讯录、备忘录、日历等信息会通 过iCloud自动同步到iOS设备上,同时 在iOS设备上 照的照片以及修改的文稿也会通过iCloud回传到Mac上…

点击查看Apple官方iCloud说明     点击访问iCloud
首先需要开启iCloud账号,iCloud账户有两种,一种是有iCloud邮箱账户,这个需要重新注册以@me@iCloud结尾的账户;另一种就是普通邮箱也可以注册的iCloud账号,但是‘邮件’这个功能是无法使用的,需要单独在“邮件”程序中单独设置

在”系统偏好设置”中点击 iCloud,输入你的 Apple ID,然后选择要启用的服务
邮件:此功能需要iCloud邮箱开启
通讯录:可以与iOS上的通讯录同步,或在iCloud上备份
日历与提醒事项:在日历中添加的任务可自动同步到iOS设备上,提醒事项也是如此
Safari:同步Safari中的标签页 以及在iOS上浏览过的网页
照片流:简单来说就是在iPhone上照张照片,立即会在Mac的iPhoto中出现~~借给朋友时 应该把此项功能关闭
文稿与数据:iWork办公套件,在iPhone上修改文稿的时候 会自动同步到Mac上,还有游戏存档~~
回到我的Mac:简单意思就是远程访问,复杂的来说 我也没有用过……
查找我的Mac:与查找我的iPhone一样,丢了 被偷了可以找回来(除非那贼太笨或压根就是个苹果白痴…个人建议在‘关闭’这个功能的时候也要输入账户密码)


日历
日历就不用多说了,但我想说的是教大家 添加农历日历(还有很多比如天气/节日等)
首先,打开‘日历’在‘文件’中选择‘新建日历订阅…⌥⌘S’,订阅日历就是 引用一些大家在网上分享的日历任务,

之后,输入订阅地址(订阅地址下面提到)

订阅之后,日历会添加农历,注意:在‘显示简介’要‘移除’‘提醒’和‘附件’,不然每天都会提醒你一遍,即使Mac上不烦在iPhone上也会烦的

之后就完成了!点击可查看每天的‘任务’

想要删除也十分简单,在左侧边栏中找到想移除的‘日历’,右键‘删除’即可…

订阅日历
2013年农历:

  1. https://www.google.com/calendar/ical/jhkliqpl%40126.com/public/basic.ics


2012、2013农历+星期+节日:

  1. http://www.google.com/calendar/ical/mnmnscg3edii9e97dvbphoreh0%40group.calendar.google.com/private-2125576945eac72a7efa790e43a83a71/basic.ics


2013节日星期农历黄历:

  1. https://www.google.com/calendar/ical/anjg3tsnm6aanh4tj8db3f42j4%40group.calendar.google.com/public/basic.ics

Time Machine
Time Machine是可以与 Mac 和外置硬盘或 Time Capsule 配合使用来备份 整个Mac的文件,包括系统文件、应用软件、帐户、偏好设置、电子邮件、音乐、照片、影片和文稿
而 Time Machine 与其他备份应用软件的区别在于它不仅能备份所有文件,还能够记住系统在任意一天的显示状态,因此可以重新访问 Mac 在过去某个时段的显示状态(像时光机器一样)。Time Machine 会保留过去 24 小时的每小时备份、过去一个月的每日备份及每周备份,直到备份硬盘撑死为止。

点击查看Apple官方Time Machine说明
备份硬盘大致有三种选择
   外置硬盘:品牌无所谓,后期需要把硬盘格式转成“mac os x扩展日志式 ”
Time Capsule:苹果自家的无线硬盘/路由器,目前有2TB和3TB版本,价格略高
硬盘分区:这个方法有种脱裤子放屁的味道~给喜欢折腾的用户吧

首先,在拿到新电脑的时候,右上角会有个类似时间的图标,这个就是Time Machine 标志,点击‘打开Time Machine 偏好设置…’即可开始设置Time Machine
从中可是设置 备份周期,需要备份的文件等,初次备份的时候因为要备份整台电脑的文件,大概需要一个通宵的时间来备份,之后每天/每周/每月的备份所需时间就少了

把要用于Time Machine 备份的移动硬盘插入电脑(最后专门准备个 用于Time Machine 备份的硬盘),用于手头没有Time Capsule,就拿移动硬盘了~~

如果不想在右上角的菜单栏里显示这个图标,在偏好设置中下部的“在菜单栏中显示Time Machine ”的选项√划掉即可

具体操作说明 看Apple官方出的视频教程,我就不在这里班门弄斧了
具体 点击查看 Apple官方录制的Time Machine教程 (讲的比较清晰)

分享功能
分享是Mountain Lion 中新添加的功能,在Mac上总是能找到”分享“按钮的
你可以通过 Mail、信息及 AirDrop 分享照片、视频及其他文件,甚至还可以从 Safari 上发送链接。只需点击几下,即可直接将内容发布到新浪微博、优酷、土豆上。

首先,这一切都是需要设置的,打开‘系统偏好设置’中的“邮件、通讯录、日历”面板,从中你可以设置 土豆/优酷/新浪微博/和一些上不去的网站

例如,在‘预览’程序中 要分享图片至新浪微博上,可以点击 分享 按钮,并分享至‘新浪微博’即可

输入上你要说的话,即可‘发送’~也可以添加‘定位’信息

也可以通过‘信息’的方式发到好友的手机上(苹果设备),一切都是免费的

设置‘信息’ iMessage,需要打开‘信息’程序,找到偏好设置,这个账户要和你iPhone上的账户一致

使用 iMessage 发信息,可以向任何运行 iOS 5/6的 iPhone、iPad 或 iPod touch 用户发送信息。信息会在你的 Mac 及你使用的任何设备上显示,就可以在 Mac 上开始对话,然后无论走到哪里都能在 iPhone 或 iPad 上继续进行。你还可以发送照片、视频、文档和通讯录,甚至发送群组消息。

分享视频到优酷/土豆
首先,在你要分享的视频(一般为mp4格式)右键,找到‘共享’,优酷或者土豆,即可分享到视频网站上


通知中心
新消息总会在 Mac 的某处即时弹出,如电子邮件、信息、软件更新或日历提醒等,通知中心会让你轻松掌握所有情况
通知横幅总会在你桌面上的同一位置出现,然后迅速消失,只要从右向左轻扫触控板,所有通知便会在通知中心里

唤出通知中心十分简单,只需双指从触摸板外向左滑即可,或 在菜单栏右上角 “

如果要设置一些项目程序的通知方式,可以在‘系统偏好设置’中的‘通知’设置
从中可以设置一切的提醒方式
:即不提醒通知
横幅:提醒用户,变回向右滑动消失
提示:可以从中操作通知选项

用户甚至可以在通知中心发布‘新浪微博’,只需把相应的‘在通知中心显示分享按钮’即可发布

系统信息
当我们买了一台新的Mac后,通过‘系统信息’可以来查看当前电脑的信息,以及硬件配置
在系统信息中可以查看Mac中所有的信息,系统、内存、显示器、储存、内存、显卡、电池等等…
新买Mac,首先,在菜单栏中点击“”,‘关于本机’,这里显示的是大致信息,以防您买错型号,点击‘更多信息’可以查看 硬件/显示器/存储/内存/保修状况…

弹出一个窗口,选择你要查看的内容,有处理器,内存,显卡,序列号等基本信息。单击‘系统报告…’可启动‘系统信息’程序

选择‘内存’可查看基本内存信息以及插槽数量,用户可自己拆机升级内存(Macbook Pro),更换内存是不影响保修的,这大家不用担心
点击“内存升级说明”可查看Apple官方制作的拆机说明,内容详细。主要选中内存的时候尽量选择同一型号/品牌/大小的,最好成双成对的选择

服务’是可以查询Apple对用户的服务范围,包括保修期限,保修状态。不用 死记硬背几下 序列号 再输入查询,直接点击 即可转到Apple官网 查询

再让我们看看‘系统信息’这个程序,这个程序比‘关于本机’要强大和详细,这个相当于win下的 设备管理器
左边是项目栏,可以选择需要查看的目录,右边则是详细信息,界面和查看方式要比win简洁明了

如何确保我的Mac是全新的呢?除了包装和激活系统
查看‘电源’也是个很好的方法,此方法适用MacBook,这里能查看Mac电池的使用状况,包括容量、实际容量、电池循环(在下面讲解电池)
电池循环通俗讲就是电池使用次数,也间接的表明了这台电脑的使用情况,一般刚拆封的MacBook 循环计数为0或1

    关于电池—锂聚合物电池

目前,可充电锂聚合物电池为你的Mac笔记本电脑、iPod 或 iPhone提供动力
锂离子聚合物电池的功率密度更高。一块电池即可提供很长的使用时间。可以随时为锂离子聚合物电池充电,而无需进行完全的充放电。也就是说新买的Mac没必要用到完全没电的时候再充电(这样反而损坏锂电池),或一次性充电十几个小时,总之 充满就好
正确的用法就是能充就充,尽量插着电源使用, 因为Mac在电量剩余95%以上的时候 是不向电池充电的,也就是说插着电源用实际上是在使用的电源电,不是电池里的电。所以就会看到 即使插着电源,菜单栏里的电池项目会显示>95%的数字,当低于95% 电池才会充电,充到100%,第二天打开电脑看剩余电量为99%而不充电,这是正常的!但 至少每月为电池充电、放电一次

充电周期与电池循环
大多数锂离子聚合物电池均采用一种快速充电方式,可迅速为你的设备充满 80% 的电量,然后再转换为连续补充式充电方式继续充电。
在Mac上,电锂电池的充电/放电次数是有限制的,可以实现多达1000次完全充电和放电循环,在‘系统信息’程序 中可查看当前循环次数
关 于电池循环的解释:一次充电循环意味着用完电池的全部电量,但不一定意味着进行一次充电。例如,某天您可能使用笔记本电脑一个小时或更长时间,用完一半电 量后即重新充满。如果第二天仍是如此,则可计为一次(而不是两次)充电循环,因此,一次充电循环是将之前用过的电量做加法合 计算的。

注意:请避免在夏天将Mac 锁在高温的车内或汽车后备箱中
10° 到 35° C 是运行电脑和锂电池的适宜温度
-25° 到 45° C 是存放笔记本电脑的适宜温度

电池是个损耗商品,无论怎样呵护与保养,它都是有寿命的,提醒各位要理性对待,不要让电池健康度与循环次数影响了用户使用电脑的体验,‘电池’这都是可以更换的!

光盘刻录
在Mac中无论是音乐光盘还是数据光盘 甚至是镜像光盘,这些全部都能搞定!
我分别讲解这几种光盘是怎么刻录的,不需要第三方软件,在Mac自带的程序中即可!
首先是先让大家了解一下常见的光盘分为哪几种,刻录的基本小常识

CD-R          容量700M 或80分钟音频/视频    不可重复擦写     容量小,刻录速度快,耗时短
CD-RW       容量700M 或80分钟音频/视频  可重复擦写
DVD±R       容量4.7G  或120分钟音频/视频  不可重复擦写    容量是CD的6倍,多用于数据备份
DVD±RW    容量4.7G  或120分钟音频/视频   可重复擦写
DVD-RAM   容量4.7G  或120分钟音频/视频  可重复擦写    比DVD±RW使用更方便
DVD±R DL  容量8.5G  或240分钟音频/视频  不可重复擦写    单面双层DVD,是普通DVD的2倍容量
BD蓝光       容量25G   或130分钟音频/视频  不可重复擦写    超大容量但Mac不可刻录

再来看看刻录的类型有哪些
数据光盘:顾名思义就是可以刻录文件,与U盘的方式差不多,受光盘容量限制,使用Finder刻录
音乐光盘:就是CD,可以在播放机中播放的光盘,受刻录时间限制,使用iTunes刻录
视频光盘:就是DVD,可在播放机中播放,受刻录时间限制,使用iDVD刻录
镜像光盘:系统光盘/安装光盘,ISO镜像文件,受光盘容量限制,使用‘磁盘工具’刻录

    数据光盘
当我们插入光盘的时候,会出现一个窗口,这个窗口问你要用什么程序打开,这无形中的意思就是问你要刻录什么类型的光盘

接着打开Finder,在左边栏里 出现了‘光盘’这个文件夹,如同U盘一样,这样就可以把需要刻录的文件拖进去就行了
大小限制是根据你用的是什么光盘,VCD就700MB,DVD达到4.7GB
拖进去的文件会以‘替身’的方式显现,当选择好文件之后,按下‘小辐射’图标或右上角的‘刻录’即可刻录光盘!

    音乐光盘
刻录音乐光盘 可以在汽车内的CD中播放
在插入光盘后显示的窗口中 选择在iTunes中打开光盘

打开iTunes,从歌曲曲目库中找到你想刻录的歌曲。点击上方菜单栏的‘文件’-‘新项目’-‘播放列表’快捷键是command+n
再把你之前选中的歌曲,拖到这个新建的播放列表里,可以给这个新播放列表重命名,然后选中这个播放列表‘右键’选择‘将播放列表刻录到光盘’

在选择完之后,会弹出一个窗口,这个窗口是设置刻录光盘的基本信息
选择‘音乐光盘’就是刻录CD,注意:音乐光盘的限制是VCD光盘80分钟,DVD光盘120分钟,也就是说 播放列表中的歌曲时间累加在一起 要在这个时间之内
如果选择‘数据CD或DVD光盘’,这个效果和在Finder里刻录的数据光盘是一样的,数据光盘的限制是VCD光盘700MB,DVD光盘4.7GB,也就是播放列表中歌曲大小累加一起要在这个容量之内,不过一些 播放机和汽车音响是识别数据光盘播放的

     视频光盘
打开iDVD这个程序(我觉得没什么用 给删了= =)
刻录DVD大致的方法就是,首先确定你要刻录的视频,或者从iMovie中制作的电子相册
新建一个项目,里面有一些模版,就是DVD播放的开始界面和选集目录,挑选一个你喜欢的
把项目视频直接拖进模版里,然后就可以刻录DVD了

     镜像光盘
接下来 着重讲一讲刻录镜像光盘,镜像光盘在日常生活中十分常用,比如系统安装光盘,软件光盘等,都是iso镜像光盘
在目前的Mac中已经取消了系统光盘,但可以DIY刻录一张,以备不时之需,刻录系统需要DVD光盘
这是一个从OS X10.8中提取的镜像文件

在‘实用工具’中打开‘磁盘工具’,点击刻录 出来一个窗口,选择你准备好的镜像文件,点击‘刻录’

接着就是刻录设置了,基本上不用更改,点击刻录……

N分钟后 热乎乎的系统光盘便出炉了,是不是很简单?

磁盘工具
磁盘工具是Mac中最为重要的系统工具之一,一切硬盘上的问题可以由它解决
当电脑不好用的时候,一些程序文件出现错误的时候,可以尝试尝试“磁盘修复权限”
在Mac中,文件是有权限的,为了保证用户不会篡改重要的文件而影响系统,所以‘修复磁盘权限’就是修文件的权限
打开‘实用工具’中的‘磁盘工具’,左侧是项目栏,能够选取需要的 磁盘,包括镜像文件、光盘、移动硬盘、U盘等……总之,一切需要装载/推出的文件
点击‘修复磁盘权限’可以修复文件的权限,以保证文件的安全和文件的有效;而‘修复磁盘’是可以检验和修复磁盘的问题,比如数据丢失 硬盘坏道等,如果损坏比较严重这是需要修硬件了

另一个比较常用的功能—格式化硬盘
在日常生活中 我们离不开U盘或移动硬盘,在Mac中 格式化硬盘也是在磁盘工具中完成的
一般全新的硬盘格式为NTFS,为Mac专用的硬盘一般为Mac OS 扩展 日志式
介绍几种常见格式
Mac OS 扩展(日志式):Mac最常用的格式,也是系统硬盘的格式,如果U盘和移动硬盘只在苹果电脑间使用那么用这个格式就好
Mac OS 扩展(日志式区分大小写):区分大小写是区分于 Mac OS扩展日志式 最大的区别,比如在这个格式下 同一名称文件 大写和小写会共同存在,尽量不要选这个会出现兼容性问题
FAT:在Mac和Win下都可以使用的硬盘格式,但对于文件大小有限制 一般文件不能超过4GB
ExFAT:在Mac和Win下可以使用,一般多为U盘格式,WinXP需要装驱动,ExFAT在Mac下读取速度一般
NTFS(compressed):(Win7)如果U盘和硬盘在Win和Mac之间使用的话,NTFS绝对是首选,Mac+Win最好选此
NTFS:这个版本比较老,U盘和硬盘在Win和Mac之间使用

插入U盘或硬盘,打开‘磁盘工具’选择你需要格式化的硬盘,在‘抹掉’中选择你需要的格式,由于我这个是4G的U盘,所以FAT是最好的选择,Win与Mac公用

NTFS
由于NTFS是微软的专利,所以在原生Mac下是只能读取,不能写入的,所以在Mac下需要第三方插件来支持读取NTFS,安装也是很方便的
Mac中NTFS插件有很多,比如Tuxera NTFS、Paragon NTFS、PropEdit、NTFS-3G等

点击查看 NTFS插件 帖子
点击下载 威锋盘 NTFS插件

  硬盘分区
从 Win过渡到Mac的用户 再使用后有疑虑 ‘为什么Mac没有 C/E/F等磁盘呢?’,这是因为Mac电脑没有硬盘分区的概念,也就是说Mac使用的是一整块硬盘空间来使用,而不像Windows 把硬盘划分很多空间区域。使用Boot Camp安装双系统(windows)时 需要硬盘分区
也就是说在Mac上 分区 完全靠用户自愿的。例如 你可以创建一个分区来用作Time Machine 备份,但硬盘出了问题 分区也是无药可救的。所以分区带来的益处在Mac上是微乎其微
Mac电脑上其实自带有两个分区,另一个分区属于隐藏分区 起到恢复盘的作用,所以在新电脑盒子里找不到传统的”系统恢复光盘”,在开机时按下option可以看见它,它叫“Recovery HD

硬盘分区也是需要由“磁盘工具”完成的,在‘实用工具’中找到它,打开
在左侧边栏找到你需要的分区的硬盘,这里我以移动硬盘为例(在分区之前请先备份一下),之后选择你需要分区的数量1~16,2个分区的涵义就是把这块硬盘划分为2为空间

在选择2个分区后,会出现2块区域,拖动之间的滑棍 可以调节这2块分区的容量空间分配
格式,格式可以参考上面的信息,根据自己需要找到合适的格式。大小,也可以手动输入容量空间的数值

之后,点击应用,热腾腾的硬盘出锅!

  磁盘镜像
磁盘镜像是可以将镜像文件(系统安装文件)投入到U盘之中,使之达到安装光盘一样的效果,适用于没有光驱的电脑安装或恢复系统
首先 打开磁盘工具程序,同时插入你需要被制成镜像的U盘(如果是OS X系统 需要8GB的U盘)根据刻录大小而定

在左边栏找到你的U盘或移动硬盘,在项目分栏中点击“恢复”,“恢复”具体涵义是指 将现成已有的镜像文件(dmg Iso)恢复到硬盘/U盘之中

之后,把你需要被刻录的镜像文件 拖入“源磁盘”之中,也可以点击“映像…”选取文件

“目的磁盘”是需要被刻录的U盘或硬盘,拖入其中就可

在检查一遍所选取的内容是否有错,最后 点击“恢复”即可

钥匙串访问
钥匙串访问是顾名思义就是Mac中的钥匙,它在‘危机’时刻十分管用!!(要利用它的好处)
比如 QQ号忘了密码 可以在这里面查看 找到你当初的QQ号密码,邮箱密码忘了 也可以在这个程序中找到密码,是不是有点毛骨悚然的感觉,你的一切密码都在这里
首先我就不拿QQ密码举例了…我拿WIFI密码来举例, 比如你拿Mac去好友家上网,但好友很抠门,捂着键盘输入密码,但利用‘钥匙串访问’就能一览无余~~
在‘应用程序’文件夹中找到‘实用工具’文件夹 找到“钥匙串访问”,打开程序,这个程序窗口很单一,操作也很简单,具体自己点两下就了解了!
找到WIFI的项目,首先是要找到WIFI的名称了(这个容易鉴别),双击之后弹出一个窗口,这个就是着串‘钥匙’的具体信息了~在查看密码前需要鉴定用户密码(登录密码)
在输入你自己的密码后 ,把‘显示密码’√划上,就能查看别人WIFI的‘密码’了~  这只是一个例子,更多的是在找不到密码的危急时刻使用

这是是抛砖引玉,强大的钥匙串访问 不止看看密码这么简单,具体深奥的用法  本人不才,各位探索~

  Boot Camp双系统
需要Windows?可以!在Mac中Boot Camp助理可以让你使用Windows,一台电脑,两个系统!
什么是Boot Camp?Boot Camp 是可以让您安装Windows 安装光盘和在 Mac 电脑上运行 Windows的助理。Windows 将被安装在Mac的另一个分区上,所以安装双系统 需要分区
切换Mac/Win系统也是十分的方便,重新启动或启动电脑时按下option键 即可选择当前需要的操作系统,相互切换系统需要重启,也就是说一台电脑有两种状态,一种是Mac状态,一种是Win状态,它们相互生存 互不打扰。
前 期准备:Windows安装光盘,没有光盘或插不了光盘可以制作一个U盘镜像  与光盘效果一样。iMac台式机用户需要注意了:在未安装 驱动之前 蓝牙的Magic Mouse鼠标和 Wireless Keyboard键盘是无法使用的,无法操作电脑的!因此需要一个无线(不是蓝牙)或有线的键盘鼠标。

看看具体步骤吧 我以普遍的安装方式安装,首先在“实用工具”中找到“Boot Camp助理”。点击‘继续’

有些人可能没有“创建更高版本的安装盘” 所以不用勾上。第 二个重要啦,“从Apple下载Win支持的软件”这里指的是驱动以及蓝牙鼠标键盘和摄像头等的驱动,以便在Windows中使用,但 苹果服务器的网速我想大家都知道,很慢,而且这个驱动也将近1GB左右,网速快的和iMac没有有线鼠标键盘的同学可以选择勾上,不过在安装完Win后可 以手动下载,所以只是早晚下载的事儿。第三个“安装Win7或更高版本”勾上,除非安XP(XP比较费工夫)
Apple官方更新BootCamp
手动下载BootCamp驱动连接

接下来会看到一个分区调整的界面,插入安装光盘或安装U盘,拖动中间滑棍来调整Mac与Win的硬盘容量划分,根据自己使用情况而定

电脑会自动分区,如果提示分区失败,可以打开‘磁盘工具’程序 修复一下磁盘权限即可,分区完毕,电脑会黑屏 重启

之后,熟悉的Windows安装界面出现了,这里的安装也是十分重要,关系着Windows安装的正确与否
选择“自定义(高级)”,从中可以自定义安装 路径或磁盘

接着,十分重要的界面出现了!这不仅关系着Windows的性命,同时也关乎着你的Mac系统的性命!小心!仔细!
一定一定要选择 之前划分的BootCamp分区,选择分区后 点击“驱动器选项(高级)”

点击“格式化”,格式化BootCamp这个分区,已达到Windows需要的分区格式

之后的步骤就是等待安装了,安装步骤一切顺利后 Windows启动,一切都是你熟悉的Windows,之前没有安装驱动可以下载安装驱动

启动或重新启动电脑时按住option键 可以选择当前需要启动哪一个系统

虚拟机
双系统太繁琐?寻求最简单使用Windows?虚拟机是首选!
虚拟机是另一种可以在Mac上使用Win的工具,它要比BootCamp双系统要简单,同时也很方便,相互切换也不必重启电脑,只是像打开一个软件一样简单,更不用硬盘分区
虚拟机可以看作是Mac的一个软件,利用这个软件来模拟使用windows,也就是说一台电脑以Mac系统为基础 可以同时运行两个系统和同时运行Mac和Win的应用程序
就像这样,是不是很酷呢,可以运行Windows、Linux 甚至 Google Chrome OS等操作系统

目 前普遍使用的虚拟机有两个 Parallels Desktop(简称PD)和VMware Fusion(简称VM) ,这俩孰优孰劣目前不能定夺,各有优缺,PD用的人多  界面华丽,VM操作简单 稳定性强。很多基本的功能两者都是相似的(目前最新版本都是支持Windows8)

Parallels Desktop目前在Apple Store上正版售价为¥298,使用PD 需要激活码,目前网上售卖的激活码也在¥188左右
点击 ParallelsDesktop威锋盘下载

VMware Fusion目前在Apple Store上正版售价为¥319,VM相比PD 要容易破解
点击VMware Fusion威锋盘下载

接着 我以 VMware Fusion为示范安装windows7
需要Windows7安装光盘(要求是‘纯洁版’的)或者制作好的U盘安装镜像 ,或者直接在电脑上下载windows的ISO镜像安装包
打开虚拟机选择安装方式
‘新建’就是新建一个虚拟机的操作系统,一般选这个。‘新建Boot Camp’就是把目前有的BootCamp双系统导入虚拟机中

插入光盘,确定是需要安装的系统后点击‘继续’

接 着,选择Windows的安装类型(集成),有“更加无缝”和“更加独立”两种方式,更加无缝就是Mac中的文件会在Win中同步显示,在Win删除一个 文件则Mac中这个文件也会消失。更加独立则是这个Windows就是全新的,Win与Mac互不打扰,但之间可以共享和传输拷贝文件/文字。个人和多数 人都选择的是“更加独立”,视自己习惯而定

下一步,‘完成’,其中有分配给虚拟机的性能,后期可以再设置调整,点击完成,会弹出窗口,选择你想要存储的位置,保存Windows系统的虚拟机文件,这个文件比较大(20GB左右)

这个文件就是Windows系统所需的文件,在Finder中就能找到它

剩 下的步骤就属于Windows安装步骤了,基本上是比较顺利的步骤。虚拟机会重新启动,熟悉的Windows便会启动(注意:虚拟机会耗大量的内存,请把 Mac上不需要的程序退出,预留内存给虚拟机使用),之后在Win上会按照各种驱动和插件,虚拟机上Win的网络会桥接Mac的网络使用,系统之间的拷贝 文件/文字就像在一个系统中操作那样方便。
不需要Windows时,和正常一样,在菜单中选择‘关机’,Windows会关机,直到黑屏后 再关闭 退出虚拟机,不然下次打开虚拟机会恢复未关机的Windows 耽误时间。

双系统与虚拟机
通过以上安装与使用方式  可以辨别BootCamp双系统和虚拟机的利与弊,优与缺

这是张以按照 电脑的100%性能为标准,比如内存、CUP等,蓝色代表Mac的性能量,红色代表Win的性能量,与此比较便可大致 明确虚拟机与双系统之间的性能差距

这是为什么呢?与双系统和虚拟机的特性相关联。
BootCamp双系统的Win与Mac切换时需要重启电脑,之间的两个系统只许运行一个,一台电脑的硬件专心奉献与一台系统
VM/PD虚拟机,它们只是一个Mac的应用程序,在Mac的基础上运行Win,切换系统时只需切换桌面样便捷,但一台电脑的硬件要供足两部系统来使用,由于虚拟机要耗费大量内存,最好再扩大一下电脑内存

那双系统好还是虚拟机好呢?根据它们的特性与自己需求来选取
虚拟机:安装简单,启动方便 快捷,两部系统可同时使用,相互切换便捷,但由于性能 只可在Win上运行小量程序,比如上上网 用用网银 看看电影 小游戏…虚拟机是首选
双系统:纯正安装Windows,性能比虚拟机强大,根据需求选用启动,日常可以 运行大游戏  专业性软件  适合大量运算…

Android Fragments 详细使用

Fragments 诞生初衷

自从Android 3.0中引入fragments 的概念,根据词海的翻译可以译为:碎片、片段。其上的是为了解决不同屏幕分辩率的动态和灵活UI设计。大屏幕如平板小屏幕如手机,平板电脑的设计使得其有 更多的空间来放更多的UI组件,而多出来的空间存放UI使其会产生更多的交互,从而诞生了fragments 。fragments 的设计不需要你来亲自管理view hierarchy 的复杂变化,通过将Activity 的布局分散到frament 中,可以在运行时修改activity 的外观,并且由activity 管理的back stack 中保存些变化。

 

      Fragments 设计理念

在设计应用时特别是Android 应用 ,有众多的分辨率要去适应,而fragments 可以让你在屏幕不同的屏幕上动态管理UI。例如:通讯应用程序(QQ),用户列表可以在左边,消息窗口在右边的设计。而在手机屏幕用户列表填充屏幕当点击 某一用户时,则弹出对话窗口的设计,如下图:

Fragments的生命周期

每一个fragments 都有自己的一套生命周期回调方法和处理自己的用户输入事件。 对应生命周期可参考下图:

其中大多数程序必须使用Fragments 必须实现的三个回调方法分别为:

onCreate

系统创建Fragments 时调用,可做执行初始化工作或者当程序被暂停或停止时用来恢复状态,跟Activity 中的onCreate相当。

onCreateView

用于首次绘制用户界面的回调方法,必须返回要创建的Fragments 视图UI。假如你不希望提供Fragments 用户界面则可以返回NULL。

onPause

当用户离开这个Fragments 的时候调用,这时你要提交任何应该持久的变化,因为用户可能不会回来。更多的事件可以参考上图的生命周期关系图。

Fragments 的类别

系统内置了三种Fragments ,这三种Fragments 分别有不同的应用场景分别为:

DialogFragment

对话框式的Fragments,可以将一个fragments 对话框并到activity 管理的fragments back stack 中,允许用户回到一个前曾摒弃fragments.

ListFragments

类似于ListActivity 的效果,并且还提供了ListActivity 类似的onListItemCLick和setListAdapter等功能。

PreferenceFragments

类似于PreferenceActivity .可以创建类似IPAD的设置界面。

 

Fragments 的详细使用

首先先来看一张DEMO 效果图:

左边点击时,右边的字符会与左边选中的项的字符相同。与IPAD上的设置界面很相似,这一点是否借鉴了ipad 上的UI呢?

相就的XML文件:

复制代码

<?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=”horizontal” >

<fragment class=”com.xuzhi.fragment.FragmentDemoActivity$TitlesFragment” android:id=”@+id/titles” android:layout_weight=”1″
android:layout_width=”0px” android:layout_height=”match_parent”
/>

<FrameLayout android:id=”@+id/details” android:layout_weight=”1″ android:layout_width=”0px” android:layout_height=”match_parent”
android:background=”?android:attr/detailsElementBackground”
></FrameLayout>
</LinearLayout>

复制代码

 

 

主界面代码(己做注释):

 

复制代码

package com.xuzhi.fragment;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.app.ListFragment;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.TextView;

public class FragmentDemoActivity extends Activity {

public static String[] array = { “text1,”, “text2”, “text3”, “text4”,
“text5,”, “text6”, “text7”, “text8” };

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}

public static class TitlesFragment extends ListFragment {

boolean mDualPane;
int mCurCheckPosition = 0;

@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
System.out.println(“Fragment–>onCreate”);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
System.out.println(“Fragment–>onCreateView”);
return super.onCreateView(inflater, container, savedInstanceState);
}

@Override
public void onPause() {
// TODO Auto-generated method stub
super.onPause();
System.out.println(“Fragment–>onPause”);
}

@Override
public void onStop() {
// TODO Auto-generated method stub
super.onStop();

System.out.println(“Fragment–>onStop”);
}

@Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
System.out.println(“Fragment–>onAttach”);
}

@Override
public void onStart() {
// TODO Auto-generated method stub
super.onStart();
System.out.println(“Fragment–>onStart”);
}

@Override
public void onResume() {
// TODO Auto-generated method stub
super.onResume();
System.out.println(“Fragment–>onResume”);
}

@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
System.out.println(“Fragment–>onDestroy”);
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onActivityCreated(savedInstanceState);
System.out.println(“Fragment–>onActivityCreted”);
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, array));

View detailsFrame = getActivity().findViewById(R.id.details);

mDualPane = detailsFrame != null
&& detailsFrame.getVisibility() == View.VISIBLE;

if (savedInstanceState != null) {
mCurCheckPosition = savedInstanceState.getInt(“curChoice”, 0); //从保存的状态中取出数据
}

if (mDualPane) {
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);

showDetails(mCurCheckPosition);
}
}

@Override
public void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
super.onSaveInstanceState(outState);

outState.putInt(“curChoice”, mCurCheckPosition);//保存当前的下标
}

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
// TODO Auto-generated method stub
super.onListItemClick(l, v, position, id);
showDetails(position);
}

void showDetails(int index) {
mCurCheckPosition = index;
if (mDualPane) {
getListView().setItemChecked(index, true);
DetailsFragment details = (DetailsFragment) getFragmentManager()
.findFragmentById(R.id.details);
if (details == null || details.getShownIndex() != index) {
details = DetailsFragment.newInstance(mCurCheckPosition);

//得到一个fragment 事务(类似sqlite的操作)
FragmentTransaction ft = getFragmentManager()
.beginTransaction();
ft.replace(R.id.details, details);//将得到的fragment 替换当前的viewGroup内容,add则不替换会依次累加
ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);//设置动画效果
ft.commit();//提交
}
} else {
new AlertDialog.Builder(getActivity()).setTitle(
android.R.string.dialog_alert_title).setMessage(
array[index]).setPositiveButton(android.R.string.ok,
null).show();
}
}
}

/**
* 作为界面的一部分,为fragment 提供一个layout
* @author terry
*
*/
public static class DetailsFragment extends Fragment {

public static DetailsFragment newInstance(int index) {
DetailsFragment details = new DetailsFragment();
Bundle args = new Bundle();
args.putInt(“index”, index);
details.setArguments(args);
return details;
}

public int getShownIndex() {
return getArguments().getInt(“index”, 0);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// TODO Auto-generated method stub
if (container == null)
return null;

ScrollView scroller = new ScrollView(getActivity());
TextView text = new TextView(getActivity());

int padding = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 4, getActivity()
.getResources().getDisplayMetrics());
text.setPadding(padding, padding, padding, padding);
scroller.addView(text);

text.setText(array[getShownIndex()]);
return scroller;
}
}
}

复制代码

注意:

 

  1. 如果你想在Fragment 里面创建menu,则必须在onCreate的时候设置让它可以存在optionMenu才可以创建,代码为:
    复制代码
    public static class DetailsFragment extends Fragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
    }
    }

    复制代码

    之后的操作即可以像平常Android的menu用法一样,代码为:

    复制代码
    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    // TODO Auto-generated method stub
    super.onCreateOptionsMenu(menu, inflater);
    menu.add(“Menu 1a”).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
    menu.add(“Menu 1b”).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
    // TODO Auto-generated method stub
    Toast.makeText(getActivity(), “index is”+getShownIndex()+” && menu text is “+item.getTitle(), 1000).show();
    return super.onOptionsItemSelected(item);
    }

    复制代码

更多详细的使用方法,请参考SDK和APIDEMO中相关的例子和解释。

DEMO下载:

Android基础类之BaseAdapter

BaseAdapter就Android应用程序中经常用到的基础数据适配器,它的主要用途是将一组数据传到像ListView、Spinner、Gallery及GridView等UI显示组件,它是继承自接口类Adapter,
1、Adapter类简介
1)、Adapter相关类结构如下图所示:
Adapter
自定义Adapter子类,就需要实现上面几个方法,其中最重要的是getView()方法,它是将获取数据后的View组件返回,如ListView中每一行里的TextView、Gallery中的每个ImageView。
     2)、Adapter在Android应用程序中起着非常重要的作用,应用也非常广泛,它可看作是数据源和UI组件之间的桥梁,其中Adapter、数据和UI之间的关系,可以用下图表示:
t2A9A
3)、常用子类
Adapter常用子类
2、BaseAdapter简介
BaseAdapter是实现了ListAdapter和SpinnerAdapter两个接口,当然它也可以直接给ListView和Spinner等UI组件直接提供数据。
相关类结构如下图所示:
tCCA2
3、示例
示例一:Gallery显示一组图片
运行结果:

说明:上面一行图片是Gallery画廊,每次点击一个Gallery图片时,会同时在下面以大图形式显示出来该图片
布局文件:

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:orientation=”vertical”
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
>
<TextView
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”@string/hello”
/>

<Gallery
android:id=”@+id/gallery1″
android:layout_width=”match_parent”
android:spacing=”5px”
android:layout_height=”wrap_content”
></Gallery>
<ImageView
android:id=”@+id/iv”
android:layout_gravity=”center_vertical”
android:layout_marginTop=”20px”
android:layout_width=”320px”
android:layout_height=”320px”
></ImageView>

</LinearLayout>

MainActivity类:
package com.magc.adapter;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.AdapterView.OnItemClickListener;

public class MainActivity extends Activity {
private Gallery gallery;
private ImageView imgview;
private int[] imgs = {R.drawable.a6,R.drawable.a1,R.drawable.a2,R.drawable.a3,R.drawable.a4,R.drawable.a5};
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
imgview = (ImageView)findViewById(R.id.iv);
gallery = (Gallery)findViewById(R.id.gallery1);
MyImgAdapter adapter = new MyImgAdapter(this);
gallery.setAdapter(adapter);
gallery.setOnItemClickListener(new OnItemClickListener() {
//用户点击图片时,将该图片的ResourceID设到下面的ImageView中去,
@Override
public void onItemClick(AdapterView<?> arg0, View view, int position,
long arg3) {

imgview.setImageResource(imgs[position]);

}
});
}

class MyImgAdapter extends BaseAdapter {
//自定义图片Adapter以内部类形式存在于MainActivity中,方便访问MainActivity中的各个变量,特别是imgs数组
private Context context;//用于接收传递过来的Context对象
public MyImgAdapter(Context context) {
super();
this.context = context;
}

/* (non-Javadoc)
* @see android.widget.Adapter#getCount()
*/
@Override
public int getCount() {
return imgs.length;
}

/* (non-Javadoc)
* @see android.widget.Adapter#getItem(int)
*/
@Override
public Object getItem(int position) {
return position;
}

/* (non-Javadoc)
* @see android.widget.Adapter#getItemId(int)
*/
@Override
public long getItemId(int position) {
return position;
}

/* (non-Javadoc)
* @see android.widget.Adapter#getView(int, android.view.View, android.view.ViewGroup)
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//针对每一个数据(即每一个图片ID)创建一个ImageView实例,
ImageView iv = new ImageView(context);//针对外面传递过来的Context变量,
iv.setImageResource(imgs[position]);
Log.i(“magc”, String.valueOf(imgs[position]));
iv.setLayoutParams(new Gallery.LayoutParams(80, 80));//设置Gallery中每一个图片的大小为80*80。
iv.setScaleType(ImageView.ScaleType.FIT_XY);
return iv;
}

}

}