記錄開發(fā)安卓apk界面的踩坑

由于公司的手持是由原生的安卓寫的,剛好想了解一下安卓,就開始長達(dá)2周的開發(fā)過程,5個頁面,可能因為跟java有關(guān)系,本來是做前端開發(fā)的,自己雖然原來學(xué)過java,都忘光了...開發(fā)初期格外艱難..好在在自己努力,老大和小哥哥的幫助下,開發(fā)算是基本圓滿完成了,現(xiàn)在來總結(jié)一下中間遇到的問題和解決方法。

問題1: 比如數(shù)字1.23或者1.26,都進行五入的操作,變成1.3該如何實現(xiàn)?

答: 有提供內(nèi)置的BigDecimal方法,詳情可見https://segmentfault.com/a/1190000002886883,介紹的很詳細(xì)。

eg:
  double value1 = 1.23;
  double value2 = 1.25;
  BigDecimal bd1 = new BigDecimal(value1);
  BigDecimal bd2 = new BigDecimal(value2);
  double result1 = bd1.setScale(1, ROUND_UP).doubleValue();  //第一個參數(shù)表示保留的小數(shù)位數(shù),第二個表示精度取值方式

  double result2 = bd2.setScale(1, ROUND_UP).doubleValue(); 

ROUND_UP: 正數(shù)是大于等于該數(shù)的那個最近數(shù),負(fù)數(shù)是小于等于該數(shù)的那個最近數(shù)
ROUND_DOWN: 與ROUND_UP相反
還有很多其他的精度取值方式...

問題2: EditText控件,默認(rèn)是獲取光標(biāo)位置,并彈出軟鍵盤。不想要軟鍵盤,但是光標(biāo)位置希望一直保留閃爍,如何實現(xiàn)?

答:

nameText.setInputType(InputType.TYPE_NULL); 

上述代碼,會隱藏軟鍵盤,但是也會讓光標(biāo)消失,不可取。

后發(fā)現(xiàn)網(wǎng)上有一種根據(jù)安卓版本,來判斷進行隱藏,看這篇鏈接:http://www.mamicode.com/info-detail-940579.html

問題3: 如何給listView中的item設(shè)置一個固定的高度?

答:
image

問題4: 布局問題:如何實現(xiàn)左右布局?如何實現(xiàn)上部內(nèi)容固定,中間部分可滾動,按鈕始終固定在底部呢?

答:

對于左右布局,最簡單的方法就是,外層布局使用RelativeLayout,包裹的子元素分別設(shè)置android:layout_alignParentLeft="true", android:layout_alignParentRight="true"

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
  <TextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_alignParentLeft="true"
    android:textSize="24sp"
   android:text="左邊" />
   <TextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_alignParentRight="true"
    android:textSize="24sp"
   android:text="右邊" />
</RelativeLayout>

對于后者問題,即布局這樣寫:即

<RelativeLayout
android:layout_width="wrap_parent"
android:layout_height="wrap_parent">
<TextView
android:id="@+id/nameText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="7"
android:gravity="right"
android:textSize="22sp" />

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_parent"
    android:layout_height="wrap_parent"
    android:layout_below="@+id/nameText"
     >
       <ScrollView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/nameText"
            android:scrollbars="none">
        <LinearLayout 
                android:layout_width="wrap_parent"
                android:layout_height="wrap_parent"> 
         XXXXX.....
       </LinearLayout>
      </ScrollView>
    </LinearLayout>

   <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="5dp"
        android:orientation="horizontal">
        <Button
            android:id="@+id/resetbutton"
            android:layout_width="100dp"
            android:layout_height="40dp"
            android:layout_gravity="center"
            android:background="@drawable/grey_button"
            android:ems="5"
            android:gravity="center"
            android:text="重置"
            android:textColor="@color/white"
            android:textSize="24sp" />
         <Button
            android:id="@+id/confirmbutton"
            android:layout_width="100dp"
            android:layout_height="40dp"
            android:layout_gravity="center"
            android:background="@drawable/light_button"
            android:ems="5"
            android:gravity="center"
            android:text="確定"
            android:textColor="@color/white"
            android:textSize="24sp" />
   </LinearLayout>

</RelativeLayout>

即:

(1)最外層是個RelativeLayout布局,中間可滾動部分是個ScrollView,外層包裹一個LinearLayout,為這個LinearLayout設(shè)置屬性: android:layout_below="@+id/nameText",表示該布局位于該TextView下面。

(2)ScrollView它的里面只能包裹一個子元素,通常是LinearLayout,取消滾動條的顯示:android:scrollbars="none"

(3)底部固定的按鈕外層包裹LinearLayout,為其設(shè)置
** android:layout_alignParentBottom="true"**,就可始終讓其居于底部了。

問題5: listView中,如何實現(xiàn)展示一級和二級菜單?類似于這樣:

image

但其實項目的需求是簡化了的,不用點擊一級菜單,再顯示或者隱藏二級菜單,而是直接一次顯示所有的一級菜單二級菜單,即像這樣:

image

粉色部分的是一級菜單,褐色部分的是二級菜單?

答:這個問題困擾了我一天多,后來問了技術(shù)老大,了解了一下思路就解決了...還是考慮的有問題,思路沒有打開啊!

按照上述圖示,后臺傳過來的json數(shù)據(jù)是這樣的:(list里面嵌套list)

{
  list: [
   {
     "name": xxx1,
     "usage": xxx1,
     "childList": [
       {
         "childName": xx1
         "code":xx1
        },
        {
         "childName": xx2
         "code":xx2
        }
      ]
   },
   {
     "name": xxx2,
     "usage": xxx2,
     "childList": [
       {
         "childName": xx3
         "code":xx3
        },
      ]
   }
  ]
}

本來想使用網(wǎng)上有些教程的:ExpandableListView,但是后來各種報錯...只能忍痛棄之

這里還是使用的是listView,里面是listItem。

我剛開始的錯誤做法是,就是將數(shù)據(jù)重組,只要遇到childList, 遍歷childList里面的數(shù)據(jù),并放入map數(shù)組中,而數(shù)組本身父級的name,id也都塞進這個map數(shù)組中。

