開發(fā)APP時怎樣快速實(shí)現(xiàn)模板的定制方法,模板的定制使用在用AndroidStudio的向?qū)陆üこ虝r,會顯示許多Android Studio內(nèi)置的Activity模板,深圳APP開發(fā)公司整理如圖25-3所示:
或在工程中選擇新建Activity時,也可以選擇內(nèi)置的Activity模板,如圖25-4所示:
這樣可以大大提高開發(fā)效率。這些模板放在AndroidStudio安裝路徑的如下文件夾中:plugins\android\lib\templates\activities,用戶也可以自己定制模板。大多數(shù)APP都有登錄功能,現(xiàn)參考AndroidStudio中提供的LoginActivity模板,定制一個登錄功能用的rwLoginActivity模板,名稱為“RuWangLoginActivity”,界面如圖25-5所示:
首先編寫rwLoginActivity.java代碼和activity_rw_login.xml文件實(shí)現(xiàn)此Activity,然后在此基礎(chǔ)上實(shí)現(xiàn)模板。
參考AndroidStudio提供的模板,要定制一個模板,涉及如圖25-6所示的文件:
圖25-6template_rw_login_activity.png—對應(yīng)在AndroidStudio中用向?qū)?chuàng)建Activity時,在圖25-3界面看到的Activity界面示意圖。template.xml—用于定義屬性參數(shù),內(nèi)容如下:<? xml version=" 1. 0"?> < template format=" 5" revision=" 1" // 模板 名稱 name=" RuWang Login Activity"
description=" Creates a new login activity, allowing users to enter a phone number and password to log in to or register with your application." requireAppTheme=" true" // 此 Activity 支持 的 最小 API 級別 minApi=" 17" minBuildApi=" 17"> < category value=" Activity" /> < formfactor value=" Mobile" /> //以下 parameter 參數(shù) 和 相關(guān) 屬性 會在 創(chuàng)建 Activity 時 的“ Customize the Acitvity” 界面 用到, 需要 用戶 輸入 一些 參數(shù) 值, 且 向 用戶 顯示 一些 提示 信息, default 和 help 的 內(nèi)容 支持 中 英文 < parameter id=" activityClass" name=" Activity Name" type=" string" constraints=" class| unique| nonempty" default=" rwLoginActivity" help=" The name of the activity class to create" /> < parameter id=" layoutName"
name=" Layout Name" type=" string" constraints=" layout| unique| nonempty" suggest="${ activityToLayout( activityClass)}" default=" activity_ rw_ login" help=" The name of the layout to create for the activity" /> < parameter id=" activityTitle" name=" Title" type=" string" constraints=" nonempty" default=" 登錄" help=" The name of the activity." /> < parameter id=" passwordLength" name=" Password Length" type=" string" constraints=" nonempty" default=" 6" help=" 設(shè)置 密碼 長度" /> < parameter id=" parentActivityClass"
name=" Hierarchical Parent" type=" string" constraints=" activity| exists| empty" default="" help=" The hierarchical parent activity, used to provide a default implementation for the 'Up' button" /> < parameter id=" packageName" name=" Package name" type=" string" constraints=" package" default=" com. mycompany. myapp" /> < thumbs> < thumb> template_ rw_ login_ activity. png</ thumb> </ thumbs> < globals file=" globals. xml. ftl" /> < execute file=" recipe. xml. ftl" /> </ template> globals. xml. ftl 和 recipe. xml. ftl 的 后綴 是 ftl, 表示 這 兩個 文件 使 用的 是 FTL( FreeMarker Template Language) 語言, 這是 一種 簡單 的 模板 編寫 語言。
globals. xml. ftl —用于 定義 屬性 參數(shù), 內(nèi)容 如下: <? xml version=" 1. 0"?> < globals> // 定義 此 Activity 界面 是否 有 ActionBar, value 為 true, 表示 不需要 ActionBar < global id=" hasNoActionBar" type=" boolean" value=" true" /> // 定義 此 Activity 是否 具有" android. intent. action. MAIN" 和" android. intent. category. LAUNCHER" 兩個 屬性 < global id=" isLauncher" type=" boolean" value="${ isNewProject? string}" /> < global id=" GenericStringArgument" type=" string" value="<# if buildApi lt 19> String</# if>" /> < globals file="../ common/ common_ globals. xml. ftl" /> </ globals> 其中 lt 是 FTL 語言 關(guān)鍵字, 相當(dāng)于 比較 運(yùn)算符“ 小于”, 其他 幾個 類似 功能 的 關(guān)鍵字: gt: 比較 運(yùn)算符" 大于" gte: 比較 運(yùn)算符" 大于 或 等于" lte: 比較 運(yùn)算符" 小于 或 等于"
recipe.xml.ftl—用于對代碼文件和資源文件的處理。AndroidStudio提供的LoginActivity模板界面沒有圖片,rwLoginActivity模板界面有圖片,需要在recipe.xml.ftl文件中增加一個copy指令,復(fù)制模板資源圖片到工程中的資源目錄下:
< copy from=" root/ res/ drawable" to="${ escapeXmlAttribute( resOut)}/ drawable" />
文件的完整內(nèi)容如下:
<? xml version=" 1. 0"?> < recipe> <# if appCompat && !(hasDependency(' com. android. support: appcompat- v7'))> < dependency mavenUrl=" com. android. support: appcompat- v7:${ buildApi}.+" /> </# if> <# if (buildApi gte 22) && appCompat && !(hasDependency(' com. android. support: design'))> < dependency mavenUrl=" com. android. support: design:${ buildApi}.+" /> </# if> < merge from=" root/ AndroidManifest. xml. ftl" to="${ escapeXmlAttribute( manifestOut)}/ AndroidManifest. xml"
< merge from=" root/ res/ values/ dimens. xml" to="${ escapeXmlAttribute( resOut)}/ values/ dimens. xml" /> < merge from=" root/ res/ values/ strings. xml. ftl" to="${ escapeXmlAttribute( resOut)}/ values/ strings. xml" /> < copy from=" root/ res/ drawable" to="${ escapeXmlAttribute( resOut)}/ drawable" /> < instantiate from=" root/ res/ layout/ activity_ rw_ login. xml. ftl" to="${ escapeXmlAttribute( resOut)}/ layout/${ layoutName}. xml" /> < instantiate from=" root/ src/ app_ package/ rwLoginActivity. java. ftl" to="${ escapeXmlAttribute( srcOut)}/${ activityClass}. java" /> < open file="${ escapeXmlAttribute( srcOut)}/${ activityClass}. java" /> </ recipe>
在root文件夾里包含此Activity相關(guān)的代碼文件、資源文件和AndroidManifest文件,如圖25-7所示:
AndroidStudio提供的LoginActivity模板界面有ActionBar,rwLoginActivity模板界面沒有ActionBar,需要把AndroidManifest.xml.ftl文件里的主題設(shè)置代碼改成自己需要的主題名稱:
<# if hasNoActionBar> android: theme="@ style/ Theme. AppCompat. Light. NoActionBar"
文件的完整內(nèi)容如下:
< manifest xmlns: android=" http:// schemas. android. com/ apk/ res/ android" > < application> < activity android: name=".${ activityClass}" <# if isNewProject> android: label="@ string/ app_ name" <# else> android: label="@ string/ title_${ simpleName}" </# if> <# if hasNoActionBar> android: theme="@ style/ Theme. AppCompat. Light. NoActionBar" </# if> <# if buildApi gte 16 && parentActivityClass != ""> android: parentActivityName="${ parentActivityClass}"</# if>> <# if parentActivityClass != ""> < meta- data android: name=" android. support. PARENT_ ACTIVITY" android: value="${ parentActivityClass}" />
</# if> <# if isLauncher && !(isLibraryProject! false)> < intent- filter> < action android: name=" android. intent. action. MAIN" /> < category android: name=" android. intent. category. LAUNCHER" /> </ intent- filter> </# if> </ activity> </ application> </ manifest>
rwLoginActivity.java.ftl可以在之前寫好的rwLoginActivity.java文件基礎(chǔ)上做修改,導(dǎo)入包名的代碼改成:
package ${ packageName};
類名和父類名改成:
public class ${ activityClass} extends ${ superClass}
密碼長度參數(shù)的賦值語句改成:
private int mPasswordLength = ${ passwordLength};
文件的完整內(nèi)容如下:
package ${ packageName}; import android. content. res. ColorStateList; import android. graphics. Color; import android. graphics. PorterDuff; import android. support. v4. view. ViewCompat; import android. support. v7. app. AppCompatActivity; import android. os. Bundle; import android. text. TextUtils; import android. text. method. HideReturnsTransformationMethod; import android. text. method. PasswordTransformationMethod; import android. view. KeyEvent; import android. view. View; import android. view. View. OnClickListener; import android. view. inputmethod. EditorInfo; import android. widget. AutoCompleteTextView; import android. widget. Button; import android. widget. EditText; import android. widget. TextView;
import java. util. regex. Matcher; import java. util. regex. Pattern; public class ${ activityClass} extends ${ superClass} { private AutoCompleteTextView mPhoneView; private EditText mPasswordView; TextView mLoginEye; boolean mIsDisplayPassword = false; private int mPasswordLength = ${ passwordLength}; @ Override protected void onCreate( Bundle savedInstanceState) { super. onCreate( savedInstanceState); setContentView( R. layout. activity_ rw_ login); // Set up the login form. mPhoneView = (AutoCompleteTextView) findViewById( R. id. phone); mPasswordView = (EditText) findViewById( R. id. password); mPasswordView. setOnEditorActionListener( new TextView. OnEditorActionListener() { @ Override public boolean onEditorAction( TextView textView, int id,
KeyEvent keyEvent) { if (id == R. id. login || id == EditorInfo. IME_ NULL) { attemptLogin(); return true; } return false; } }); mLoginEye = (TextView) findViewById( R. id. login_ eye); mLoginEye. setOnClickListener( new View. OnClickListener() { @ Override public void onClick( View v) { OnSetDisplayPassword(); } }); Button mSignInButton = (Button) findViewById( R. id. sign_ in_ button); mSignInButton. setOnClickListener( new OnClickListener() { @ Override public void onClick( View view) { attemptLogin(); } });
} private void attemptLogin() { // Reset errors. mPhoneView. setError( null); mPasswordView. setError( null); // Store values at the time of the login attempt. String phone = mPhoneView. getText(). toString(); String password = mPasswordView. getText(). toString(); boolean cancel = false; View focusView = null; // Check for a valid password, if the user entered one. if (!TextUtils. isEmpty( password) && !isPasswordValid( password)) { mPasswordView. setError( getString( R. string. error_ invalid_ password)); focusView = mPasswordView; cancel = true; } // Check for a valid phone. if (TextUtils. isEmpty( phone)) {
mPhoneView. setError( getString( R. string. error_ field_ required)); focusView = mPhoneView; cancel = true; } else if (!isPhone( phone)) { mPhoneView. setError( getString( R. string. error_ invalid_ phone)); focusView = mPhoneView; cancel = true; } if (cancel) { // There was an error; don' t attempt login and focus the first // form field with an error. focusView. requestFocus(); } else { // perform the user login attempt. logIn( phone, password); } } /** * 判斷 手機(jī) 格式 是否 正確 *
* @param phone 手機(jī) 號 * @return true 正確 false 錯誤 */ public static boolean isPhone( String phone) { if (TextUtils. isEmpty( phone)) { return false; } Pattern p = Pattern .compile("^(( 13[ 0- 9])|( 14[ 5, 7])|( 17[ 0- 9])|( 15[^ 4,\\ D])|( 18[ 0- 9]))\\ d{ 8}$"); Matcher m = p. matcher( phone); return m. matches(); } private boolean isPasswordValid( String password) { // TODO: Replace this with your own logic return password. length() >= mPasswordLength; } private void OnSetDisplayPassword() { mIsDisplayPassword = !mIsDisplayPassword; if (mIsDisplayPassword) { ViewCompat. setBackgroundTintList( mLoginEye, ColorStateList. valueOf( Color. parseColor("# FF4081")));
ViewCompat. setBackgroundTintMode( mLoginEye, PorterDuff. Mode. SCREEN); mPasswordView. setTransformationMethod( HideReturnsTransformationMethod. getInstance()); } else { ViewCompat. setBackgroundTintList( mLoginEye, ColorStateList. valueOf( Color. parseColor("# CCCCCC"))); ViewCompat. setBackgroundTintMode( mLoginEye, PorterDuff. Mode. SCREEN); mPasswordView. setTransformationMethod( PasswordTransformationMethod. getInstance()); } } private void logIn( String phone, String password) { } }
activity_rw_login.xml.ftl也可以在之前寫好的activity_rw_login.xml文件基礎(chǔ)上做修改,里面涉及類名的地方改成:
tools: context="${ relativePackage}.${ activityClass}"
文件的完整內(nèi)容如下:
< LinearLayout xmlns: android=" http:// schemas. android. com/ apk/ res/ android" xmlns: tools=" http:// schemas. android. com/ tools" android: layout_ width=" match_ parent" android: layout_ height=" match_ parent" android: gravity=" center_ horizontal" android: orientation=" vertical" android: paddingBottom="@ dimen/ activity_ vertical_ margin" android: paddingLeft="@ dimen/ activity_ horizontal_ margin" android: paddingRight="@ dimen/ activity_ horizontal_ margin" android: paddingTop="@ dimen/ activity_ vertical_ margin" tools: context="${ relativePackage}.${ activityClass}"> < ScrollView android: id="@+ id/ login_ form" android: layout_ width=" match_ parent" android: layout_ height=" match_ parent"> < LinearLayout android: id="@+ id/ phone_ login_ form"
android: layout_ width=" match_ parent" android: layout_ height=" wrap_ content" android: orientation=" vertical"> < ImageView android: id="@+ id/ login_ image" android: layout_ width=" match_ parent" android: layout_ height=" wrap_ content" android: src="@ drawable/ login_ image" /> < android. support. design. widget. TextInputLayout android: layout_ width=" match_ parent" android: layout_ height=" wrap_ content"> < AutoCompleteTextView android: id="@+ id/ phone" android: layout_ width=" match_ parent" android: layout_ height=" wrap_ content" android: hint="@ string/ prompt_ phone" android: inputType=" phone" android: maxLines=" 1" android: singleLine=" true" /> </ android. support. design. widget. TextInputLayout>
< FrameLayout android: id="@+ id/ password_ layout" android: layout_ width=" match_ parent" android: layout_ height=" wrap_ content"> < android. support. design. widget. TextInputLayout android: layout_ width=" match_ parent" android: layout_ height=" wrap_ content"> < EditText android: id="@+ id/ password" android: layout_ width=" match_ parent" android: layout_ height=" wrap_ content" android: hint="@ string/ prompt_ password" android: imeActionId="@+ id/ login" android: imeActionLabel="@ string/ action_ sign_ in" android: imeOptions=" actionUnspecified" android: inputType=" textPassword" android: maxLines=" 1" android: singleLine=" true" /> </ android. support. design. widget. TextInputLayout> < android. support. v7. widget. AppCompatTextView android: id="@+ id/ login_ eye"
android: layout_ width=" wrap_ content" android: layout_ height=" wrap_ content" android: layout_ gravity=" center| right" android: background="@ drawable/ login_ eye" android: gravity=" center" android: paddingRight=" 12dp" /> </ FrameLayout> < Button android: id="@+ id/ sign_ in_ button" style="? android: textAppearanceSmall" android: layout_ width=" match_ parent" android: layout_ height=" wrap_ content" android: layout_ marginTop=" 16dp" android: text="@ string/ action_ sign_ in" android: textStyle=" bold" /> </ LinearLayout> </ ScrollView> </ LinearLayout>
完成開發(fā)后,把rwLoginActivity模板文件夾放在AndroidStudio安裝路徑的如下文件夾中:plugins\android\lib\templates\activities,關(guān)閉并重啟Android
Studio,就可以使用rwLoginActivity模板了。創(chuàng)建rwLoginActivity的界面如圖25-8和圖25-9所示:
在工程中選擇新建Activity時,也可以使用rwLoginActivity模板了,如圖25-10所示:
好了,APP開發(fā)公司本文關(guān)于“開發(fā)APP時怎樣快速實(shí)現(xiàn)模板的定制方法”詳解,就分享到這里,謝謝關(guān)注,博納網(wǎng)絡(luò)編輯整理。