A. Android入門教程 | Fragment 基礎概念
Fragment,直譯為「碎片」,「片段」。Fragment表示FragmentActivity中的行為或界面的一部分。可以在一個Activity中組合多個片段,從而構建多窗格界面,並在多個Activity中重復使用某個片段。可以將片段視為Activity的模塊化組成部分,它具有自己的生命周期,能接收自己的輸入事件,並且可以在Activity運行時添加或移除片段(這有點像可以在不同Activity中重復使用的「子Activity」)。
片段必須始終託管在Activity中,其生命周期直接受宿主Activity生命周期的影響。例如,當Activity暫停時,Activity的所有片段也會暫停;當Activity被銷毀時,所有片段也會被銷毀。
不過,當Activity正在運行(處於已恢復生命周期狀態)時,可以獨立操縱每個片段,如添加或移除片段。當執行此類片段事務時,也可將其添加到由Activity管理的返回棧 — Activity中的每個返回棧條目都是一條已發生片段事務的記錄。藉助返回棧,用戶可以通過按返回按鈕撤消片段事務(後退)。
Fragment的優點包括其代碼與Activity非常相似,包含與Activity類似的回調方法,如onCreate()、onStart()、onPause() 和onStop()。實際上,如果要將現有Android應用轉換為使用片段,可能只需將代碼從Activity的回調方法移入片段相應的回調方法中。通常,至少應實現以下生命周期方法。
片段通常用作Activity界面的一部分,並且會將其自己的布局融入Activity。如要為片段提供布局,必須實現onCreateView()回調方法,Android系統會在片段需要繪制其布局時調用該方法。此方法的實現所返回的View必須是片段布局的根視圖。如要從onCreateView()返回布局,可以通過XML中定義的布局資源來擴展布局。為幫助您執行此操作,onCreateView()提供了一個LayoutInflater對象。例如,以下這個Fragment子類從example_fragment.xml文件載入布局:。
接下來,需將該片段添加到您的Activity中。
通常,片段會向宿主Activity貢獻一部分界面,作為Activity整體視圖層次結構的一部分嵌入到Activity中。可以通過兩種方式向Activity布局添加片段。靜態方式在Activity的布局文件內聲明片段。java代碼載入Fragment通過編程方式將片段添加到某個現有ViewGroup。如要在Activity中執行片段事務(如添加、移除或替換片段),則必須使用FragmentTransaction中的API。
在Activity中使用片段的一大優點是,可以通過片段執行添加、移除、替換以及其他操作,從而響應用戶交互。提交給Activity的每組更改均稱為事務,並且可使用FragmentTransaction中的API來執行一項事務。也可將每個事務保存到由Activity管理的返回棧內,從而讓用戶能夠回退片段更改(類似於回退Activity)。
每個事務都是想要同時執行的一組更改。可以使用add()、remove()和replace()等方法,為給定事務設置您想要執行的所有更改。然後,如要將事務應用到Activity,必須調用commit()。不過,在調用commit()之前,可能希望調用addToBackStack(),以將事務添加到片段事務返回棧。該返回棧由Activity管理,允許用戶通過按返回按鈕返回上一片段狀態。
在 Activity中使用Fragment的一大優點是,可以通過片段執行添加、移除、替換以及其他操作,從而響應用戶交互。每個事務都是想要同時執行的一組更改。可以使用add()、remove()和replace()等方法,為給定事務設置您想要執行的所有更改。然後,如要將事務應用到Activity,必須調用commit()。不過,在調用commit()之前,可能希望調用addToBackStack(),以將事務添加到片段事務返回棧。該返回棧由Activity管理,允許用戶通過按返回按鈕返回上一片段狀態。
在 Activity中使用Fragment的一大優點是,可以通過片段執行添加、移除、替換以及其他操作,從而響應用戶交互。每個事務都是想要同時執行的一組更改。可以使用add()、remove()和replace()等方法,為給定事務設置您想要執行的所有更改。然後,如要將事務應用到Activity,必須調用commit()。不過,在調用commit()之前,可能希望調用addToBackStack(),以將事務添加到片段事務返回棧。該返回棧由Activity管理,允許用戶通過按返回按鈕返回上一片段狀態。
B. android 自定義switch樣式
在修改後的MySwitch控制項中,介面基本與原Switch控制項一致,並且新增了兩項功能。首先,用戶可以使用Track背景圖片的方式代替文字來表示開關狀態的變化,這使得界面更加美觀且可定製。其次,可以調整Switch的高度,以適應不同的設計需求。這些改動使得MySwitch控制項更加靈活和實用。
以下為關鍵代碼片段:
java
public class MySwitch extends CompoundButton {
// 支持使用Track背景圖片表示開關狀態
private Drawable mTrackOnDrawable;
private Drawable mTrackOffDrawable;
// 支持設置Switch的最小高度
private int mSwitchMinHeight;
/**
* 構造函數,根據給定的主題屬性確定控制項的樣式,並覆蓋特定的樣式屬性。
* @param context Context,用於確定此控制項的主題。
* @param attrs 屬性規范,用於指定應偏離默認樣式屬性。
* @param defStyle 一個屬性ID,位於當前主題中,包含此控制項的默認樣式引用。例如,android.R.attr.switchStyle。
*/
public MySwitch(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
Resources res = getResources();
mTextPaint.density = res.getDisplayMetrics().density;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Switch, defStyle, 0);
mTrackOnDrawable = a.getDrawable(R.styleable.Switch_trackOn);
mTrackOffDrawable = a.getDrawable(R.styleable.Switch_trackOff);
if (checkTrackOffOnDrawable()) {
mTrackDrawable = mTrackOffDrawable;
} else {
mTrackDrawable = a.getDrawable(R.styleable.Switch_track);
}
mThumbDrawable = a.getDrawable(R.styleable.Switch_thumb);
mTextOn = a.getText(R.styleable.Switch_textOn);
mTextOff = a.getText(R.styleable.Switch_textOff);
mThumbTextPadding = a.getDimensionPixelSize(R.styleable.Switch_thumbTextPadding, 0);
mSwitchMinWidth = a.getDimensionPixelSize(R.styleable.Switch_switchMinWidth, 0);
mSwitchMinHeight = a.getDimensionPixelSize(R.styleable.Switch_switchMinHeight, 0);
mSwitchPadding = a.getDimensionPixelSize(R.styleable.Switch_switchPadding, 0);
int appearance = a.getResourceId(R.styleable.Switch_switchTextAppearance, 0);
if (appearance != 0) {
setSwitchTextAppearance(context, appearance);
}
a.recycle();
ViewConfiguration config = ViewConfiguration.get(context);
mTouchSlop = config.getScaledTouchSlop();
mMinFlingVelocity = config.getScaledMinimumFlingVelocity();
refreshDrawableState();
setChecked(isChecked());
}
private boolean checkTrackOffOnDrawable() {
return mTrackOnDrawable != null && mTrackOffDrawable != null;
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mOnLayout == null) {
mOnLayout = makeLayout(mTextOn);
}
if (mOffLayout == null) {
mOffLayout = makeLayout(mTextOff);
}
mTrackDrawable.getPadding(mTempRect);
final int maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth());
final int switchWidth = Math.max(mSwitchMinWidth, maxTextWidth * 2 + mThumbTextPadding * 4 + mTempRect.left + mTempRect.right);
int switchHeight; if (mSwitchMinHeight <= 0) {
switchHeight = mTrackDrawable.getIntrinsicHeight();
} else {
switchHeight = Math.max(mSwitchMinHeight, mTempRect.top + mTempRect.bottom);
}
mThumbWidth = maxTextWidth + mThumbTextPadding * 2;
mSwitchWidth = switchWidth;
mSwitchHeight = switchHeight;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int measuredHeight = getMeasuredHeight();
if (measuredHeight < switchHeight) {
setMeasuredDimension(getMeasuredWidthAndState(), switchHeight);
}
}
@Override
public void setChecked(boolean checked) {
if (checkTrackOffOnDrawable()) {
mTrackDrawable = checked ? mTrackOnDrawable : mTrackOffDrawable;
refreshDrawableState();
}
super.setChecked(checked);
mThumbPosition = checked ? getThumbScrollRange() : 0;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 繪制開關
int switchLeft = mSwitchLeft;
int switchTop = mSwitchTop;
int switchRight = mSwitchRight;
int switchBottom = mSwitchBottom;
if (checkTrackOffOnDrawable()) {
mTrackDrawable = getTargetCheckedState() ? mTrackOnDrawable : mTrackOffDrawable;
refreshDrawableState();
}
mTrackDrawable.setBounds(switchLeft, switchTop, switchRight, switchBottom);
mTrackDrawable.draw(canvas);
canvas.save();
mTrackDrawable.getPadding(mTempRect);
int switchInnerLeft = switchLeft + mTempRect.left;
int switchInnerTop = switchTop + mTempRect.top;
int switchInnerRight = switchRight - mTempRect.right;
int switchInnerBottom = switchBottom - mTempRect.bottom;
canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);
mThumbDrawable.getPadding(mTempRect);
final int thumbPos = (int) (mThumbPosition + 0.5f);
int thumbLeft = switchInnerLeft - mTempRect.left + thumbPos;
int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + mTempRect.right;
mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
mThumbDrawable.draw(canvas);
// mTextColors 不應為null,但以防萬一
if (mTextColors != null) {
mTextPaint.setColor(mTextColors.getColorForState(getDrawableState(), mTextColors.getDefaultColor()));
}
mTextPaint.drawableState = getDrawableState();
Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
if (switchText != null) {
canvas.translate((thumbLeft + thumbRight) / 2 - switchText.getWidth() / 2, (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2);
switchText.draw(canvas);
}
canvas.restore();
}
}
關鍵屬性聲明如下:
java
public static final int switchMinHeight;
public static final int switchMinWidth;
public static final int switchPadding;
public static final int switchTextAppearance;
public static final int thumbTextPadding;