即最終形成的數(shù)據(jù)就是這樣:


     "resetList": [
       {
         "childName": xx1
         "code":xx1,
         "name": xxx1,
         "usage": xxx1,
        },
        {
         "childName": xx2
         "code":xx2,
          "name": xxx1,
         "usage": xxx1,
        },
        {

         "childName": xx3
         "code":xx3,
         "name": xxx2,
         "usage": xxx2,
        },
    ]

這樣在遍歷時,本來第一個parent下面應(yīng)該有2個子元素,第二個parent下面有1個子元素,現(xiàn)在遍歷渲染時,即變成這樣:

image

明顯不對!要急哭無可奈何的時候,請教了技術(shù)老大,老大提供了這樣一種思路,就是===》

把父級元素單獨提取出來放在一個數(shù)組中,把孩子元素提取出來放到一個數(shù)組中,在listView重寫SimpleAdapter的方法時,進行判斷,如果父級元素有,設(shè)置父級元素的樣式,孩子元素隱藏;如果孩子元素有,就隱藏父級元素,設(shè)置孩子元素的樣式。

即數(shù)據(jù)結(jié)果變成這樣:

   "resetList": [
       {
          "name": xxx1,
          "usage": xxx1,
        },
        {
          "name": xxx2,
          "usage": xxx2,
        },
        {
         "childName": xx1
         "code":xx1,
        },
        {
         "childName": xx2
         "code":xx2,
        },
        {
         "childName": xx3
         "code":xx3,
        },
    ]

Adapter接收的數(shù)據(jù)還是傳遞所有的字段名:


SimpleAdapter simpleAdapter = new abnormalTipsDetailAdapter2(AbnormalTipsDetailActivity.this,
                   dataList3,
                   R.layout.abnormal_tips_detail_item2,
                   new String[]{"name", "usage", "childName", "code"},
                   new int[]{R.id.name, R.id.usage, R.id.childName, R.id.code}
           );

     detail_listView.setAdapter(simpleAdapter);

在重寫的SimpleAdapter的這個方法getView再進行判斷:

   public class abnormalTipsDetailAdapter2 extends SimpleAdapter {
   List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
   private LayoutInflater layoutInflater;
   private Context context;
   private int hiddenType;

   public abnormalTipsDetailAdapter2(Context context, List<? extends Map<String, ?>> data,
                                     int resource, String[] from, int[] to) {
       super(context, data, resource, from, to);
       this.context = context;
       this.data = (List<Map<String, Object>>) data;
       this.layoutInflater = LayoutInflater.from(context);
   }

   public final class abnormalTipsDetailComponent {
       public TextView name;
       public TextView usage;
       public TextView childName;
       public TextView code;

       public RelativeLayout child; //子組件包裹層
       public RelativeLayout topWrapper; //父組件包裹層
   }

   @Override
   public int getCount() {
       // TODO Auto-generated method stub
       return super.getCount();
   }

   @Override
   public Object getItem(int position) {
       // TODO Auto-generated method stub
       return super.getItem(position);
   }

   @Override
   public long getItemId(int position) {
       // TODO Auto-generated method stub
       return super.getItemId(position);
   }


   public View getView(final int position, View convertView, ViewGroup parent) {
       // TODO Auto-generated method stub)
       abnormalTipsDetailComponent abnormal_detail_component = null;
       if (abnormal_detail_component == null) {
           abnormal_detail_component = new abnormalTipsDetailComponent();
           //獲得組件,實例化組件
           convertView = layoutInflater.inflate(R.layout.abnormal_tips_detail_item2, null);

           abnormal_detail_component.name = (TextView) convertView.findViewById(R.id.name);
           abnormal_detail_component.usage = (TextView) convertView.findViewById(R.id.usage);
           abnormal_detail_component.childName = (TextView) convertView.findViewById(R.id.childName);
           abnormal_detail_component.code = (TextView) convertView.findViewById(R.id.code);
   
           abnormal_detail_component.topWrapper = (RelativeLayout) convertView.findViewById(R.id.topWrapper);
           abnormal_detail_component.child = (RelativeLayout) convertView.findViewById(R.id.child);

           convertView.setTag(abnormal_detail_component);
       } else {
           abnormal_detail_component = (abnormalTipsDetailComponent) convertView.getTag();
       }

       String name = (String) data.get(position).get("name"); //父組件里才有該值
       String childName = (String) data.get(position).get("childName"); //子組件里才有該值

       String usage = "";
       String code ="";

       if(name != null) {
           usage = (String) data.get(position).get("usage");

           //顯示父元素
           abnormal_detail_component.topWrapper.setVisibility(View.VISIBLE);
           abnormal_detail_component.child.setVisibility(View.GONE);

           abnormal_detail_component.name.setText(name);
           abnormal_detail_component.usage.setText(usage);

       }else if(childName != null) {
           code = (String) data.get(position).get("code");

           //顯示對應(yīng)的子元素
           abnormal_detail_component.topWrapper.setVisibility(View.GONE);
           abnormal_detail_component.child.setVisibility(View.VISIBLE);

           abnormal_detail_component.code.setText(code + "號");
           abnormal_detail_component.code.setTextColor(Color.RED);
       }

       return convertView;
   }
}

這樣就解決了。

問題6: listView中的listItem點擊每一項時,發(fā)現(xiàn)不、無法響應(yīng)對應(yīng)的setOnItemClickListener方法?

答:查了百度發(fā)現(xiàn),這個原因是由于:

ListViewItem中有Button或者Checkable的子類控件的話,那么默認(rèn)focus是交給了子控件,而ListView的Item能被選中的基礎(chǔ)是Item本身

所以,分為2步,

(1)為有Button或者Checkable的子類控件增加屬性:

android:focusable="false"
android:clickable="false"
android:focusableInTouchMode="false"

(2)在item最外層增加屬性:

android:descendantFocusability="blocksDescendants"

問題7: 原生的android開發(fā)無論是接收數(shù)據(jù)還是傳遞數(shù)據(jù),是接收json格式的數(shù)據(jù),如何解析呢?

答:這里使用的是插件Gson來解析數(shù)據(jù)。

在app/build.gradle下,dependencies,加入該插件:

image

在File/Synchronize后,項目加入該包后,要解析或生成對應(yīng)的json格式的數(shù)據(jù),看這篇鏈接,https://www.cnblogs.com/liqw/p/4266209.html 寫的很詳細(xì)。

問題8: 頁面由一個頁面跳轉(zhuǎn)到另一個頁面,在原生的android中,使用的是Intent,通過

