安卓開發(fā)需要注意/知道的小問題

  1. android:descendantFocusability屬性,其中翻譯成中文意思是子孫焦點(diǎn)旁蔼,也就是當(dāng)前 viewgroup 和其子控件誰獲取當(dāng)前焦點(diǎn)的意思。常用在 listview 和 recyclerView 中,當(dāng) listView 每個(gè)條目需要監(jiān)聽點(diǎn)擊事件,同時(shí)每個(gè)條目里的子控件例如:button够吩、checkbox 等也需要點(diǎn)擊焦點(diǎn)的時(shí)候。

此屬性對應(yīng)的值有三個(gè)丈氓,分別是

beforeDescendants:viewgroup會優(yōu)先其子類控件而獲取到焦點(diǎn)

afterDescendants:viewgroup只有當(dāng)其子類控件不需要獲取焦點(diǎn)時(shí)才獲取焦點(diǎn) 

blocksDescendants:viewgroup會覆蓋子類控件而直接獲得焦點(diǎn)

官方文檔對此說明是:

android:descendantFocusabilityDefines the relationship between the ViewGroup and its descendants when looking for a View to take focus.Must be one of the following constant values.


對應(yīng)的值.jpg
  1. Android 里 canvas.draw() 方法需要注意的:
    當(dāng)畫矩形 canvas.drawRect() 時(shí)如果是空心的矩形周循,即設(shè)置了 paint.setStyle(Paint.Style.STROKE) 和 paint.setStrokeWidth(20) 屬性强法,則要注意矩形起始點(diǎn)和右下角坐標(biāo)位置應(yīng)該分別減去線條寬度的一半,即
canvas.drawRect(strokeWidth/2湾笛,strokeWidth/2饮怯,width-strokeWidth/2,height-strokeWidth/2,paint);  //左上右下,畫筆

舉個(gè)例子 參考來源

矩形畫布.png

如果在上圖位置畫一個(gè) 50*100dp 的矩形(見下圖)嚎研,其中線條寬度是20dp,起始左上角坐標(biāo)和結(jié)束右下角坐標(biāo)不是(0蓖墅,0)和 (100,50)临扮,此時(shí)應(yīng)該注意線條寬度也占據(jù)了位置置媳,起始位置應(yīng)該加上線條寬度的一半,終點(diǎn)位置應(yīng)該減去線條寬度的一半公条,也就是取線條的中間拇囊。這里就是

canvas.drawRect(10,10靶橱,90, 40, paint);  //這里暫不考慮 dp 轉(zhuǎn) px 的分辨率問題寥袭,都當(dāng)成 px 處理。
需要實(shí)現(xiàn)的矩形

延伸

①.如果畫矩形不設(shè)置 stroke 屬性关霸,直接設(shè)置 paint.setStyle(Style.FILL)传黄,則直接從紅色矩形左上角坐標(biāo)點(diǎn)開始即可;

②.如果畫圓队寇,也設(shè)置了描邊膘掰,如下圖,那么畫圓的時(shí)候半徑就是布局的一半減去線條寬度的一半佳遣。


圓.png

③.如果畫線识埋,即 canvas.drawLine(),如下圖所示零渐,如果設(shè)置 paint.setStrokeWidth(20)窒舟,
則表示畫線的線條粗細(xì)為 20px ,那么畫的時(shí)候坐標(biāo)點(diǎn)就是圖中紅點(diǎn)诵盼,即左邊界線條的中間點(diǎn)惠豺,即(0,10)這個(gè)點(diǎn);


線條
  1. 全面屏手機(jī)顯示 view 的時(shí)候风宁,部分手機(jī)底部有留白或者黑邊洁墙,也就是沒有鋪滿屏幕顯示。
    其實(shí)只要設(shè)置項(xiàng)目的 targetSdkVersion > 24戒财,即大于 7.0热监,則默認(rèn)支持全面屏,也就不會有黑邊顯示固翰。如果項(xiàng)目是比較老的版本狼纬,并且 targetSdkVersion < 24 且不好隨便更改羹呵,也可以在 manifest 文件里配置以下內(nèi)容:
