Android自定義View實(shí)現(xiàn)搜索框(SearchView)功能
概述
在Android開(kāi)發(fā)中,當(dāng)系統(tǒng)數(shù)據(jù)項(xiàng)比較多時(shí),常常會(huì)在app添加搜索功能,方便用戶能快速獲得需要的數(shù)據(jù)。搜索欄對(duì)于我們并不陌生,在許多app都能見(jiàn)到它,比如豌豆莢
在某些情況下,我們希望我們的自動(dòng)補(bǔ)全信息可以不只是純文本,還可以像豌豆莢這樣,能顯示相應(yīng)的圖片和其他數(shù)據(jù)信息,因此Android給我們提供的AutoCompleteTextView往往就不夠用,在大多情況下我們都需要自己去實(shí)現(xiàn)搜索框。
分析
根據(jù)上面這張圖,簡(jiǎn)單分析一下自定義搜索框的結(jié)構(gòu)與功能,有
1. 搜索界面大致由三部門組成,如圖:輸入框+(自動(dòng)補(bǔ)全)提示框+結(jié)果列表。
2. 提示框的數(shù)據(jù)與輸入框輸入的文本是實(shí)時(shí)聯(lián)動(dòng)的,而結(jié)果列表只有在每次進(jìn)行搜索操作時(shí)才會(huì)更新數(shù)據(jù)
3. 輸入框的UI應(yīng)是動(dòng)態(tài)的,即UI隨著輸入的文本的改變而改變,如:在未輸入文本時(shí),清除按鈕應(yīng)該是隱藏的;只有當(dāng)框中有文本時(shí)才會(huì)顯示。
4. 軟鍵盤也應(yīng)該是動(dòng)態(tài)的,如完成搜索時(shí)應(yīng)自動(dòng)隱藏。
5. 選擇提示框的選項(xiàng)會(huì)自動(dòng)補(bǔ)全輸入框,且自動(dòng)進(jìn)行搜索
6. (external)有熱門搜索推薦/記錄搜索記錄的功能——熱門搜索推薦列表只在剛要進(jìn)行搜索的時(shí)候彈出,即未輸入文本時(shí),可供用戶選擇。
根據(jù)上面的分析,我們認(rèn)為一個(gè)搜索框應(yīng)該包含輸入框和提示框兩個(gè)部分。搜索框可以設(shè)置一個(gè)回調(diào)監(jiān)聽(tīng)接口,當(dāng)需要進(jìn)行搜索操作時(shí),調(diào)用監(jiān)聽(tīng)者的search()方法,從而實(shí)現(xiàn)具體的搜索操作以及結(jié)果列表的數(shù)據(jù)聯(lián)動(dòng)。
演示Demo
注意:
1. 這里,博主圖方便沒(méi)有模擬太多數(shù)據(jù),而且提示框和熱搜列表也都只是使用String類型的數(shù)據(jù),各位看官們可以根據(jù)自身需要去設(shè)置item_layout和相應(yīng)的adapter。
2. 由于個(gè)人習(xí)慣,博主在這個(gè)demo中使用了通用適配器,所以生成和設(shè)置adapter的代碼比較簡(jiǎn)略,看官們可以根據(jù)傳統(tǒng)的ViewHolder模式打造自己的adapter?;蛘邔W(xué)習(xí)一下通用適配器的打造??梢詤⒖歼@里(鴻神博客Again)學(xué)習(xí)一下通用適配器的打造,在我的源碼里面也有對(duì)應(yīng)的源碼。
實(shí)現(xiàn)
好了,說(shuō)了那么多,開(kāi)始來(lái)看代碼吧
先看SearchView的布局文件 search_layout.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:background="#eee" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout android:background="#eb4f38" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <FrameLayout android:layout_weight="1" android:layout_width="0dp" android:layout_height="wrap_content"> <EditText android:id="@+id/search_et_input" android:layout_gravity="center_vertical" android:layout_margin="10dp" android:drawableLeft="@drawable/search_icon" android:drawablePadding="5dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/search_edittext_shape" android:textSize="16sp" android:imeOptions="actionSearch" android:inputType="text" android:hint="請(qǐng)輸入關(guān)鍵字"/> <ImageView android:visibility="gone" android:layout_marginRight="20dp" android:src="@drawable/iv_delete_bg" android:id="@+id/search_iv_delete" android:layout_gravity="right|center_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </FrameLayout> <Button android:id="@+id/search_btn_back" android:layout_marginRight="10dp" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:layout_gravity="center_vertical" android:background="@drawable/btn_search_bg" android:layout_width="@dimen/btn_width" android:layout_height="@dimen/btn_height" android:text="返回" android:textColor="@color/color_white"/> </LinearLayout> <ListView android:visibility="gone" android:id="@+id/search_lv_tips" android:background="@drawable/lv_search_tips_bg" android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:layout_marginBottom="10dp" android:layout_width="match_parent" android:layout_height="200dp"> </ListView> </LinearLayout>
注意:demo中顏色什么的都直接用的rgb 值去設(shè)置,在實(shí)際開(kāi)發(fā)時(shí),需要把它們都統(tǒng)一管理到values目錄下 。
比較簡(jiǎn)單,需要注意的是EditText的這個(gè)屬性
android:imeOptions="actionSearch"
就是把Enter鍵設(shè)置為Search鍵,并把點(diǎn)擊Enter鍵的動(dòng)作設(shè)為actionSearch,這樣既可在代碼中監(jiān)聽(tīng)何時(shí)按下search鍵
沒(méi)什么說(shuō)的,bg屬性可以直接看看源碼。接下來(lái)看模擬的bean類,這里直接就叫Bean.java
public class Bean { private int iconId; private String title; private String content; private String comments; public Bean(int iconId, String title, String content, String comments) { this.iconId = iconId; this.title = title; this.content = content; this.comments = comments; } public int getIconId() { return iconId; } public void setIconId(int iconId) { this.iconId = iconId; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getComments() { return comments; } public void setComments(String comments) { this.comments = comments; } }
接著看主角SearchView.java
public class SearchView extends LinearLayout implements View.OnClickListener { /** * 輸入框 */ private EditText etInput; /** * 刪除鍵 */ private ImageView ivDelete; /** * 返回按鈕 */ private Button btnBack; /** * 上下文對(duì)象 */ private Context mContext; /** * 彈出列表 */ private ListView lvTips; /** * 提示adapter (推薦adapter) */ private ArrayAdapter<String> mHintAdapter; /** * 自動(dòng)補(bǔ)全adapter 只顯示名字 */ private ArrayAdapter<String> mAutoCompleteAdapter; /** * 搜索回調(diào)接口 */ private SearchViewListener mListener; /** * 設(shè)置搜索回調(diào)接口 * * @param listener 監(jiān)聽(tīng)者 */ public void setSearchViewListener(SearchViewListener listener) { mListener = listener; } public SearchView(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; LayoutInflater.from(context).inflate(R.layout.search_layout, this); initViews(); } private void initViews() { etInput = (EditText) findViewById(R.id.search_et_input); ivDelete = (ImageView) findViewById(R.id.search_iv_delete); btnBack = (Button) findViewById(R.id.search_btn_back); lvTips = (ListView) findViewById(R.id.search_lv_tips); lvTips.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { //set edit text String text = lvTips.getAdapter().getItem(i).toString(); etInput.setText(text); etInput.setSelection(text.length()); //hint list view gone and result list view show lvTips.setVisibility(View.GONE); notifyStartSearching(text); } }); ivDelete.setOnClickListener(this); btnBack.setOnClickListener(this); etInput.addTextChangedListener(new EditChangedListener()); etInput.setOnClickListener(this); etInput.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) { if (actionId == EditorInfo.IME_ACTION_SEARCH) { lvTips.setVisibility(GONE); notifyStartSearching(etInput.getText().toString()); } return true; } }); } /** * 通知監(jiān)聽(tīng)者 進(jìn)行搜索操作 * @param text */ private void notifyStartSearching(String text){ if (mListener != null) { mListener.onSearch(etInput.getText().toString()); } //隱藏軟鍵盤 InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE); imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS); } /** * 設(shè)置熱搜版提示 adapter */ public void setTipsHintAdapter(ArrayAdapter<String> adapter) { this.mHintAdapter = adapter; if (lvTips.getAdapter() == null) { lvTips.setAdapter(mHintAdapter); } } /** * 設(shè)置自動(dòng)補(bǔ)全adapter */ public void setAutoCompleteAdapter(ArrayAdapter<String> adapter) { this.mAutoCompleteAdapter = adapter; } private class EditChangedListener implements TextWatcher { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { } @Override public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { if (!"".equals(charSequence.toString())) { ivDelete.setVisibility(VISIBLE); lvTips.setVisibility(VISIBLE); if (mAutoCompleteAdapter != null && lvTips.getAdapter() != mAutoCompleteAdapter) { lvTips.setAdapter(mAutoCompleteAdapter); } //更新autoComplete數(shù)據(jù) if (mListener != null) { mListener.onRefreshAutoComplete(charSequence + ""); } } else { ivDelete.setVisibility(GONE); if (mHintAdapter != null) { lvTips.setAdapter(mHintAdapter); } lvTips.setVisibility(GONE); } } @Override public void afterTextChanged(Editable editable) { } } @Override public void onClick(View view) { switch (view.getId()) { case R.id.search_et_input: lvTips.setVisibility(VISIBLE); break; case R.id.search_iv_delete: etInput.setText(""); ivDelete.setVisibility(GONE); break; case R.id.search_btn_back: ((Activity) mContext).finish(); break; } } /** * search view回調(diào)方法 */ public interface SearchViewListener { /** * 更新自動(dòng)補(bǔ)全內(nèi)容 * * @param text 傳入補(bǔ)全后的文本 */ void onRefreshAutoComplete(String text); /** * 開(kāi)始搜索 * * @param text 傳入輸入框的文本 */ void onSearch(String text); // /** // * 提示列表項(xiàng)點(diǎn)擊時(shí)回調(diào)方法 (提示/自動(dòng)補(bǔ)全) // */ // void onTipsItemClick(String text); } }
搜索框主要包含兩個(gè)結(jié)構(gòu):輸入欄+彈出框(自動(dòng)補(bǔ)全或熱門搜素推薦)。
代碼不多,實(shí)現(xiàn)很簡(jiǎn)單,主要是需要給EditText(輸入框)設(shè)置點(diǎn)擊監(jiān)聽(tīng)和文本改變監(jiān)聽(tīng),有以下幾點(diǎn):
1. 當(dāng)輸入框沒(méi)有文本時(shí),點(diǎn)擊輸入框,顯示熱門搜索列表框。
2. 當(dāng)輸入框有文本時(shí),點(diǎn)擊輸入框,應(yīng)顯示自動(dòng)補(bǔ)全列表框。
3. 當(dāng)輸入框的文本發(fā)生改變時(shí),需要更新自動(dòng)補(bǔ)全列表框的數(shù)據(jù)。由于這些數(shù)據(jù)應(yīng)該是在外部(調(diào)用者)中獲得的,所以可以通過(guò)接口回調(diào)的形式,當(dāng)需要更新時(shí),通知監(jiān)聽(tīng)者更新數(shù)據(jù)。
4. 當(dāng)輸入框的文本從空”“變換到非空時(shí),即有字符時(shí),界面應(yīng)顯示自動(dòng)補(bǔ)全框,隱藏?zé)衢T搜索框。
5. 當(dāng)輸入框的文本從非空變?yōu)榭諘r(shí),系統(tǒng)應(yīng)隱藏自動(dòng)補(bǔ)全框和熱門搜索框。
6. 需要監(jiān)聽(tīng)是否按下search鍵(enter),按下時(shí)通知監(jiān)聽(tīng)者執(zhí)行search操作
結(jié)合以上6點(diǎn)和在上文分析過(guò)的內(nèi)容,就能很輕松地實(shí)現(xiàn)該view。
之后來(lái)看看搜索界面的布局文activity_main.xml
<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" tools:context=".MainActivity" android:orientation="vertical"> <com.yetwish.customsearchdemo.activity.widge.SearchView android:id="@+id/main_search_layout" android:layout_width="match_parent" android:layout_height="wrap_content"> </com.yetwish.customsearchdemo.activity.widge.SearchView> <ListView android:visibility="gone" android:id="@+id/main_lv_search_results" android:layout_width="match_parent" android:layout_height="wrap_content"> </ListView> </LinearLayout>
就是一個(gè)SearchView加上一個(gè)結(jié)果列表,這些我們?cè)谏衔亩挤治鲞^(guò)了,所以也沒(méi)什么好說(shuō)的。布局可根據(jù)自身需求去自定義。
最后就是搜索界面調(diào)用該view MainActiviy.java
public class MainActivity extends Activity implements SearchView.SearchViewListener { /** * 搜索結(jié)果列表view */ private ListView lvResults; /** * 搜索view */ private SearchView searchView; /** * 熱搜框列表adapter */ private ArrayAdapter<String> hintAdapter; /** * 自動(dòng)補(bǔ)全列表adapter */ private ArrayAdapter<String> autoCompleteAdapter; /** * 搜索結(jié)果列表adapter */ private SearchAdapter resultAdapter; /** * 數(shù)據(jù)庫(kù)數(shù)據(jù),總數(shù)據(jù) */ private List<Bean> dbData; /** * 熱搜版數(shù)據(jù) */ private List<String> hintData; /** * 搜索過(guò)程中自動(dòng)補(bǔ)全數(shù)據(jù) */ private List<String> autoCompleteData; /** * 搜索結(jié)果的數(shù)據(jù) */ private List<Bean> resultData; /** * 默認(rèn)提示框顯示項(xiàng)的個(gè)數(shù) */ private static int DEFAULT_HINT_SIZE = 4; /** * 提示框顯示項(xiàng)的個(gè)數(shù) */ private static int hintSize = DEFAULT_HINT_SIZE; /** * 設(shè)置提示框顯示項(xiàng)的個(gè)數(shù) * * @param hintSize 提示框顯示個(gè)數(shù) */ public static void setHintSize(int hintSize) { MainActivity.hintSize = hintSize; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); initData(); initViews(); } /** * 初始化視圖 */ private void initViews() { lvResults = (ListView) findViewById(R.id.main_lv_search_results); searchView = (SearchView) findViewById(R.id.main_search_layout); //設(shè)置監(jiān)聽(tīng) searchView.setSearchViewListener(this); //設(shè)置adapter searchView.setTipsHintAdapter(hintAdapter); searchView.setAutoCompleteAdapter(autoCompleteAdapter); lvResults.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) { Toast.makeText(MainActivity.this, position + "", Toast.LENGTH_SHORT).show(); } }); } /** * 初始化數(shù)據(jù) */ private void initData() { //從數(shù)據(jù)庫(kù)獲取數(shù)據(jù) getDbData(); //初始化熱搜版數(shù)據(jù) getHintData(); //初始化自動(dòng)補(bǔ)全數(shù)據(jù) getAutoCompleteData(null); //初始化搜索結(jié)果數(shù)據(jù) getResultData(null); } /** * 獲取db 數(shù)據(jù) */ private void getDbData() { int size = 100; dbData = new ArrayList<>(size); for (int i = 0; i < size; i++) { dbData.add(new Bean(R.drawable.icon, "android開(kāi)發(fā)必備技能" + (i + 1), "Android自定義view——自定義搜索view", i * 20 + 2 + "")); } } /** * 獲取熱搜版data 和adapter */ private void getHintData() { hintData = new ArrayList<>(hintSize); for (int i = 1; i <= hintSize; i++) { hintData.add("熱搜版" + i + ":Android自定義View"); } hintAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, hintData); } /** * 獲取自動(dòng)補(bǔ)全data 和adapter */ private void getAutoCompleteData(String text) { if (autoCompleteData == null) { //初始化 autoCompleteData = new ArrayList<>(hintSize); } else { // 根據(jù)text 獲取auto data autoCompleteData.clear(); for (int i = 0, count = 0; i < dbData.size() && count < hintSize; i++) { if (dbData.get(i).getTitle().contains(text.trim())) { autoCompleteData.add(dbData.get(i).getTitle()); count++; } } } if (autoCompleteAdapter == null) { autoCompleteAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, autoCompleteData); } else { autoCompleteAdapter.notifyDataSetChanged(); } } /** * 獲取搜索結(jié)果data和adapter */ private void getResultData(String text) { if (resultData == null) { // 初始化 resultData = new ArrayList<>(); } else { resultData.clear(); for (int i = 0; i < dbData.size(); i++) { if (dbData.get(i).getTitle().contains(text.trim())) { resultData.add(dbData.get(i)); } } } if (resultAdapter == null) { resultAdapter = new SearchAdapter(this, resultData, R.layout.item_bean_list); } else { resultAdapter.notifyDataSetChanged(); } } /** * 當(dāng)搜索框 文本改變時(shí) 觸發(fā)的回調(diào) ,更新自動(dòng)補(bǔ)全數(shù)據(jù) * @param text */ @Override public void onRefreshAutoComplete(String text) { //更新數(shù)據(jù) getAutoCompleteData(text); } /** * 點(diǎn)擊搜索鍵時(shí)edit text觸發(fā)的回調(diào) * * @param text */ @Override public void onSearch(String text) { //更新result數(shù)據(jù) getResultData(text); lvResults.setVisibility(View.VISIBLE); //第一次獲取結(jié)果 還未配置適配器 if (lvResults.getAdapter() == null) { //獲取搜索數(shù)據(jù) 設(shè)置適配器 lvResults.setAdapter(resultAdapter); } else { //更新搜索數(shù)據(jù) resultAdapter.notifyDataSetChanged(); } Toast.makeText(this, "完成搜素", Toast.LENGTH_SHORT).show(); } }
使用SearchView比較簡(jiǎn)單,只要給SearchView設(shè)置onSearchViewListener監(jiān)聽(tīng)接口,實(shí)現(xiàn)對(duì)應(yīng)的方法,并給SearchView傳入熱搜版和自動(dòng)補(bǔ)全的adapter既可。
這里使用的匹配算法比較簡(jiǎn)單,也沒(méi)有考慮多個(gè)搜索詞的情況,(這些之后都可以再完善),主要實(shí)現(xiàn)就是在總數(shù)據(jù)中匹配每個(gè)Bean的Title是否包含搜索詞,包含則表示該數(shù)據(jù)匹配,否則不匹配。然后將所有匹配的Bean顯示到結(jié)果列表中。
考慮到實(shí)際開(kāi)發(fā)中,數(shù)據(jù)量十分龐大,可以只把結(jié)果集的一部分(如前10個(gè))顯示出來(lái),上拉到底的時(shí)候再加載之后的記錄,也就是可以加入上拉加載的機(jī)制,使app性能更優(yōu)化。
自動(dòng)補(bǔ)全匹配也是采用相同的算法。算法都比較簡(jiǎn)單,當(dāng)然也可以弄得復(fù)雜點(diǎn),比如根據(jù)“ ”(空格)去分割輸入文本,再逐個(gè)考慮單個(gè)搜索詞的匹配項(xiàng),把匹配次數(shù)從多到少排列出結(jié)果集等等。這里不細(xì)說(shuō)。
這里有一個(gè)問(wèn)題是進(jìn)入該搜索界面時(shí)需要加載所有的數(shù)據(jù)項(xiàng)到內(nèi)存,當(dāng)數(shù)據(jù)項(xiàng)很多時(shí),是否會(huì)占用大量的內(nèi)存?如果是應(yīng)該如何避免?是采用只加載一部分?jǐn)?shù)據(jù)的形式,還是直接使用搜索詞到數(shù)據(jù)庫(kù)中查詢更優(yōu)?還請(qǐng)各位看官大神們給出寶貴的意見(jiàn)~
好了,自定義搜索框到這就打造完成啦,是不是感覺(jué)簡(jiǎn)單過(guò)頭了。
各位看官如果有任何問(wèn)題可評(píng)論或者發(fā)郵件跟我聯(lián)系yetwish@gmail.com
囧~忘記貼代碼了,代碼放在github上,各位看官直接download即可
鏈接:https://github.com/yetwish/CustomSearchView
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android 自定義View的使用介紹
- Android開(kāi)發(fā)使用自定義View將圓角矩形繪制在Canvas上的方法
- Android自定義View設(shè)定到FrameLayout布局中實(shí)現(xiàn)多組件顯示的方法 分享
- Android自定義View實(shí)現(xiàn)廣告信息上下滾動(dòng)效果
- Android自定義View實(shí)現(xiàn)繪制虛線的方法詳解
- Android自定義View之自定義評(píng)價(jià)打分控件RatingBar實(shí)現(xiàn)自定義星星大小和間距
- Android自定義View實(shí)現(xiàn)loading動(dòng)畫加載效果
- Android自定義View實(shí)現(xiàn)漸變色進(jìn)度條
- Android 使用Kotlin自定義View的方法教程
- Android?自定義view中根據(jù)狀態(tài)修改drawable圖片
相關(guān)文章
Android+Flutter實(shí)現(xiàn)彩虹圖案的繪制
彩虹,是氣象中的一種光學(xué)現(xiàn)象,當(dāng)太陽(yáng)光照射到半空中的水滴,光線被折射及反射,在天空上形成拱形的七彩光譜。接下來(lái),我們就自己手動(dòng)繪制一下彩虹圖案吧2022-11-11Android編程使用Service實(shí)現(xiàn)Notification定時(shí)發(fā)送功能示例
這篇文章主要介紹了Android編程使用Service實(shí)現(xiàn)Notification定時(shí)發(fā)送功能,涉及Android服務(wù)Service控制通知的發(fā)送功能相關(guān)操作技巧,需要的朋友可以參考下2017-08-08Android自定義控件實(shí)現(xiàn)水波紋效果
這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)水波紋效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01android開(kāi)機(jī)自啟動(dòng)apk的方法
今天小編就為大家分享一篇android開(kāi)機(jī)自啟動(dòng)apk的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08Android開(kāi)發(fā)返回鍵明暗點(diǎn)擊效果的實(shí)例代碼
這篇文章主要介紹了Android開(kāi)發(fā)返回鍵明暗點(diǎn)擊效果的實(shí)例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04Android漲姿勢(shì)知識(shí)點(diǎn)之你沒(méi)用過(guò)的BadgeDrawable
現(xiàn)在Android中有許多的應(yīng)用仿蘋果的在應(yīng)用圖標(biāo)上顯示小紅點(diǎn),下面這篇文章主要給大家介紹了關(guān)于Android漲姿勢(shì)知識(shí)點(diǎn)之你沒(méi)用過(guò)的BadgeDrawable的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09Android使用AlertDialog實(shí)現(xiàn)的信息列表單選、多選對(duì)話框功能
在使用AlertDialog實(shí)現(xiàn)單選和多選對(duì)話框時(shí),分別設(shè)置setSingleChoiceItems()和setMultiChoiceItems()函數(shù)。具體實(shí)現(xiàn)代碼大家參考下本文吧2017-03-03最新Android版本、代號(hào)、對(duì)應(yīng)API/NDK級(jí)別、發(fā)布時(shí)間及市場(chǎng)份額
這篇文章主要介紹了最新Android版本、代號(hào)、對(duì)應(yīng)API/NDK級(jí)別、發(fā)布時(shí)間及市場(chǎng)份額,在開(kāi)發(fā)Android應(yīng)用時(shí)會(huì)碰到如何選擇Android版本級(jí)API級(jí)別的問(wèn)題,看完這篇文章后相信這個(gè)問(wèn)題會(huì)迎刃而解2017-12-12動(dòng)態(tài)添加LinearLayout的高度實(shí)例
下面小編就為大家?guī)?lái)一篇?jiǎng)討B(tài)添加LinearLayout的高度實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04