Intent intent = new Intent();
intent.setClass(MainActivity.this, OtherActivity.class);
startActivity(intent);
finish();

就可以實現(xiàn)跳轉(zhuǎn),當(dāng)然這個是未涉及到頁面?zhèn)髦担?dāng)涉及到傳值時,傳遞的值分別是String,int,或者是一個jsonArray,接收的頁面該如何解析獲得值呢?

答: 這里,這樣實現(xiàn),先把jsonArray要轉(zhuǎn)化為json字符串形式,再在接收的頁面進行解析,代碼實現(xiàn)如下:

Intent intent = new Intent();
intent.setClass(MainActivity.this, OtherActivity.class);

String waitAreaList = object.getString("list"); //這里解析jsonObject中的jsonArray的鍵,獲取對應(yīng)的值

//轉(zhuǎn)化jsonArray為json字符串,項目統(tǒng)一使用的是Gson插件解析json數(shù)據(jù)
String str = new Gson.toJson(waitAreaList); 

//發(fā)送數(shù)據(jù)
intent.putExtra("extra", String.valueOf(123)); 
intent.putExtra("name","張三");
intent.putExtra("waitAreaList", str);
startActivity(intent);
finish();

//接收數(shù)據(jù)
 Intent intent = getIntent();
 int extra = intent.getIntExtra("extra", 0); //獲取int類型的數(shù)據(jù),為其默認(rèn)賦值一個0
 String name = intent.getStringExtra("name"); //獲取string類型的數(shù)據(jù)
 String stringData = intent.getStringExtra("waitAreaList"); //獲取json字符串?dāng)?shù)組

 //判斷json字符串是否有數(shù)據(jù),有數(shù)據(jù)進行解析,還原成正常的jsonArray
 if(stringData.length() != 0) {
     //將JsonArray類型的Json字符串解析成對象方法
      JsonParser parser = new JsonParser();
      JsonArray array = parser.parse(stringData).getAsJsonArray();
     
     ....//執(zhí)行某些方法
 }

問題9: 給textView字體加粗?

答: 對于英文字體,直接在對應(yīng)的xml中,為TextView設(shè)置樣式

android:textStyle="bold"

而對于中文字體,則要動態(tài)的設(shè)置:

TextView text = (TextView)findViewById(R.id.text);//或從xml導(dǎo)入 
text.getPaint().setFakeBoldText(true); //字體加粗

問題10: 實現(xiàn)類似于ios的那種swithBtn效果?switchBtn放在了listView的item,如何點擊時,進行相應(yīng),請求接口?

答:

(1)對于問題1:剛開始百度了一堆,剛開始還是想搬磚,模仿網(wǎng)上的demo自定義實現(xiàn),后來技術(shù)老大說,這個東西應(yīng)該有插件,網(wǎng)上找一下,就不用自己寫很多代碼了。果斷搜索后,發(fā)現(xiàn)了插件,github網(wǎng)址:https://github.com/kyleduo/SwitchButton ,例子很詳細(xì)。

同理,還是現(xiàn)在app/build.gradle下的dependencies加入

compile 'com.github.zcweng:switch-button:0.0.3@aar'

然后在對應(yīng)要使用的xml實現(xiàn):

   <com.suke.widget.SwitchButton
    android:id="@+id/switchBtn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:layout_marginTop="10dp"
    android:layout_marginRight="10dp"
    app:sb_checked_color="#8BC34A"  //開啟的背景顏色:綠色
    app:sb_enable_effect="true"  //動態(tài)效果:默認(rèn)是true,開啟
    app:sb_show_indicator="false" //是否顯示指示器,
    app:sb_uncheck_color="#C6C7C5" /> //關(guān)閉的背景顏色:灰色

(2)對于問題2,還是考慮了一段時間的。。因為listView的數(shù)據(jù)源是通過調(diào)后端接口動態(tài)獲得的,因為listItem的文字涉及到動態(tài)的改變顏色,所以得重寫對應(yīng)的adapter方法,adapter繼承simpleAdapter方法。跟之前問題5的重寫Adapter方法是一樣的。

問題是,如果在重寫的getView方法中,點擊對應(yīng)的switchBtn按鈕,進行發(fā)起請求,代碼會報錯...那如何在本身當(dāng)前頁面的Activity中,進行請求?

在listView獲取數(shù)據(jù)后,進行

wait_area_list_view.setAdapter(simpleAdapter);

獲取list的子元素,在遍歷時,遇到問題,** ListView在setAdapter()后,getChildCount總是0的原因?**

==>網(wǎng)上查到 setAdapater是非同步(asynchronous) 的,所以類似js promise處理這種異步的請求或數(shù)據(jù),android也提供方法:加入post函式去更新ListView的ChildView即可。

這篇鏈接解決了我的問題:

http://www.cnblogs.com/linlf03/archive/2013/06/06/3120408.html

 wait_area_list_view.post(new Runnable() { //這里為了解決setAdapter是非同步(asynchronous),取得的childCount總是0的問題
        @Override
        public void run() {
            if (datalist.size() == wait_area_list_view.getChildCount()) {
               int childLen =  wait_area_list_view.getChildCount(); //獲取listView下的item個數(shù)

               for(int i = 0; i< childLen; i++) {
                  RelativeLayout layout = (RelativeLayout) wait_area_list_view.getChildAt(i); //獲得子item的layout
                  SwitchButton switchBtn = (SwitchButton) layout.findViewById(R.id.switchBtn); //獲得switch按鈕
                  final TextView areaId = (TextView) layout.findViewById(R.id.areaId);

                 //switchBtn提供當(dāng)狀態(tài)更改時的監(jiān)聽器函數(shù)
                 switchBtn.setOnCheckedChangeListener(new SwitchButton.OnCheckedChangeListener() {
                        @Override
                        public void onCheckedChanged(SwitchButton view, boolean isChecked) {
                           if(isChecked) {
                               int areaId =  Integer.valueOf(areaId.getText().toString()); //獲得當(dāng)前改變狀態(tài)的id

                              changeStatus(areaId,isChecked); //進行對應(yīng)的請求
                              xxx..
                           }                    
                     } 
                 }
               }
             }
        }
 });


//執(zhí)行對應(yīng)的后臺請求方法
private void changeStatus(int areaId,boolean useState) {
   xxx... 
}

解決問題~

問題11: 安卓的listView如何獲取item的EditText值?(因為:當(dāng)動態(tài)添加數(shù)據(jù)item或者刪除某個item時,由于頁面會重繪,導(dǎo)致之前填寫的edittext值被重刷消失...)

答: 這個問題還是當(dāng)時來看,困擾了我半天多,還是最后在小哥哥的幫助和理清思路下,順利解決了!真希望自己有一天,業(yè)務(wù)做的久了,在為別人解答疑惑時 都能思路清晰,經(jīng)驗豐富...

首先,要明確一點的是:listView中的item是復(fù)用的,就像我們看一個頁面中有很多條新聞一樣,不是像我們所想象的,有多少個新聞,就有多少個item渲染出來。假設(shè)頁面有1000條新聞呢?頁面會渲染卡死,體驗很差,所以按原生的安卓來寫的話,所謂復(fù)用就是: 假設(shè)listView每次就規(guī)定渲染10條item,當(dāng)我們上滑加載更多時,假設(shè)此時有3條被遮擋了,那此時要加載后續(xù)的數(shù)據(jù),安卓的實現(xiàn)是回收前3條被遮擋的item資源,在接下來的展示復(fù)用前面的3條,進行顯示,周而復(fù)始這樣循環(huán)利用,這樣確保了頁面的流暢性和性能的提升,不得不說,是一個很棒的思路和做法。

當(dāng)然,碰到的問題就是如何獲取listitem中edittext的值?

image

好的做法就是: 重寫listView的Adapter.getView函數(shù)方法時 ,用一個list數(shù)組來保存Editext的值,監(jiān)聽EditText值的變化,當(dāng)值有非空有變化時 ,就將對應(yīng)的值,存儲起來。其中數(shù)組的下標(biāo)就是上述listItem的position值,就是上述圖示顯示的0,1,2...

當(dāng)頁面比如有數(shù)據(jù)增加進來或者刪除時,我們此時不用擔(dān)心數(shù)據(jù)沒有,因為預(yù)先在一個數(shù)組里保存了對應(yīng)的位置和數(shù)據(jù),在頁面重繪后,再重新獲取list數(shù)組中的值,進行對應(yīng)的setText賦值,這樣就保證了數(shù)據(jù)不會丟失。

這里核心代碼主要是如下所示:

image
image

博客園的這篇鏈接: https://www.cnblogs.com/exmyth/p/3799260.html和另外一個鏈接:http://blog.sina.cn/dpool/blog/s/blog_80c69e390101g221.html 也提供幫助我很多,十分感謝!

問題12: 如何實現(xiàn)自定義dialog?

答:請戳這篇鏈接:https://blog.csdn.net/zhuwentao2150/article/details/52254579

問題13: 安卓原生系統(tǒng)中,如何讓EditText光標(biāo)集中時,始終隱藏軟鍵盤,但光標(biāo)不失去焦點?

答: 這次在stackoverflow上找到了答案。

(1)設(shè)置EditText的inputType為null,隱藏了軟鍵盤,但同時光標(biāo)也消失了... 沒啥用!
(2) 在AndroiManifest.xml中對應(yīng)的activity中,設(shè)置:android:windowSoftInputMode="stateAlwaysHidden" 然并卵..也沒啥用!
(3)當(dāng)當(dāng)當(dāng)~
最終的高票答案來了,應(yīng)該是可取的,附上代碼:

// Update the EditText so it won't popup Android's own keyboard, since I have my own.
EditText editText = (EditText)findViewById(R.id.edit_mine);
editText.setOnTouchListener(new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        v.onTouchEvent(event);
        InputMethodManager imm = (InputMethodManager)v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (imm != null) {
            imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
        }                
        return true;
    }
});

解決方法是通過onTouch時,檢測input的變化,動態(tài)的去顯示隱藏軟鍵盤。

這里我未使用的原因是,由于使用的是listview,可能listitem會有許多個,每個item中又有EditText,處理每個時,都進行動態(tài)的判斷和監(jiān)聽,無疑是比較耗性能的。

所以采取了另外的答案,就是設(shè)置在xml這樣設(shè)置:

<EditText
android:textIsSelectable="true"
...
/>

或者設(shè)置:

EditText editText = (EditText) findViewById(R.id.editText);
editText.setTextIsSelectable(true);

對于這個屬性,官方給出的解釋是:

the cursor will still be present, and you'll be able to select/copy/cut/paste, but SoftKeyboard will never show但是要求安卓的sdk版本是在>=11以上

這樣就解決啦~中間其實還遇到問題,剛開始只是在相應(yīng)的xml中設(shè)置該屬性,一臺手持設(shè)備上表現(xiàn)正常,但另一個頁面就光標(biāo)和軟鍵盤就都消失了。。排查了一圈,發(fā)現(xiàn)應(yīng)該是手持設(shè)備sdk的版本問題導(dǎo)致的,所以最終不在xml設(shè)置屬性,在代碼里判斷版本,再設(shè)置屬性:

   int version = Build.VERSION.SDK_INT;
   EditText editText = (EditText) findViewById(R.id.editText);

    if (version >= 11) {
        editText.setRawInputType(InputType.TYPE_CLASS_TEXT);
        editText.setTextIsSelectable(true);
    } else {
        editText.setRawInputType(InputType.TYPE_NULL);
        editText.setFocusable(true);
    }

問題14: listView的listItem中,使用了checkbox控件,由于checkbox的獲取焦點優(yōu)先級高于listItem本身的setOnItemClickListener,所以希望當(dāng)點擊listitem時,也能選中或者不選中對應(yīng)的checkbox,而不是只能點擊checkbox進行選中非選中?

答:這里搜索了一圈,后來有篇博客提供了很好的答案: http://blog.sina.com.cn/s/blog_6fff321b0100otwo.html

即布局大概是這樣的:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/check_box_list_item"
android:minHeight="45dp"
android:orientation="horizontal"
android:descendantFocusability="blocksDescendants"
>
    <CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/boilBox"
        style="@style/BoilAreaCheckBox"
        android:background="@drawable/selector"
        android:button="@null"
        android:checked="false"
        android:focusable="false"
        android:layout_marginTop="5dp"
        android:layout_marginLeft="20dp"
        />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:textSize="20sp"
            android:id="@+id/areaName"
            android:layout_marginTop="5dp"
      />