<meta-data
            android:name="android.max_aspect"
            android:value="2.4" />

這樣也可以做到全屏展示。為什么這里 value 是 2.4疗琉,其實(shí)這是計(jì)算出來的一個(gè)預(yù)估值冈欢,因?yàn)閭鹘y(tǒng)屏幕:ratio_float = 16/9 = 1.778 ;像小米的 MIX2 是 18 / 9 =2 的盈简,mix3 是 19.5 / 9 = 2.16凑耻,越來越長可以寫稍微大點(diǎn)留一些余地,所以直接寫成 2.4 更保險(xiǎn)一些柠贤。以后開發(fā)估計(jì)都會支持全面屏香浩,并且 Google 支持把 targetSdkVersion 寫成最新版本,所以基本上以后的項(xiàng)目不會涉及到全面屏顯示不全的問題臼勉,因?yàn)?targetSdkVersion 大于 24 已經(jīng)默認(rèn)支持了全面屏顯示邻吭。

  1. 安卓中三個(gè)獲取定義的 dimens 值的方法:
  getDimension、getDimensionPixelOffset 和 getDimensionPixelSize

在開發(fā)中宴霸,在代碼里動(dòng)態(tài)設(shè)置布局的間距囱晴、尺寸等數(shù)值時(shí),最好使用 /res/values/dimens.xml 里的自定義尺寸瓢谢,這樣可以做到不同分辨率的屏幕適配畸写,因?yàn)榭梢远x不同的 dimens 文件對應(yīng)不同的分辨率。現(xiàn)在就看下上邊三種方法對應(yīng)獲取的值的區(qū)別氓扛。

首先說明三個(gè)方法返回的都是對應(yīng)的像素值枯芬,也就是不管定義的是 dp 還是 sp 或者 px,返回的都是 px 單位的值,可以通過以下的例子來看:

<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="dp_value">17dp</dimen>
    <dimen name="sp_value">17sp</dimen>
    <dimen name="px_value">17px</dimen>
</resources>

        //獲取屏幕信息
        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        int width = displayMetrics.widthPixels;
        int height = displayMetrics.heightPixels;
        float density = displayMetrics.density;
        int densityDpi = displayMetrics.densityDpi;
        System.out.println("屏幕寬:"+ width + "屏幕高:"+height);
        System.out.println("屏幕密度:"+ density + "屏幕密度 DPI:" + densityDpi);


        float a1 = getResources().getDimension(R.dimen.px_value);
        float a2 = getResources().getDimension(R.dimen.dp_value);
        float a3 = getResources().getDimension(R.dimen.sp_value);
        System.out.println("getDimension 中 px值是:" + a1);
        System.out.println("getDimension 中 dp值是:" + a2);
        System.out.println("getDimension 中 sp值是:" + a3);

        int b1 = getResources().getDimensionPixelSize(R.dimen.px_value);
        int b2 = getResources().getDimensionPixelSize(R.dimen.dp_value);
        int b3 = getResources().getDimensionPixelSize(R.dimen.sp_value);
        System.out.println("getDimensionPixelSize 中 px值是:" + b1);
        System.out.println("getDimensionPixelSize 中 dp值是:" + b2);
        System.out.println("getDimensionPixelSize 中 sp值是:" + b3);

        int c1 = getResources().getDimensionPixelOffset(R.dimen.px_value);
        int c2 = getResources().getDimensionPixelOffset(R.dimen.dp_value);
        int c3 = getResources().getDimensionPixelOffset(R.dimen.sp_value);
        System.out.println("getDimensionPixelOffset 中 px值是:" + c1);
        System.out.println("getDimensionPixelOffset 中 dp值是:" + c2);
        System.out.println("getDimensionPixelOffset 中 sp值是:" + c3);

打印數(shù)據(jù)是:

2019-07-28 17:43:27.469 23912-23912/com.ispring.gameplane I/System.out: 屏幕寬:1080 屏幕高:2030
2019-07-28 17:43:27.470 23912-23912/com.ispring.gameplane I/System.out: 屏幕密度:2.75屏幕密度 DPI:440
2019-07-28 17:43:27.470 23912-23912/com.ispring.gameplane I/System.out: getDimension 中 px值是:17.0
2019-07-28 17:43:27.470 23912-23912/com.ispring.gameplane I/System.out: getDimension 中 dp值是:46.75
2019-07-28 17:43:27.470 23912-23912/com.ispring.gameplane I/System.out: getDimension 中 sp值是:46.75
2019-07-28 17:43:27.470 23912-23912/com.ispring.gameplane I/System.out: getDimensionPixelSize 中 px值是:17
2019-07-28 17:43:27.470 23912-23912/com.ispring.gameplane I/System.out: getDimensionPixelSize 中 dp值是:47
2019-07-28 17:43:27.470 23912-23912/com.ispring.gameplane I/System.out: getDimensionPixelSize 中 sp值是:47
2019-07-28 17:43:27.470 23912-23912/com.ispring.gameplane I/System.out: getDimensionPixelOffset 中 px值是:17
2019-07-28 17:43:27.470 23912-23912/com.ispring.gameplane I/System.out: getDimensionPixelOffset 中 dp值是:46
2019-07-28 17:43:27.470 23912-23912/com.ispring.gameplane I/System.out: getDimensionPixelOffset 中 sp值是:46

通過結(jié)果可以看出采郎,獲取某個(gè) dimen 的值千所,如果單位是 dp 或者 sp ,需要乘以 density (屏幕密度),如果是 px ,則不需要尉剩。

不同點(diǎn):
getDimension:返回的是 float 類型的值真慢。
getDimensionPixelSize: 返回的是 int 類型的值,并且由浮點(diǎn)型轉(zhuǎn)成整型時(shí)是四舍五入的方式理茎。
getDimensionPixelOffset : 返回的是 int 類型的值,并且由浮點(diǎn)型轉(zhuǎn)成整型時(shí)管嬉,原則是忽略小數(shù)點(diǎn)部分皂林。

  1. textView 在代碼中設(shè)置粗體可以這樣設(shè)置:
TextView tv = (TextView)findViewById(R.id.TextView01);  
TextPaint tp = tv.getPaint();
tp.setFakeBoldText(true); 

取消加粗效果的話設(shè)置
TextPaint tp = tv.getPaint();
tp.setFakeBoldText(false);

  1. android:clipToPadding屬性的用法

在使用 ListView 或者 RecycleView、ScrollView 等滑動(dòng)控件時(shí)候有一個(gè)強(qiáng)大但隱秘的屬性蚯撩,在android 的布局 XML 文件中础倍,android:clipToPadding=“boolean”,該屬性值可設(shè)為 true 或者false胎挎。表示控件的繪制區(qū)域是否在 padding 里面沟启,true 的情況下如果你設(shè)置了 padding 那么繪制的區(qū)域就往里縮忆家,false 則表示滑動(dòng)時(shí)忽略 padding 的值。系統(tǒng)默認(rèn)是 true德迹。

屬性的作用就是當(dāng)你對 ListView 等滑動(dòng)控件設(shè)置了 padding 屬性后芽卿,四周會有縮進(jìn)的效果,正常會與屏幕四邊有空白間距胳搞,然后滑動(dòng)的時(shí)候此間距一直顯示卸例。如果設(shè)置 android:clipToPadding=“false” ,則在滑動(dòng)的時(shí)候間距自動(dòng)隨著滑動(dòng)布局上滑以致不會顯示空白間距,此時(shí)也就有了比較好的用戶體驗(yàn)肌毅。

效果就是下邊兩張圖所示:第一張為默認(rèn)情況筷转,即 android:clipToPadding =“true”,第二張為 false 時(shí)的結(jié)果。


true結(jié)果.png
false結(jié)果.png
  1. ColorStateList 可以設(shè)置文字顏色在不同狀態(tài)下切換的功能悬而,不需要手動(dòng)根據(jù)不同狀態(tài)設(shè)置不同的顏色值呜舒,使用方法如下:

首先,定義一個(gè) selector 的選擇器

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:color="@color/color_ffffff" android:state_enabled="true" android:state_selected="true" />
    <item android:color="@color/color_2f9cf6"/>
</selector>

在代碼中使用方法如下:

ColorStateList csl=(ColorStateList)getResources().getColorStateList(R.color.button_text);  
Button btn =  new Button(mContext);
btn.setTextColor(csl);

也可以直接在布局文件中設(shè)置 android:textColor = "@color/button_text" 來實(shí)現(xiàn)笨奠。

此外袭蝗,還有個(gè) StateListDrawable 與 ColorStateList 類似,只不過它是設(shè)置 drawable 類型的資源文件艰躺,并且設(shè)置的資源文件是放在 res/drawable/ 文件夾下呻袭,靜態(tài)使用方法如下:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true"
          android:drawable="@drawable/button_pressed" /> <!-- pressed -->
    <item android:state_focused="true"
          android:drawable="@drawable/button_focused" /> <!-- focused -->
    <item android:state_hovered="true"
          android:drawable="@drawable/button_focused" /> <!-- hovered -->
    <item android:drawable="@drawable/button_normal" /> <!-- default -->
</selector>
<Button
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:background="@drawable/button" />

也可以動(dòng)態(tài)代碼構(gòu)造一個(gè) StateListDrawable ,例如:

//初始化一個(gè)空對象
StateListDrawable stalistDrawable = new StateListDrawable();
//獲取對應(yīng)的屬性值 Android框架自帶的屬性 attr
int pressed = android.R.attr.state_pressed;
int window_focused = android.R.attr.state_window_focused;
int focused = android.R.attr.state_focused;
int selected = android.R.attr.state_selected;
stalistDrawable.addState(newint []{pressed , window_focused}, getResources().getDrawable(R.drawable.pic1));
//負(fù)值表示對應(yīng)的屬性是 false, 下邊的屬性即按下狀態(tài)但沒有獲取焦點(diǎn)的時(shí)候
stalistDrawable.addState(newint []{pressed , -focused}, getResources().getDrawable(R.drawable.pic2);
stalistDrawable.addState(newint []{selected }, getResources().getDrawable(R.drawable.pic3);
stalistDrawable.addState(newint []{focused }, getResources().getDrawable(R.drawable.pic4);
//沒有任何狀態(tài)時(shí)顯示的圖片腺兴,我們給它設(shè)置我空集合
stalistDrawable.addState(newint []{}, getResources().getDrawable(R.drawable.pic5);

動(dòng)態(tài)使用方法:

   StateListDrawable states = new StateListDrawable();
   states.addState(new int[] {-android.R.attr.state_pressed}, INTERSTITIAL_CLOSE_BUTTON_NORMAL.createDrawable( getContext()));
    states.addState(new int[] {android.R.attr.state_pressed}, INTERSTITIAL_CLOSE_BUTTON_PRESSED.createDrawable(
                getContext()));
    mImageView.setImageDrawable(states);
  1. 異常的處理和拋出:throw與throws以及捕捉異常try左电、catch、finally
    1页响、throws出現(xiàn)在方法函數(shù)頭篓足;而throw出現(xiàn)在函數(shù)體。
    2闰蚕、throws表示出現(xiàn)異常的一種可能性栈拖,并不一定會發(fā)生這些異常;throw則是拋出了異常没陡,執(zhí)行throw則一定拋出了某種異常對象涩哟。
    3、兩者都是消極處理異常的方式(這里的消極并不是說這種方式不好)盼玄,只是拋出或者可能拋出異常贴彼,但是不會由函數(shù)去處理異常,真正的處理異常由函數(shù)的上層調(diào)用處理埃儿。
    4器仗、throws說明你有那個(gè)可能,傾向。throw的話精钮,那就是你把那個(gè)傾向變成真實(shí)的了威鹿。
    5、舉例:throws E1,E2,E3只是告訴程序這個(gè)方法可能會拋出這些異常轨香,方法的調(diào)用者可能要處理這些異常忽你,而這些異常E1,E2弹沽,E3可能是該函數(shù)體產(chǎn)生的檀夹。
    throw則是明確了這個(gè)地方要拋出這個(gè)異常。
    舉個(gè)例子:
void function_throws(int a,int b) throws Exception1,Exception3{
           try{
                 ......
           }catch(Exception1 e){
              throw e;
           }catch(Exception2 e){
              System.out.println("出錯(cuò)了策橘!");
           }
           if(a!=b)
              throw new  Exception3("自定義異常");
}

代碼塊中可能會產(chǎn)生3個(gè)異常炸渡,(Exception1,Exception2,Exception3)。
如果產(chǎn)生 Exception1 異常丽已,則捕獲之后再拋出蚌堵,由該方法的調(diào)用者去處理。
如果產(chǎn)生 Exception2 異常沛婴,則該方法自己處理了(即System.out.println("出錯(cuò)了吼畏!");)。所以該方法就不會再向外拋出 Exception2 異常了嘁灯,即 throws Exception1,Exception3 里面不用寫 Exception2 異常泻蚊。

拋出異常后的語句都不會執(zhí)行,try catch finally 里 finally 不管怎樣都會執(zhí)行丑婿。

  1. 申請權(quán)限時(shí)性雄,在 Fragment 中申請權(quán)限,不要使用這種方式
ActivityCompat.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);

直接使用 Fragment 的 requestPermissions 方法羹奉,即

requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);

否則會回調(diào)到 Activity 的 onRequestPermissionsResult ,使用第二種方法會直接在 Fragment 里回調(diào)秒旋。

如果在 Fragment 中嵌套 Fragment,在子 Fragment 中使用 requestPermissions 方法诀拭,onRequestPermissionsResult 不會回調(diào)回來迁筛,建議在子 Fragment 中使用 getParentFragment().requestPermissions 方法,
這個(gè)方法會回調(diào)到父 Fragment 中的 onRequestPermissionsResult()耕挨,加入以下代碼可以把回調(diào)透傳到子 Fragment细卧。

 @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        List<Fragment> fragments = getChildFragmentManager().getFragments();
        if (fragments != null) {
            for (Fragment fragment : fragments) {
                if (fragment != null) {
                    fragment.onRequestPermissionsResult(requestCode,permissions,grantResults);
                }
            }
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市筒占,隨后出現(xiàn)的幾起案子酒甸,更是在濱河造成了極大的恐慌,老刑警劉巖赋铝,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異沽瘦,居然都是意外死亡革骨,警方通過查閱死者的電腦和手機(jī)农尖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來良哲,“玉大人盛卡,你說我怎么就攤上這事≈欤” “怎么了滑沧?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長巍实。 經(jīng)常有香客問我滓技,道長,這世上最難降的妖魔是什么棚潦? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任令漂,我火速辦了婚禮,結(jié)果婚禮上丸边,老公的妹妹穿的比我還像新娘叠必。我一直安慰自己,他們只是感情好妹窖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布纬朝。 她就那樣靜靜地躺著,像睡著了一般骄呼。 火紅的嫁衣襯著肌膚如雪共苛。 梳的紋絲不亂的頭發(fā)上耘戚,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天鹿鳖,我揣著相機(jī)與錄音,去河邊找鬼邑商。 笑死绕德,一個(gè)胖子當(dāng)著我的面吹牛患膛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播耻蛇,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼踪蹬,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了臣咖?” 一聲冷哼從身側(cè)響起跃捣,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎夺蛇,沒想到半個(gè)月后疚漆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年娶聘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了闻镶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡丸升,死狀恐怖铆农,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情狡耻,我是刑警寧澤墩剖,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站夷狰,受9級特大地震影響岭皂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜孵淘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一蒲障、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瘫证,春花似錦揉阎、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至毡庆,卻和暖如春坑赡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背么抗。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工毅否, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蝇刀。 一個(gè)月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓螟加,卻偏偏與公主長得像,于是被迫代替她去往敵國和親吞琐。 傳聞我的和親對象是個(gè)殘疾皇子捆探,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評論 2 355

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