編輯:關於Android編程
首先,感謝開源中國的開源精神。當初學者拿到客戶端源碼時,可能會對其中的項目結構和代碼產生許多困惑,不知道該從何下手,當然我也是其中一員,接觸安卓時間不長,也不是很精通,但是通過一段時間的琢磨,慢慢地領會到其中的一些編程方法,我只是想把我弄明白的這些知識通過博客的形式記錄下來,以備以後查看,當然也可以幫助到更多的初學者。我的主要工作是給代碼添加注釋,理順調用關系,讓初學者更快、更深刻地理解代碼的含義,領會其精神。首先大家從http://git.oschina.net/oschina/android-app下載整個開源項目,先跑通這個程序,並且對這個項目整體的結構有大致的了解,然後再看我寫的博客。由於我也是初學者,錯誤之處在所難免,希望大家踴躍指出,你們的支持是我最大的動力,謝謝!
1、net.oschina.app.widget.ScreenShotView
package net.oschina.app.widget;
import net.oschina.app.AppConfig;
import net.oschina.app.R;
import net.oschina.app.common.UIHelper;
import net.oschina.app.ui.BaseActivity;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
/**
*
* 實現截圖功能的View
*
* @author [email protected]
*
*/
public class ScreenShotView extends View implements OnTouchListener {
/**
* 定義畫筆
*/
private Paint mGrayPaint;
/**
* 定義截屏所用的四個矩形
*/
private Rect topRect;
private Rect rightRect;
private Rect bottomRect;
private Rect leftRect;
/**
* 設備的寬
*/
private int screenWidth;
/**
* 設備的高
*/
private int screeenHeight;
/**
* 回調模式所用的接口
*/
private OnScreenShotListener mListener;
/**
* 上下文
*/
private BaseActivity mContext;
/**
* 截圖矩形的坐標
*/
private int top, right, bottom, left;
/**
* 輔助變量,用於暫時保存矩形坐標
*/
private int tmpLeft, tmpTop, tmpRight, tmpBottom;
/**
* 矩形的寬高
*/
private int innerWidth, innerHeight;
/**
* 觸摸屏幕前後坐標
*/
private int downX, downY, moveX, moveY;
/**
* 選擇標識(開始畫截屏)
*/
private final static int TOUCH_SELECT = 1;
/**
* 移動截屏標識
*/
final static int TOUCH_MOVE = 2;
/**
* 默認為選擇標識
*/
private int touchFlag = TOUCH_SELECT;
/**
* 是否在移動選區內
*/
private boolean isInMoveSelection;
/**
* 上拉調整大小
*/
private boolean isInTopPullArea;
/**
* 右拉調整大小
*/
private boolean isInRightPullArea;
/**
* 下拉調整大小
*/
private boolean isInBottomPullArea;
/**
* 左拉調整大小
*/
private boolean isInLeftPullArea;
/**
* 選框內雙擊中的有效點擊次數
*/
private int innnerClickCount = 0;
/**
* 選框外雙擊的有效點擊次數
*/
private int outterClickCount = 0;
/**
* 觸碰事件間隔
*/
private long timeInterval;
/**
* 第一次單擊時刻
*/
private long firstClickTime;
/**
* 第二次單擊時刻
*/
private long secondClickTime;
/**
* 剛觸碰的時刻
*/
private long TouchDownTime;
/**
* 觸碰結束時刻
*/
private long TouchUpTime;
/**
* 觸摸down,up一下500毫秒以內為一次單擊
*/
private final static long VALID_CLICK_INTERVAL = 500;
/**
* 兩次單擊之間時間距離
*/
private final static long VALID_DOUBLE_CLICK_INTERNAL = 1000;
/**
* 有效拉大拉小距離
*/
private final static int VALID_PULL_DISTANCE = 30;
/**
* 是否顯示雙擊圖片
*/
private boolean isTimeToTip = false;
/**
* 截圖是否隱藏
*/
private boolean isHide = false;
/**
* 截圖保存路徑
*/
public final static String TEMP_SHARE_FILE_NAME = AppConfig.DEFAULT_SAVE_IMAGE_PATH
+ "_share_tmp.jpg";
/**
* 顯示出雙擊圖片
*/
private static Bitmap bmDoubleClickTip;
/**
* 監聽截圖完成後要完成的動作
*/
public interface OnScreenShotListener {
public void onComplete(Bitmap bm);
}
@SuppressLint("NewApi")
public ScreenShotView(BaseActivity context, OnScreenShotListener listener) {
super(context);
//監聽器初始化
mListener = listener;
//上下文初始化
mContext = context;
//這句話有兩個作用:
//(1)當前Activity不可銷毀
//(2)將當前View對象傳遞給基類BaseActivity中的view對象,
//在取消截屏摁返回鍵的時候會用到,第一次摁返回鍵時,消失的是自定義的view,
//第二次摁返回鍵時,消失的才是真正的Activity中的view
mContext.setAllowDestroy(false, this);
//獲取不同設備的寬高
Point p = getDisplaySize(context.getWindowManager().getDefaultDisplay());
screenWidth = p.x;
screeenHeight = p.y;
//實例化畫筆
mGrayPaint = new Paint();
//將該畫筆的透明度設置為100
mGrayPaint.setARGB(100, 0, 0, 0);
//實例化四個矩形類
topRect = new Rect();
rightRect = new Rect();
bottomRect = new Rect();
leftRect = new Rect();
//將topRect的寬高設置為設備的寬高(即當點擊截屏分享的時候,整個屏幕都被topRect所占據)
topRect.set(0, 0, screenWidth, screeenHeight);
//由於當前類實現了OnTouchListener接口,因此可以將當前對象賦值給自定義View的setOnTouchListener()方法
setOnTouchListener(this);
//實例化雙擊圖標
if(bmDoubleClickTip==null){
bmDoubleClickTip = BitmapFactory.decodeStream(getResources().openRawResource(R.drawable._pointer));
}
//吐司提示信息
UIHelper.ToastMessage(mContext, "請滑動手指確定選區!");
}
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//在屏幕上用畫筆畫出這四個矩形
canvas.drawRect(topRect, mGrayPaint);
canvas.drawRect(rightRect, mGrayPaint);
canvas.drawRect(bottomRect, mGrayPaint);
canvas.drawRect(leftRect, mGrayPaint);
//判斷矩形是否畫完
if (isTimeToTip) {
//下面7行代碼作用是讓雙擊圖片在選框中居中顯示
//計算矩形的寬高
innerWidth = right - left;
innerHeight = bottom - top;
//計算雙擊圖片的寬高
int bmWidth = bmDoubleClickTip.getWidth();
int bmHeight = bmDoubleClickTip.getHeight();
//在矩形中居中顯示雙擊圖片的坐標
int x = (int) (left + (innerWidth - bmWidth) * 0.5);
int y = (int) (top + (innerHeight - bmHeight) * 0.5);
//在矩形中顯示出該圖片
canvas.drawBitmap(bmDoubleClickTip, x, y, null);
//雙擊圖片顯示後,馬上設置成false
isTimeToTip = false;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
/**
* 重寫onTouch方法
*/
@Override
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
//手指按下的時候
case MotionEvent.ACTION_DOWN:
//雙擊圖標不顯示
isTimeToTip = false;
//記錄按下時的坐標
downX = (int) event.getX();
downY = (int) event.getY();
//判斷按下的坐標是否在畫好的矩形內
isInMoveSelection = isInSeletion(downX, downY);
//判斷按下的坐標是否屬於畫好的矩形內的上拉區域
isInTopPullArea = isInTopPullArea(downX, downY);
//判斷按下的坐標是否屬於畫好的矩形內的右拉區域
isInRightPullArea = isInRightPullArea(downX, downY);
//判斷按下的坐標是否屬於畫好的矩形內的下拉區域
isInBottomPullArea = isInBottomPullArea(downX, downY);
//判斷按下的坐標是否屬於畫好的矩形內的左拉區域
isInLeftPullArea = isInLeftPullArea(downX, downY);
//記錄當前按下屏幕的時間
TouchDownTime = System.currentTimeMillis();
break;
//手指在屏幕上移動的時候
case MotionEvent.ACTION_MOVE:
//雙擊圖片不顯示
isTimeToTip = false;
//移動過程中手指的坐標
moveX = (int) event.getX();
moveY = (int) event.getY();
if (touchFlag == TOUCH_SELECT) {
//開始畫矩形
tmpLeft = left = getMin(downX, moveX);
tmpTop = top = getMin(downY, moveY);
tmpRight = right = getMax(downX, moveX);
tmpBottom = bottom = getMax(downY, moveY);
//不是在移動矩形
isInMoveSelection = false;
} else if (touchFlag == TOUCH_MOVE && isInMoveSelection) {
//移動畫好的矩形
int xDistance = moveX - downX;
int yDistance = moveY - downY;
//決定矩形選框的坐標
decideCoordinate(xDistance, yDistance);
} else if (touchFlag == TOUCH_MOVE && isInTopPullArea) {
//當手指在上拉調整區域,將畫好的矩形垂直拉伸
int yDistance = downY - moveY;
//下面兩行代碼的目的是矩形選框的top與bottom至少要有2倍於VALID_PULL_DISTANCE的距離
int extremeY = (bottom - 2 * VALID_PULL_DISTANCE);
top = (tmpTop - yDistance) < extremeY ? (tmpTop - yDistance)
: extremeY;
} else if (touchFlag == TOUCH_MOVE && isInRightPullArea) {
//當手指在右拉調整區域,將畫好的矩形水平拉伸
int xDistance = moveX - downX;
//下面兩行代碼的目的是矩形選框的right與left至少要有2倍於VALID_PULL_DISTANCE的距離
int extremeX = (left + 2 * VALID_PULL_DISTANCE);
right = (tmpRight + xDistance) > extremeX ? (tmpRight + xDistance)
: extremeX;
} else if (touchFlag == TOUCH_MOVE && isInBottomPullArea) {
//當手指在下拉調整區域,將畫好的矩形垂直拉伸
int yDistance = downY - moveY;
//下面兩行代碼的目的是矩形選框的bottom與top至少要有2倍於VALID_PULL_DISTANCE的距離
int extremeY = (top + 2 * VALID_PULL_DISTANCE);
bottom = (tmpBottom - yDistance) > extremeY ? (tmpBottom - yDistance)
: extremeY;
} else if (touchFlag == TOUCH_MOVE && isInLeftPullArea) {
//當手指在左拉調整區域,將畫好的矩形水平拉伸
int xDistance = downX - moveX;
//下面兩行代碼的目的是矩形選框的left與right至少要有2倍於VALID_PULL_DISTANCE的距離
int extremeX = (right - 2 * VALID_PULL_DISTANCE);
left = (tmpLeft - xDistance) < extremeX ? (tmpLeft - xDistance)
: extremeX;
}
//設置矩形的邊框坐標
setInnerBorder(left, top, right, bottom);
break;
//手指從屏幕上抬起或者事件被其他組件攔截掉該事件而造成的本次事件取消
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (touchFlag == TOUCH_SELECT) {
//手指抬起的時候,如果是選擇標識,則換成移動標識
touchFlag = TOUCH_MOVE;
} else if (touchFlag == TOUCH_MOVE) {
//手指抬起的時候,如果是移動標識,則將最終坐標寫進輔助變量中
tmpLeft = left;
tmpTop = top;
tmpRight = right;
tmpBottom = bottom;
}
//重新顯示雙擊圖片
if (isShouldShowTip() && isTimeToTip == false) {
isTimeToTip = true;
//重新繪制,調用onDraw()
invalidate();
}
//記錄離開屏幕的時間
TouchUpTime = System.currentTimeMillis();
//計算本次ACTION_DOWN與ACTION_UP的時間間隔
timeInterval = TouchUpTime - TouchDownTime;
if (timeInterval < VALID_CLICK_INTERVAL && isInMoveSelection) {
//這是一次單擊,將單擊次數加1
innnerClickCount = innnerClickCount + 1;
if (innnerClickCount == 1) {
//記錄第一次單擊的時間
firstClickTime = System.currentTimeMillis();
} else if (innnerClickCount == 2) {
//記錄第二次單擊的時間
secondClickTime = System.currentTimeMillis();
//符合雙擊的條件則完成截圖
if ((secondClickTime - firstClickTime) < VALID_DOUBLE_CLICK_INTERNAL) {
isTimeToTip = false;
mListener.onComplete(getCutImage());
dismiss();
}
innnerClickCount = 0;
}
} else if (timeInterval < VALID_CLICK_INTERVAL
&& !isInMoveSelection) {
//在非選中區域雙擊,取消本次截屏
outterClickCount = outterClickCount + 1;
if (outterClickCount == 1) {
firstClickTime = System.currentTimeMillis();
} else if (outterClickCount == 2) {
secondClickTime = System.currentTimeMillis();
if ((secondClickTime - firstClickTime) < VALID_DOUBLE_CLICK_INTERNAL) {
isTimeToTip = false;
dismiss();
}
outterClickCount = 0;
}
}
break;
default:
break;
}
return true;
}
private int getMin(int x, int y) {
return x > y ? y : x;
}
private int getMax(int x, int y) {
return x > y ? x : y;
}
/**
* 是否在左拉動選區
*
* @return
*/
private boolean isInLeftPullArea(int x, int y) {
if (((left - VALID_PULL_DISTANCE) <= x && x < (left + VALID_PULL_DISTANCE))
&& ((top + VALID_PULL_DISTANCE) < y && y < (bottom - VALID_PULL_DISTANCE))) {
return true;
}
return false;
}
/**
* 是否在右拉動選區
*
* @return
*/
private boolean isInRightPullArea(int x, int y) {
if (((right - VALID_PULL_DISTANCE) <= x && x < (right + VALID_PULL_DISTANCE))
&& ((top + VALID_PULL_DISTANCE) < y && y < (bottom - VALID_PULL_DISTANCE))) {
return true;
}
return false;
}
/**
* 是否在上拉動選區
*
* @return
*/
private boolean isInTopPullArea(int x, int y) {
if (((left + VALID_PULL_DISTANCE) <= x && x < (right - VALID_PULL_DISTANCE))
&& ((top - VALID_PULL_DISTANCE) < y && y < (top + VALID_PULL_DISTANCE))) {
return true;
}
return false;
}
/**
* 是否在下拉動選區
*
* @return
*/
private boolean isInBottomPullArea(int x, int y) {
if (((left + VALID_PULL_DISTANCE) <= x && x < (right - VALID_PULL_DISTANCE))
&& ((bottom - VALID_PULL_DISTANCE) < y && y < (bottom + VALID_PULL_DISTANCE))) {
return true;
}
return false;
}
/**
* 判斷觸碰的點有沒有在移動選區內
*
* @param x
* @param y
* @return
*/
private boolean isInSeletion(int x, int y) {
if ((left != 0 || right != 0 || top != 0 || bottom != 0)
&& ((left + VALID_PULL_DISTANCE) <= x && x <= (right - VALID_PULL_DISTANCE))
&& ((top + VALID_PULL_DISTANCE) <= y && y <= (bottom - VALID_PULL_DISTANCE))) {
return true;
}
return false;
}
/**
* 判斷是否應該出現提示
*
* @return
*/
private boolean isShouldShowTip() {
if ((right - left) > 100 && (bottom - top) > 100) {
return true;
}
return false;
}
/**
* 決定矩形選框的坐標
*
* @param xDistance
* @param yDistance
*/
private void decideCoordinate(int xDistance, int yDistance) {
innerWidth = right - left;
innerHeight = bottom - top;
// 決定左右坐標
if ((tmpLeft + xDistance) < 0) {
right = innerWidth;
left = 0;
} else if ((tmpRight + xDistance) > screenWidth) {
left = screenWidth - innerWidth;
right = screenWidth;
} else {
left = tmpLeft + xDistance;
right = tmpRight + xDistance;
}
// 決定上下坐標
if ((tmpTop + yDistance) < 0) {
bottom = innerHeight;
top = 0;
} else if ((tmpBottom + yDistance) > screeenHeight) {
top = screeenHeight - innerHeight;
bottom = screeenHeight;
} else {
top = tmpTop + yDistance;
bottom = tmpBottom + yDistance;
}
}
/**
* 設置矩形的邊框坐標
*/
private void setInnerBorder(int left, int top, int right, int bottom) {
Log.i("com.example", "left:" + left + ",top:" + top + ",right:" + right
+ ",bottom:" + bottom);
topRect.set(0, 0, screenWidth, top);
rightRect.set(right, top, screenWidth, bottom);
bottomRect.set(0, bottom, screenWidth, screeenHeight);
leftRect.set(0, top, left, bottom);
this.invalidate();
}
/**
* 截取內層邊框中的View.
*/
private Bitmap getCutImage() {
View view = mContext.getWindow().getDecorView();
Bitmap bmp = Bitmap.createBitmap(view.getWidth(), view.getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
view.draw(canvas);
return imageCrop(bmp);
}
/**
* 裁剪圖片
*/
private Bitmap imageCrop(Bitmap bitmap) {
int x = left<0?0:left;
int y = top + getStatusHeight();
int width = right- left;
int height = bottom - top;
if((width+x)>bitmap.getWidth()){
width = bitmap.getWidth()-x;
}
if((y+height)>bitmap.getHeight()){
height = bitmap.getHeight()-y;
}
return Bitmap.createBitmap(bitmap,x,y,width,height , null, false);
}
/**
* 返回狀態欄的高度
*
* @return
*/
private int getStatusHeight() {
Rect frame = new Rect();
mContext.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
return frame.top;
}
/**
* 注銷該view
*/
private void dismiss() {
isHide = true;
mGrayPaint.setARGB(0, 0, 0, 0);
setOnTouchListener(null);
mContext.setAllowFullScreen(true);
invalidate();
}
/**
* 獲取不同設備的寬高
* @param display
* @return
*/
@SuppressLint("NewApi")
private static Point getDisplaySize(final Display display) {
final Point point = new Point();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
display.getSize(point);
} else {
point.x = display.getWidth();
point.y = display.getHeight();
}
return point;
}
/**
* 自定義View中的onKeyDown方法,默認情況下不調用View.onKeyDown方法,
* 但是在BaseActivity中的onKeyDown方法中可以顯式調用
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && isHide == false) {
Log.i("ScreenShotView", "---->第一次摁返回鍵");
mContext.setAllowDestroy(false);
dismiss();
} else if ((keyCode == KeyEvent.KEYCODE_BACK && isHide == true)) {
Log.i("ScreenShotView", "---->第二次摁返回鍵");
mContext.setAllowDestroy(true);
}
return false;
}
}
2、net.oschaina.app.common.UIHelper
/**
* 分享到'新浪微博'或'騰訊微博'的對話框
*
* @param context
* 當前Activity
* @param title
* 分享的標題
* @param url
* 分享的鏈接
*/
public static void showShareDialog(final Activity context,
final String title, final String url) {
final String spiltUrl;
Log.i("UIHelper", "---->showShareDialog--->url:"+url);
//判斷分享的鏈接是否包含my
if(url.indexOf("my")>0){
spiltUrl = "http://m.oschina.net/" + url.substring(url.indexOf("blog"));
}else{
spiltUrl = "http://m.oschina.net/" + url.substring(22);
}
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(android.R.drawable.btn_star);
builder.setTitle(context.getString(R.string.share));
builder.setItems(R.array.app_share_items,
new DialogInterface.OnClickListener() {
AppConfig cfgHelper = AppConfig.getAppConfig(context);
AccessInfo access = cfgHelper.getAccessInfo();
public void onClick(DialogInterface arg0, int arg1) {
switch (arg1) {
case 0:// 新浪微博
// 分享的內容
final String shareMessage = title + " " + url;
// 初始化微博
if (SinaWeiboHelper.isWeiboNull()) {
SinaWeiboHelper.initWeibo();
}
// 判斷之前是否登陸過
if (access != null) {
SinaWeiboHelper.progressDialog = new ProgressDialog(
context);
SinaWeiboHelper.progressDialog
.setProgressStyle(ProgressDialog.STYLE_SPINNER);
SinaWeiboHelper.progressDialog
.setMessage(context
.getString(R.string.sharing));
SinaWeiboHelper.progressDialog
.setCancelable(true);
SinaWeiboHelper.progressDialog.show();
new Thread() {
public void run() {
SinaWeiboHelper.setAccessToken(
access.getAccessToken(),
access.getAccessSecret(),
access.getExpiresIn());
SinaWeiboHelper.shareMessage(context,
shareMessage);
}
}.start();
} else {
SinaWeiboHelper
.authorize(context, shareMessage);
}
break;
case 1:// 騰訊微博
QQWeiboHelper.shareToQQ(context, title, url);
break;
case 2:// 微信朋友圈
WXFriendsHelper.shareToWXFriends(context, title, spiltUrl);
break;
case 3:// 截圖分享
//這就是所謂的回調接口OnScreenShotListener
addScreenShot(context, new OnScreenShotListener() {
@SuppressLint("NewApi")
public void onComplete(Bitmap bm) {
Intent intent = new Intent(context,ScreenShotShare.class);
intent.putExtra("title", title);
intent.putExtra("url", url);
intent.putExtra("cut_image_tmp_path",ScreenShotView.TEMP_SHARE_FILE_NAME);
try {
//將圖片保存到SD卡中
ImageUtils.saveImageToSD(context,ScreenShotView.TEMP_SHARE_FILE_NAME,bm, 100);
} catch (IOException e) {
e.printStackTrace();
}
context.startActivity(intent);
}
});
break;
case 4:// 更多
showShareMore(context, title, spiltUrl);
break;
}
}
});
builder.create().show();
}
/**
* 添加截屏功能
*/
@SuppressLint("NewApi")
public static void addScreenShot(Activity context,
OnScreenShotListener mScreenShotListener) {
BaseActivity cxt = null;
if (context instanceof BaseActivity) {
cxt = (BaseActivity) context;
cxt.setAllowFullScreen(false);
ScreenShotView screenShot = new ScreenShotView(cxt,
mScreenShotListener);
//設置布局的參數
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
//將自定義截屏的View添加到當前Activity中
context.getWindow().addContentView(screenShot, lp);
}
}
3、net.oschina.app.ui.BaseActivity—-所有Activity中的基類
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//如果view非空,則就是自定義View---ScreenShotView
if (keyCode == KeyEvent.KEYCODE_BACK && view != null) {
Log.i("BaseActivity", "---->onKeyDown");
//顯式調用自定義View中的onKeyDown方法
view.onKeyDown(keyCode, event);
if (!allowDestroy) {
Log.i("BaseActivity", "---->第一次只銷毀截屏的view,但不銷毀Activity");
return false;
}
}
//如果view為空,直接銷毀當前Activity
return super.onKeyDown(keyCode, event);
}
在Android 的程序中設置項可以說是一個必須要有的頁面。下面說一下如何寫一個基本的設置頁面。我們先來看一下常用安卓程序的設置頁面:
在 Android 3.0 開始 ,所有的主題默認把 ActionBar 作為默認的 App Bar,但是它很死板,不容易自行設計想要的風格, 在
線程池簡單點就是任務隊列+線程組成的。接下來我們來簡單的了解下ThreadPoolExecutor的源碼。先看ThreadPoolExecutor的簡單類圖,對Threa
Android底部支付彈窗實現的效果:實現的思路:1.通過繼承PopupWindow自定義View來達到彈窗的彈出效果;2.通過回調將輸入的密碼由彈窗傳入到主界面中;2.