/>

對應(yīng)的activity中這樣寫:

     checkbox_list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
   //         LinearLayout layout = (LinearLayout) adapterView.getChildAt(position);
   //         CheckBox checkBox = (CheckBox) layout.getChildAt(0);
            CheckBox checkBox = (CheckBox) view.findViewById(R.id.boilBox);
            checkBox.setChecked(!checkBox.isChecked());
        }
    });   

注意:

(1): 這里的 checkbox_list是listView的id名稱;

(2): 這里setItem時,去動態(tài)監(jiān)聽布局,拿到每次點擊的positon對應(yīng)的LinearLayout; 由于CheckBox控件都是布局的第一個元素,所以是 CheckBox checkBox = (CheckBox) layout.getChildAt(0);

(3): 通過setChecked控制選中,通過isChecked()判斷當(dāng)前是否選中

(4): checkBox獲取焦點的優(yōu)先級,不要搶占點擊listitem的優(yōu)先級,即對于checkbox設(shè)置屬性:

android:checked="false"
android:focusable="false"

而對于listItem層級,設(shè)置屬性

android:descendantFocusability="blocksDescendants"

這里在之后發(fā)現(xiàn)大bug!!注意注意!!,就是listview中使用checkbox,當(dāng)數(shù)據(jù)多時,由于listview本身的復(fù)用item的特性,導(dǎo)致getChildAt會報空指針!!

所以之前的代碼用斜杠注釋掉了,現(xiàn)在點擊某一個item下的checkbox,直接在setOnItemClickListener中找到當(dāng)前view下的checkBox,之后再進行選中非選中操作。

問題15: 如果讓edittext的光標(biāo)始終集中在輸入文字的末尾?

答: 添加該行代碼:

EditText et = (EditText)R.id.findViewById(R.id.edit);
et.setSelection(et.getText().length()); //讓光標(biāo)在文字末尾

問題16: 當(dāng)listview中使用了checkbox時,由于listitem的復(fù)用的特性,導(dǎo)致勾選的狀態(tài)混亂或者勾選狀態(tài)消失,如何解決?

答:雖然這個問題百度和stackoverflow上一搜一大堆,但是質(zhì)量良莠不齊的,耽誤了2天的時間搜索答案,結(jié)果中午吃飯的時候突然有了思路,外加查到一篇好的博文,終于解決問題!!大塊人心!!

這里好好總結(jié)處理一下:

這篇博文: https://blog.csdn.net/jdsjlzx/article/details/7318659 幫助很多!強烈建議一看啊!

我最終的解決方法也是模仿文章的方法來做的:

這里,首先重寫Adapter類,繼承自SimpleAdapter,這里,用一個HashMap<Integar,Boolean>來保存checkbox的勾選狀態(tài),默認(rèn)初始都為false

public class BindBoidAreaAdapter extends SimpleAdapter {

List<Map<String, Object>> data = new ArrayList<Map<String, Object>>();
private LayoutInflater layoutInflater;
private Context context;

private static HashMap<Integer, Boolean> isSelected = null;  //用來控制CheckBox的選中狀況

public BindBoidAreaAdapter(Context context, List<? extends Map<String, ?>> data,
                           int resource, String[] from, int[] to) {
    super(context, data, resource, from, to);
    this.context = context;
    this.data = (List<Map<String, Object>>) data;
    this.layoutInflater = LayoutInflater.from(context);

    isSelected = new HashMap<Integer, Boolean>();

    initStatus();
}

// 初始化isSelected的數(shù)據(jù),默認(rèn)都為未勾選狀態(tài)
private void initStatus() {
    for (int i = 0; i < data.size(); i++) {
        getIsSelected().put(i, false); 
    }
}

//向activity暴露checkbox的勾選狀態(tài),返回這個HashMap
public static HashMap<Integer, Boolean> getIsSelected() {
    return isSelected;
}

public final class bindBoidAreaComponent {
    public CheckBox boilBox;
    public TextView areaName;
    public TextView areaId;
}

@Override
public int getCount() {
    // TODO Auto-generated method stub
    return super.getCount();
}

@Override
public Object getItem(int position) {
    // TODO Auto-generated method stub
    return super.getItem(position);
}

@Override
public long getItemId(int position) {
    // TODO Auto-generated method stub
    return super.getItemId(position);
}

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final int pos = position;
    // TODO Auto-generated method stub)
    bindBoidAreaComponent bind_boil_area = null;
    if (bind_boil_area == null) {
        bind_boil_area = new bindBoidAreaComponent();
        //獲得組件,實例化組件
        convertView = layoutInflater.inflate(R.layout.check_box_list_item, null);

        bind_boil_area.boilBox = (CheckBox) convertView.findViewById(R.id.boilBox);
        bind_boil_area.areaName = (TextView) convertView.findViewById(R.id.areaName);
        bind_boil_area.areaId = (TextView) convertView.findViewById(R.id.areaId);

        convertView.setTag(bind_boil_area);
    } else {
        bind_boil_area = (bindBoidAreaComponent) convertView.getTag();
    }


    bind_boil_area.boilBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
      @Override
       public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
          getIsSelected().put(pos,isChecked); //用來解決listView在滾動時,checkbox狀態(tài)混亂的問題
       }
    });

    //綁定數(shù)據(jù)
    String areaName = (String) data.get(position).get("areaName");
    Integer areaId = (Integer) data.get(position).get("areaId");

    bind_boil_area.areaName.setText(areaName);
    bind_boil_area.areaId.setText("" + areaId);

    //根據(jù)isSelected設(shè)置checkbox的選中
    bind_boil_area.boilBox.setChecked(getIsSelected().get(pos));

    return convertView;
  }

}

上述adapter方法中,最重要的幾個方法,

(1)一個是構(gòu)建HashMap,初始化checkbox的state, 方法為initStatus();

(2) 如果要將adapter中設(shè)置的HashMap,在activity中 也能使用,則要寫一個public static方法,返回這個HashMap,之后就可以在activity中,BindBoidAreaAdapter.getIsSelected(),訪問得到我們設(shè)置的HashMap。(當(dāng)時思路就卡在這里了!不知道如果去訪問adpater中的設(shè)置的這個數(shù)據(jù),恩,還是有收獲的)

這里就涉及到android的static,是靜態(tài)變量,一般靜態(tài)變量用的不多,靜態(tài)常量用的比較多。

static即始終會保存在內(nèi)存里,不會隨著activity的銷毀被回收,會占用內(nèi)存。static的使用,是為了讓多個對象共用一份空間,節(jié)省內(nèi)存,由于不正確的操作或者編碼不規(guī)范,會造成內(nèi)存泄露。。但這里先不深入那么多...

(3)特別注意,中間的針對于checkbox的setOnCheckedChangeListener監(jiān)聽的方法中,

getIsSelected().put(pos,isChecked); //該行代碼,、在滾動時,動態(tài)設(shè)置checkbox的選中非選中為true 或者false

   //根據(jù)isSelected設(shè)置checkbox的選中
  bind_boil_area.boilBox.setChecked(getIsSelected().get(pos));

再來看Activity方法中,接收的數(shù)據(jù)是這樣的,后臺會傳一份全部的數(shù)據(jù)list,和(如果之前有勾選checkbox)傳遞一個checkedList數(shù)組,反之傳來的checkedList為空字符串。

我這里具體的做法是,請求數(shù)據(jù)獲得全部的數(shù)據(jù)后,先去動態(tài)繪制出這個listview

private void getData() {
     xxx....
     setAllCheckViews();

    //這里前面加判斷,如果有勾選的list,則去顯示勾選的list
    checkbox_list.post(new Runnable() { //這里為了解決setAdapter是非同步(asynchronous),取得的childCount總是0的問題
       @Override
        public void run() {
         checkedBoxView(checkedArray);
      }
    });
}


//設(shè)置全部的checkbox名稱與id
private void setAllCheckViews() {
    int allcount = allArray.size();
    for (int i = 0; i < allcount; i++) {
        Map<String, Object> map = new HashMap<String, Object>();
        String areaName = allArray.get(i).getAsJsonObject().get("areaName").getAsString();
        int areaId = allArray.get(i).getAsJsonObject().get("areaId").getAsInt();

        map.put("areaName", areaName);
        map.put("areaId", areaId);
        allList.add(map);
    }

    simpleAdapter = new bindBoidAreaAdapter(BindBoilAreaActivity.this,
            allList,
            R.layout.check_box_list_item,
            new String[]{"areaName", "areaId"},
            new int[]{R.id.areaName, R.id.areaId}
    );

    checkbox_list.setAdapter(simpleAdapter);

}

然后,listView中的各個item顯示出來后,再進行具體的勾選狀態(tài):

private void checkedBoxView(JsonArray checkedArray) {
    int allCount = allArray.size();
    int checkedCount = checkedArray.size();
    for (int i = 0; i < allCount; i++) {
        for (int j = 0; j < checkedCount; j++) {
            int allId = allArray.get(i).getAsJsonObject().get("areaId").getAsInt();
            int checkId = checkedArray.get(j).getAsJsonObject().get("areaId").getAsInt();
            if (allId == checkId) { //勾選對應(yīng)checkbox
                BindBoidAreaAdapter.getIsSelected().put(i, true); //這里就是通過雙重循環(huán)比對id,若id相同,則設(shè)置對應(yīng)的checkbox為選中
            }
        }
    }
    simpleAdapter.notifyDataSetChanged(); //重繪一下頁面,否則頁面觀察不到變化!
}

上述代碼中,只有通過:

BindBoidAreaAdapter.getIsSelected().put(i, true);

該行代碼,BindBoidAreaAdapter這個類才能訪問到里面構(gòu)造的靜態(tài)方法getIsSelected,從而拿到BindBoidAreaAdapter類中預(yù)先定義好的靜態(tài)變量hashMap,進行對應(yīng)的更改操作。

但很奇怪,在自己的理解中,在類中定義一個public的方法,按理說不需要static修飾,在activity中實例化這個類的對象,就可以通過對象訪問到該方法了。

但當(dāng)我去掉BindBoidAreaAdapter中對于isSelected這個hashMap的static的修飾,同時也去掉對于方法名getIsSelected的static的修飾時,Activity中

BindBoidAreaAdapter.getIsSelected().put(i, true); 這行代碼就會報錯,說Non-static method 'getIsSelected' cannot be referenced from a static context.

即后來問了小哥哥,討論了一下,看書了解到,即只有靜態(tài)方法可以訪問到自身類中的靜態(tài)域

就比如這個例子

public static int getId() { return nextId; // return static field }

此時假設(shè)包含這個靜態(tài)方法getId的類叫Employee,我們就可以通過

int id = Employee.getId(); //獲得數(shù)據(jù)

可以使用對象調(diào)用靜態(tài)方法,比如我們此時可以

BindBoidAreaAdapter bindBoidAreaAdapter = null; //bindBoidAreaAdapter為BindBoidAreaAdapter的對象

在循環(huán)中,再

bindBoidAreaAdapter.getIsSelected().put(i, true);

不過書上講,這種方式很容易造成混淆,原因是getIsSelected得到的結(jié)果跟bindBoidAreaAdapter沒有任何關(guān)系。

書上建議:

建議使用類名,而不是對象來調(diào)用靜態(tài)方法。

書上同樣指出,以下兩種情況使用靜態(tài)方法:

(1)一個方法不需要訪問對象狀態(tài),其所需參數(shù)都是通過顯式參數(shù),如Math.pow(x,a),就是一個靜態(tài)方法

(2)一個方法只需要訪問類中的靜態(tài)域,比如我們之前所寫代碼的:BindBoidAreaAdapter.getIsSelected().put(i, true);

這里原來自己老的做法是,雙重循環(huán)遍歷,然后

private void checkedBoxView(JsonArray checkedArray) {
    int allCount = allArray.size();
    int checkedCount = checkedArray.size();
    for (int i = 0; i < allCount; i++) {
        for (int j = 0; j < checkedCount; j++) {
           int allId = allArray.get(i).getAsJsonObject().get("areaId").getAsInt();
           int checkId = checkedArray.get(j).getAsJsonObject().get("areaId").getAsInt();

          LinearLayout layout = (LinearLayout) checkbox_list.getChildAt(i); 
          CheckBox checkBox = (CheckBox) layout.findViewById(R.id.boilBox);
                    
         if(allId = checkId) {
          checkBox.setChecked(true);
        }
   }
 }
}

這里當(dāng)時就報nullPointerException了,比如現(xiàn)在allArray現(xiàn)在是9個,而頁面可視區(qū)域只有7個,getChildAt最多定位的postion只有7,當(dāng)循環(huán)遍歷到8和9時,listview找不到,就報錯了。。。

解決報錯的方法:即網(wǎng)上說的很多,positon要為可視區(qū)域的position,有2種解決方法:

一種是: 即最外層的循環(huán),allCount并非 allArray.size(),而是listView可視區(qū)域的數(shù)量,

int allCount = checkbox_list.getLastVisiblePosition() - checkbox_list.getFirstVisiblePosition(); 

另一種是:內(nèi)部的getChildAt,使用,

int positon = i - checkbox_list.getFirstVisiblePosition(); 
LinearLayout layout = (LinearLayout) checkbox_list.getChildAt(positon); 

雖然上述2種做法可以解決不報錯了,但是還是沒有解決勾選對應(yīng)的應(yīng)選中的checkbox,還是會復(fù)用item,checkbox的狀態(tài)混亂,所以。。舍棄,但記錄下來,為防止以后碰到類似問題。

一個bug解決了2天多...最終有學(xué)到東西,還是挺好的,希望自己之后安卓這部分做好,還是回歸前端,好好夯實前端基礎(chǔ)吧。

問題17: 如何讓ScrollView下的內(nèi)容都能居中顯示呢?

答:百度搜了一圈,沒有很靠譜的,后來同樣是在stackoverflow上找到答案。

問題描述,類似于這樣:

image

好幾個優(yōu)質(zhì)的答案,我選用的是第一種,即設(shè)置linearlayout的中的屬性

android:gravity="center_horizontal"

android:layout_gravity="center_horizontal"

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scrollView1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:paddingTop="12dp"
    android:paddingBottom="20dp"
    android:scrollbarStyle="outsideOverlay" >


    <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" 
        android:layout_gravity="center"
        android:gravity="center">

        <Button
            android:id="@+id/button1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="check" 
            android:gravity="center_vertical|center_horizontal"/>
    </LinearLayout>

</ScrollView>

第二種好的做法是,在ScrollView外面再包裹一層Relativelayout,為了讓其生效,首先要設(shè)置ScrollView下的layout_height:wrap_content,

其次,對于ScrollView,實際上此時為RelativeLayout的子元素,要使其居中,設(shè)置屬性 android:layout_centerVertical="true"

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">

<ScrollView
    android:id="@+id/scrollView1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" 
    android:layout_centerVertical="true" >

 <LinearLayout
        android:id="@+id/linearLayout1"
        android:layout_width="wrap_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
</LinearLayout>
</ScrollView>
</RelativeLayout>

但個人感覺這樣,一層層嵌套包裹,實際上頁面渲染會變慢,最好的方式實際上是頁面結(jié)構(gòu)越簡單越好。

問題18: 遇到一個問題,就是安卓的頁面中有EditText控件,在它的下面又有spinner控件,EditText控件 在第一次輸入后,按Enter鍵表現(xiàn)正常,當(dāng)?shù)诙屋斎氚磂nter鍵,則光標(biāo)會定位到spinner控件上,如何處理?

答: 這里也不知道是不是手持設(shè)備的原因,最終是為EditText控件設(shè)置屬性: android:nextFocusDown="@id/soakEdit",即下次光標(biāo)定位還是在其本身,就可以解決這個問題了。

<EditText
        android:id="@+id/soakEdit"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="center_horizontal"
        android:background="@null"
        android:ems="8"
        android:hint="@string/soak_scan"
        android:nextFocusDown="@id/soakEdit"
        android:textSize="23sp" />

問題19: 使用原生安卓的button時,button使用的是一張背景圖。當(dāng)發(fā)起請求,由于請求是異步的,得到結(jié)果有延遲,導(dǎo)致用戶以為沒有效果,會多點按鈕,體驗效果差。更好的體驗是:發(fā)起請求有個loading的狀態(tài),得到返回結(jié)果后隱藏這個這個loading狀態(tài)。

答:開始考慮這個問題的時候,跟之前做過的switchButton一樣,首先應(yīng)該考慮的是有無這樣的button插件實現(xiàn)。

網(wǎng)上搜到了這種效果的progressButton,但是在設(shè)置build.gradle,該插件的依賴時,各種報錯,沒有辦法解決,所以最終棄之。

后來在stackoverflow上,找到提供思路的答案,即使用安卓原生的組件progressBar,具體鏈接,參考:https://stackoverflow.com/questions/12559461/how-to-show-progress-barcircle-in-an-activity-having-a-listview-before-loading

這個高票答案寫的很棒,我也基本上按照這個思路來:

image

即:

  1. 先在xml里設(shè)置好ProgressBar的布局,默認(rèn)隱藏;
  2. 在activity里,初始化該ProgressBar
  3. 發(fā)送請求時,顯示這個ProgressBar,得到請求結(jié)果時,隱藏該ProgressBar。

中間出現(xiàn)的問題,可能集中在布局這里,原來只是button設(shè)置background為drawable下的圖片資源,ProgressBar也可以放在按鈕的前面,但是問題是分離了,loading未包含在btn里面。

后來好的解決方法:

即將ProgressBar和Button都放在一個Linearlayout布局中,就像這樣:

 <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:background="@drawable/bh_button_shape"
            >
            <ProgressBar
                android:id="@+id/pbNormal"
                android:layout_width="35dp"
                android:layout_height="wrap_content"
                android:layout_marginLeft="15dp"
                android:visibility="invisible"
                />

            <Button
                android:id="@+id/bindbutton"
                android:layout_width="wrap_content"
                android:layout_height="40dp"
                android:background="@android:color/transparent"
                android:text="綁定"
                android:layout_marginRight="45dp"
                android:textColor="@color/white"
                android:textSize="24sp" />
</LinearLayout>

具體步驟:
1、為LinearLayout設(shè)置背景為原來的button背景圖,orientation設(shè)置為水平horizontal
2、ProgressBar默認(rèn)不顯示
3、Button設(shè)置背景為透明,android:background="@android:color/transparent"
4、具體再調(diào)整樣式細(xì)節(jié)。

這中間還遇到一個問題,如何讓一個按鈕始終居于頁面底部呢?
兩種方式:

第一種:

如果是Linearlayout布局,則給上面的Linearlayout設(shè)置android:layout_weight="1" ,這樣可以讓底部的button到達(dá)底部。

第二種:

使用Relativelayout布局,對于Button設(shè)置屬性=》,android:layout_alignParentBottom="true"

問題20: 如何讓兩個TextView在頁面上實現(xiàn)左右平分布局?

答:百度查的答案都良莠不齊,后來在stackoverflow上找到答案。

參考鏈接在這里:https://stackoverflow.com/questions/13441405/android-how-to-split-between-two-textview-the-full-width-of-screen-exactly-fifty

總結(jié)一下,有2種方案:

第一種:

用一個Linearlayout包裹這2個TextView,設(shè)置layout_width為fill_parent,給子TextView要么設(shè)置layout_weight為1要么都不設(shè)置這個layout_weight。

代碼如下:

<LinearLayout 
     android:layout_width = "fill_parent"
    android:layout_height = "wrap_content"
     orientation = "horizontal">
    <TextView
        android:layout_width = "fill_parent"
        android:layout_height = "wrap_content"
        android:text = "Text 1"
    />
    <TextView
        android:layout_width = "fill_parent"
        android:layout_height = "wrap_content"
        android:text = "Text 2"
    />
</LinearLayout>

第二種:(比較高票,我也使用的這個,實現(xiàn)了平分布局的效果)

代碼如下:

<RelativeLayout
    android:layout_width = "fill_parent" 
    android:layout_height = "wrap_content">
    <LinearLayout 
    android:layout_width = "fill_parent" 
    android:layout_height = "wrap_content" 
    android:orientation="horizontal"
    android:weightSum = "2">
        <TextView
            android:layout_width = "fill_parent"
            android:layout_height = "wrap_content"
            android:text = "YOUR FIRST TEXT"
            android:weight = "1"
        />
        <TextView
            android:layout_width = "fill_parent"
            android:layout_height = "wrap_content"
             android:text = "YOUR SECOND TEXT"
            android:weight = "1"
        />
    </LinearLayout>

</RelativeLayout>

該方法的要點有3個:

  1. 設(shè)置他們的layout_width均為fill_parent
  2. 給外層包裹的Linearlayout設(shè)置權(quán)重總和android:weightSum = "2",android:orientation="horizontal"
  3. 設(shè)置子TextView的android:weight = "1"

答案這么介紹這個weight sum屬性:

   the weight sum will be used to measured the portion of the textview like if you give the weight sum 3 and give 1 textview weight = 2 and another textview weight = 1 the layout will be 2/3 (66.666%) and 1/3 (33.3333%) so if you set it 2 and give every textview weight = 1 it should be 50% and 50%

問題21: 如何將一個JSONArray中的值取出來,添加到一個字符串?dāng)?shù)組里?如何將一個字符串?dāng)?shù)組轉(zhuǎn)化為以逗號分隔的字符串?

答:同樣是在stackoverflow上找到答案,國外的answer,真是很棒~

這里,原來百度查到的,將字符串?dāng)?shù)組變?yōu)樽址梢杂肧tringUtils.join(',',strArray);

但后來查到: StringUtils.join(',',strArray) 是Jave 8里添加的一個方法,所以不能用在Android里。

可以用TextUtils.join來代替,

String result = TextUtils.join(", ", list); //list

所以最終所有問題的實現(xiàn),代碼如下可以解決:

ArrayList<String> stringArr = new ArrayList<String>();
JSONArray jsonArray = object.getJSONArray("list");
int count = jsonArray.length();
for(int i = 0; i < count;i++) {
  String code = jsonArray.getJSONObject(i).getString("code");
  stringArr.add(code);
}

String[] stringArr = stringArr.toArray(new String[stringArr.size()]);
String bucketStr = TextUtils.join(",",stringArr);

問題22: (1)安卓的spinner下拉控件,原來是用一個背景圖片替換原生的spinner樣式,但是由于固定了寬度等,當(dāng)文字變多時,文字會被遮擋住,如何優(yōu)化樣式?
(2)如何讓spinner下拉選項的文字(默認(rèn)是靠左的),實現(xiàn)居中顯示?

答: 對于(1),(2)找了一圈,后來在stackoverflow上找到答案,spinner此時不用設(shè)置background為圖片,用定義的樣式xml文件實現(xiàn)。具體看代碼:

對于問題1:在spinner外包裹一個LinearLayout,為這個LinearLayout設(shè)置background

<LinearLayout
    android:layout_width="200dp"
    android:layout_height="40dp"
    android:background="@drawable/bg_spinner"
    >
  <Spinner
      android:id="@+id/print_spinner"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:background="@null"
      />
</LinearLayout>

背景樣式文件,放在drawable文件下的bg_spinner.xml中

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:top="2dp">
        <shape>
            <corners android:radius="2dp"/>
            <stroke
                android:width="2dp"
                android:color="#A4A4A4" />
            <padding
                android:top="2dp"
                android:right="2dp"/>
        </shape>
    </item>
    <item android:right="4dp">
        <bitmap android:gravity="right|center_vertical"
            android:src="@drawable/custom_spinner_icon"
            >
        </bitmap>
    </item>
</layer-list>

注: 第一個item是設(shè)置spinner的圓角大小,邊框顏色粗細(xì)和padding,第二個item是設(shè)置旁邊的倒著的小三角箭頭

對于問題2,如何使spinner下拉選項Item中的文字居中?默認(rèn)是靠左顯示的。

第一步,設(shè)置一個xml文件命名為spinner_item.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:textColor="#929292"
    android:textSize="22sp"
    android:gravity="center"
    android:textAlignment="center"
    />

注意:這里之前設(shè)置了屬性android:gravity="center",android:textAlignment="center,但是文字就是不居中,查閱了半天,后來發(fā)現(xiàn)原來設(shè)置android:layout_width和android:layout_height為wrap_content,改為match_parent后就生效了。

第二步,在java類中,調(diào)用spinner的時候,使用自定義的這個xml下拉

ArrayAdapter<String> adapter= new ArrayAdapter<String>(context, R.layout.spinner_item, myList);
adapter.setDropDownViewResource(R.layout.spinner_item)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,237評論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,957評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,248評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,356評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 72,081評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,485評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,534評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,720評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,263評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,025評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,204評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,787評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,461評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,874評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,105評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,945評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 48,205評論 2 375

推薦閱讀更多精彩內(nèi)容