最近參考 今日頭條算法 ,優(yōu)化了項(xiàng)目的屏幕適配策略。下面是適配過(guò)程中的一些心得,部分內(nèi)容來(lái)源于網(wǎng)絡(luò)。
為江源等地區(qū)用戶提供了全套網(wǎng)頁(yè)設(shè)計(jì)制作服務(wù),及江源網(wǎng)站建設(shè)行業(yè)解決方案。主營(yíng)業(yè)務(wù)為成都做網(wǎng)站、網(wǎng)站設(shè)計(jì)、江源網(wǎng)站設(shè)計(jì),以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。我們深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!
舉個(gè)例子:屏幕分辨率為:1920*1080,屏幕尺寸為5吋的話,那么dpi為440。
dp就是密度自適應(yīng)的像素。1dp表示 在dpi為160的設(shè)備上的一顆像素
px與dp的換算公式px = dp * (dpi / 160),很顯然,由于相同分辨率但不同屏幕大小的設(shè)備dpi是不同的,導(dǎo)致px和dp的基本不存在一個(gè)固定的換算關(guān)系,為了方便屏幕適配,Android設(shè)置了6個(gè)通用的密度,換算px與dp時(shí)采取通用密度計(jì)算,而非設(shè)備實(shí)際的密度。
以下為6種通用密度,以及其最小的分辨率
得到上面通用密度之后,我們換算dp與px多了一種簡(jiǎn)便方式。Android系統(tǒng)用mdpi(160dpi)作為基準(zhǔn),此時(shí)1px = 1dp,又有px = dp * (dpi / 160),所以我們可以很容易的得到以下?lián)Q算:
sp在dp的基礎(chǔ)上引入了scaleFactor變量,一般用于字號(hào),可在系統(tǒng)設(shè)置里調(diào)大。
同一張圖片放到以上4個(gè)分辨率類型的文件夾里,在頁(yè)面上呈現(xiàn)的效果如下
實(shí)際呈現(xiàn)的算法為: 圖片尺寸 * 系統(tǒng)density / 文件夾 density
因?yàn)閳D片尺寸、系統(tǒng)density都是固定的,因此圖片最終尺寸表現(xiàn)為: 圖片放的位置越"low",呈現(xiàn)的尺寸越大
比如 圖片寬度200px,系統(tǒng) density =3,則圖片寬度
下面是詳細(xì)的解釋
我們知道,不管在布局文件中填寫(xiě)的是什么單位,它最后都會(huì)被系統(tǒng)轉(zhuǎn)化為 px。系統(tǒng)的轉(zhuǎn)換算法如下:
可以看到 px = dp*density 。
橫向適配的最終目的:讓100dp的寬度,在各個(gè)機(jī)型上,在屏幕上所占的 比例相同 。
其核心算法是px = dp* density。通過(guò)修改density這個(gè)變量,我們可以讓px和畫(huà)布標(biāo)注的px值一致,達(dá)到適配的效果。
美工同學(xué)提供的畫(huà)布寬度為 750px(iphone6) ,開(kāi)發(fā)中,我們對(duì)這些px標(biāo)注 除2 得到dp值進(jìn)行使用。
那么density如何求出呢? 根據(jù)系統(tǒng)算法px = dp*density,反推 density =px/dp
拿橫向適配畫(huà)布, density對(duì)于不同分辨率的手機(jī)修改后如下:
375是我們拿UI畫(huà)布橫向分辨率750/2得出。
一、activity
1.一個(gè)activity就是一個(gè)類,繼承activity;
2.需要復(fù)寫(xiě)onCreate()方法;
3.每一個(gè)activity都需要在AndroidMainfest.xml清單上進(jìn)行配置;
4.為activity添加必要的控件。
二、布局
線性布局:LinearLayout
1.填滿父空間:fill_parent、match_parent
2.文本多大空間就有多大:warp_content
3.文字對(duì)齊方式:gravity
4.占屏幕的比例:layout_weight="1" ?水平方向,則width=0,垂直方向,則height=0
5.一行顯示,空間不夠會(huì)省略:singleLine="ture"? false會(huì)換行
6.背景:background="#ffffff"
7.水平布局:orientation="horizontal"
垂直布局:orientation="vertivcal"
表格布局:TableLayout
1.內(nèi)邊距:padding
2.外邊距:marginLeft\Start、Right\End、Top、Bottom
三、RelativeLayout相對(duì)布局
layout_above 將該控件的底部置于給定ID控件之上
layout_below 將該控件的頂部置于給定ID控件之下
layout_toLeftOf 將該控件的右邊緣和給定ID控件的左邊緣對(duì)齊
layout_toRightOf 將該控件的左邊緣和給定ID控件的右邊緣對(duì)齊
layout_alignBaseline 該控件的baseline和給定ID的控件的Baseline對(duì)齊
layout_alignBottom 該控件的底部邊緣和給定ID的控件的底部邊緣對(duì)齊
layout_alignLeft 該控件的左邊緣和給定ID的控件的左邊緣對(duì)齊
layout_alignRight 該控件的右邊緣和給定ID的控件的右邊緣對(duì)齊
layout_alignTop 該控件的頂部邊緣和給定ID的控件的頂部邊緣對(duì)齊
layout_alignparentBottom 如果該值為true,則該控件的底部和父控件的底部對(duì)齊layout_alignParentLeft 如果該值為true,則該控件的左邊和父控件的左邊對(duì)齊
layout_alignParentRight 如果該值為true,則該控件的右邊和父控件的右邊對(duì)齊
layout_alignParentTop 如果該值為true,則該控件的上邊和父控件的上邊對(duì)齊
layout_centerHorizontal 如果該值為true,則該控件將被置于水平方向的中央
layout_centerInParent 如果該值為true,則該控件將被置于父控件水平和垂直方向的中央
layout_centerVertival 如果該值為true,則該控件將被置于垂直方向的中央
四、一個(gè)Intent對(duì)象包含一組信息
1.Component name
2.Action
3.Data
4.Category
5.Extras
6.Flags
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);? //startActivity方法
intent.putExtra("Key", "Value");? //鍵值對(duì)
intent = getIntent();
String value = intent.getStringExtra("Key");? ? //通過(guò)鍵提取數(shù)據(jù)
五、初級(jí)控件:EditText、TextView、Button
1.獲取EditText的值
String value = EditText.getText().toString();
2.將值放到Intent對(duì)象中
Intent intent = new Intent();
intent.putExtra("one",value )
intent.setCalss(Activity.this, OtherActivity.class);
3.使用這個(gè)Intent對(duì)象來(lái)啟動(dòng)Otheractivity
Activity.this.startActivity(intent);
4.將監(jiān)聽(tīng)器的對(duì)象綁定到按鈕對(duì)象上
button.setOnclickListener(new Listener());
5.得到Intent對(duì)象當(dāng)中的值
Intent intent = getIntent();
String value1 = intent.getStringExtra("one");
int value2 = Integer.parseInt(value);
六、其他初級(jí)控件使用
①I(mǎi)mageView
②RadioGroup和RadioButton
setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener())
③Checkbox
setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener())
④Menu
1.當(dāng)客戶點(diǎn)擊MENU按鈕的時(shí)候,調(diào)用onCreateOptionMenu()方法
public boolean onCreateOptionMenu(Menu menu){
menu.add(0,1,1,R.string.id);
}
2.當(dāng)客戶點(diǎn)擊MENU內(nèi)部的具體某一個(gè)選項(xiàng)時(shí),調(diào)用onOptionItemSelected()方法
public boolean onOptionItemSelected(MenuItem item){
if(item.getItemId() == 1){
finish();
}
return super.onOptionItemSelected(item);
}
七、Activity的生命周期
1.第一次創(chuàng)建時(shí)調(diào)用
protected void onCreat(Bundle saveInstanceState);
2.顯示出來(lái)時(shí)調(diào)用
protected void onStrat();
3.獲得用戶焦點(diǎn)時(shí)調(diào)用(可操作)
protected void onResume();
4.點(diǎn)擊彈出第二個(gè)Activity時(shí)調(diào)用
protected void onPause();
5.當(dāng)?shù)谝粋€(gè)Activity不可見(jiàn)時(shí)調(diào)用
protected void onStop();
6.當(dāng)返回第一個(gè)Activity時(shí)調(diào)用,代替OnCreate,因?yàn)闆](méi)被銷毀
protected void onRestart();
7.當(dāng)返回第一個(gè)Activity時(shí)調(diào)用(先執(zhí)行onStop,在執(zhí)行,因?yàn)榈诙€(gè)Activity被銷毀,不能返回獲取,只能通過(guò)onCreat,onStart,onResume再創(chuàng)建)
protected void onDestory();
八、Task
1.Task是存放Activity的Stack棧。當(dāng)點(diǎn)擊啟動(dòng)第二個(gè)Activiry時(shí),第一個(gè)Activtiy會(huì)被壓入Stack棧當(dāng)中,第二個(gè)Activity會(huì)位于棧的頂部;當(dāng)返回第一個(gè)Activtiy時(shí),第二個(gè)Activity會(huì)被彈出Stack,第一個(gè)Activity會(huì)位于棧的頂部,以此類推。
注釋:當(dāng)調(diào)用finish()時(shí),當(dāng)前的Activity會(huì)被Destory掉,棧中的Activity會(huì)消失。
2.當(dāng)Activity都從Stack退出后,則就不存在Task。
九、高級(jí)控件
①進(jìn)度條ProgressBar
水平進(jìn)度條style="?android:attr/progressBarStyleHorizontal"
圓圈進(jìn)度條style="?android:attr/progressBarStyle"
用戶可視的visibility="gone"
②列表ListView
十、其他控件
A.下拉菜單Spinner
1.創(chuàng)建一個(gè)ArrayAdapter:
ArrayAdapterCharSequence adapter = ArrayAdapter.createFromResource(
this, //指上下文對(duì)象
R.array.plant_array, //引用了在文件中定義的String數(shù)組
android.R.layout.simple_spinner_item);//用來(lái)指定Spinner的樣式,可替換自定義
adapter.setDropDownViewResource(
android.R.layout.simple_spinner_dropdown_item);//設(shè)置Spinner當(dāng)中每個(gè)條目的樣式
2.得到Spinner對(duì)象,并設(shè)置數(shù)據(jù):
spinner=(spinner)findViewById(R.id.spinnerId);
spinner.setAdapter(adapter);
spinner.setPrompt("測(cè)試");//標(biāo)題
3.創(chuàng)建監(jiān)聽(tīng)器
class SpinnerOnSelectListener implements OnItemSelectedListener{
@override
public void onItemSelected(
AdapterView? adapterView,//整個(gè)列表對(duì)象
View view,//被選中的具體條目對(duì)象
int position,//位置
long id){ //id
String selected = adapterView.getItemAtPosition(position).toString();
}
@override
public void onNothingSelected(AdapterView? adapterView){
S.o.p("nothingSelected");
}
}
4.綁定監(jiān)聽(tīng)器
spinner.setOnItemSelectedListener(new SpinnerOnSelectListener());
注:第二種動(dòng)態(tài)設(shè)計(jì)
1.創(chuàng)建ArrayList對(duì)象
ListString list = new ArrayListString();
list.add("test1");
2. 調(diào)用方法
ArrayAdapter adapter = new ArrayAdapter(
this, //指上下文對(duì)象
R.layout.item, //引用了指定了下拉菜單的自定義布局文件
R.id.textViewId,//id
list);//數(shù)據(jù)
3.得到Spinner對(duì)象,并設(shè)置對(duì)象
spinner.setAdapter(adapter);
spinner.setPrompt("測(cè)試");//標(biāo)題
3.創(chuàng)建監(jiān)聽(tīng)器
class SpinnerOnSelectListener implements OnItemSelectedListener{
@override
public void onItemSelected(
AdapterView? adapterView,//整個(gè)列表對(duì)象
View view,//被選中的具體條目對(duì)象
int position,//位置
long id){ //id
String selected = adapterView.getItemAtPosition(position).toString();
}
@override
public void onNothingSelected(AdapterView? adapterView){
S.o.p("nothingSelected");
}
}
4.綁定監(jiān)聽(tīng)器
spinner.setOnItemSelectedListener(new SpinnerOnSelectListener());
B.DatePicker和DatePickerDialog
1.聲明一個(gè)監(jiān)聽(tīng)器,使用匿名內(nèi)部類
DatePickerDialog.OnDateSetListener onDateSetListener
= new DatePivkerDialog.OnDateSetListener(){
public void onDateSet(
DatePicker view,
int year,
int monthOfYear,
int dayOfMonth){
S.o.p(year+"-"+motnOfYear+"-"+dayOfMonth)
}
}
2.復(fù)寫(xiě)onCreateDialog(int id)方法:
@override
protected Dialog onCreateDialog(int id){
switch(id){
case DATE_PICKER_ID:
return new DatePickerDialog(this,onDateSetListener,2019,11,25);
}
return null;
}
3.使用時(shí)調(diào)用showDialog()方法
showDialog(DATE_PICKER_ID);
C.AutoCompleteTextView
B.Widget
C.Animatin
十一、實(shí)現(xiàn)ContentProvider過(guò)程
1.定義一個(gè)CONTENT_URI常量
2.定義一個(gè)類,繼承ContentProvider
3.實(shí)現(xiàn)query、insert、update、delete、getType和onCreate方法
4.在AndroidManifest.xml當(dāng)中進(jìn)行聲明
Android開(kāi)發(fā)簡(jiǎn)單來(lái)說(shuō),就是在安卓系統(tǒng)的手機(jī)上制作APP,現(xiàn)在安卓手機(jī)市場(chǎng)份額大,對(duì)人才的需求也是很高的
Android開(kāi)發(fā),需要掌握以下知識(shí):
android以java為基礎(chǔ)的,所以前提要學(xué)好Java基礎(chǔ)知識(shí),比如基本類型、集合等。
android api,學(xué)習(xí)基本的Activity、service、intent等基本的知識(shí),可以開(kāi)發(fā)一些界面。
計(jì)算機(jī)網(wǎng)絡(luò)基本知識(shí)。
Linux命令、C編程基礎(chǔ)、Android Java編程、Google Android Linux操作系統(tǒng)具體操作等
課 工 場(chǎng)的Android開(kāi)發(fā)教學(xué)系統(tǒng)非常完備,如果有這方面的學(xué)習(xí)需求,可以點(diǎn) 擊 頭 像試聽(tīng)課程了解一下。
安卓開(kāi)發(fā)要學(xué)多久,安卓開(kāi)發(fā)如果自學(xué)的話,沒(méi)有系統(tǒng)性的學(xué)習(xí),而且缺乏項(xiàng)目經(jīng)驗(yàn)的實(shí)踐是難以真正掌握的。
培訓(xùn)機(jī)構(gòu)對(duì)于安卓開(kāi)發(fā)的培訓(xùn),一般有4個(gè)月到半年的不等。
安卓開(kāi)發(fā)要學(xué)多久,學(xué)習(xí)android又需要哪些技能基礎(chǔ)呢。
1、Java基礎(chǔ)知識(shí)很多朋友一上手就開(kāi)始學(xué)習(xí)Android,似乎太著急了一些。
Android應(yīng)用程序開(kāi)發(fā)是以Java語(yǔ)言為基礎(chǔ)的,所以沒(méi)有扎實(shí)的Java基礎(chǔ)知識(shí),只是機(jī)械的照抄別人的代碼,是沒(méi)有任何意義的。
萬(wàn)丈高樓平地而起,Java就是筑起高樓的每一塊磚頭。
那么Java學(xué)到什么程度才算是過(guò)關(guān)呢?我個(gè)人認(rèn)為至少要掌握以下兩個(gè)方面的內(nèi)容:a)Java基礎(chǔ)語(yǔ)法:具體的知識(shí)點(diǎn)列表可以在這里下載:《Java知識(shí)點(diǎn)列表》V1.0。
這部分內(nèi)容沒(méi)有討價(jià)還價(jià)的余地,必須爛熟于胸。
至于具體的學(xué)習(xí)方法,可以看書(shū)或者是看視頻,但是關(guān)鍵是要多加練習(xí),無(wú)論是書(shū)上的練習(xí)還是視頻里面的練習(xí),都需要仔仔細(xì)細(xì)的完成;b)設(shè)計(jì)模式:由于在Android系統(tǒng)的框架層當(dāng)中,使用了大量的設(shè)計(jì)模式,如果沒(méi)有這個(gè)方面的知識(shí),對(duì)于Android的理解就會(huì)大打折扣。
設(shè)計(jì)模式的種類非常之多,一個(gè)一個(gè)的全部掌握,是不現(xiàn)實(shí)的,必須首先掌握面向?qū)ο蟮幕A(chǔ)設(shè)計(jì)原則,有了這些基礎(chǔ)原則的支持,就可以舉一反三。
這部分內(nèi)容可以在《EffectiveJava》和《Agile.Software.Development:Principles,Patterns.and.Practices》這兩本書(shū)中找到。
2、Linux基礎(chǔ)知識(shí)大家都知道,Android系統(tǒng)的基礎(chǔ)是Linux操作系統(tǒng)。
在開(kāi)發(fā)過(guò)程當(dāng)中,我們也需要使用到一些Linux命令。
所以說(shuō)一些Linux的基礎(chǔ)知識(shí)是必須的(話說(shuō)現(xiàn)在的程序員,不懂Linux都不好意思跟人家打招呼),廣州北大青鳥(niǎo)推薦大家看看北大青鳥(niǎo)相當(dāng)不錯(cuò);3、數(shù)據(jù)庫(kù)基礎(chǔ)知識(shí)這個(gè)比較簡(jiǎn)單,就是一個(gè)增刪改查的數(shù)據(jù)庫(kù)操作,可以看一下這本書(shū):《SQL編程練習(xí)與解答》。
4、網(wǎng)絡(luò)協(xié)議至少需要學(xué)習(xí)兩種基礎(chǔ)的協(xié)議,HTTP協(xié)議與Socket協(xié)議;5、Android基礎(chǔ)知識(shí)此知識(shí)點(diǎn)的篇幅較大,在這里就不作更多解釋了。
android以java為基礎(chǔ)的,所以前提要學(xué)好Java基礎(chǔ)知識(shí),比如基本類型、集合等。
android api,學(xué)習(xí)基本的Activity、service、intent等基本的知識(shí),可以開(kāi)發(fā)一些界面。
計(jì)算機(jī)網(wǎng)絡(luò)基本知識(shí)。
Linux命令、C編程基礎(chǔ)、Android Java編程、Google Android Linux操作系統(tǒng)具體操作等
安卓系統(tǒng)開(kāi)發(fā)的方法,簡(jiǎn)單來(lái)說(shuō)分成四層:
第一層,以Inventor為代表的繪圖工具,是Google推出的簡(jiǎn)單開(kāi)發(fā)工具,主要是針對(duì)初級(jí)玩家的玩意兒,操作起來(lái)確實(shí)容易,一個(gè)不懂程序開(kāi)發(fā)的用戶就可以通過(guò)拖拽搞出一個(gè)能在安卓平臺(tái)上跑的應(yīng)用來(lái),有點(diǎn)像做PPT,但任何事情都有兩面性,這種容易上手的繪圖工具,無(wú)法實(shí)現(xiàn)業(yè)務(wù)邏輯,運(yùn)行效率也比較低。
第二層,以Rexsee為代表的無(wú)線中間件,這種方法就不是玩家用的了,必須是工程師來(lái)用,但對(duì)技術(shù)門(mén)檻的要求很低,會(huì)用HTML和JS的技術(shù)員就可以方便的使用,在技術(shù)要求大幅度降低的同時(shí),基礎(chǔ)功能的封裝也是一大亮點(diǎn),這些中間件已經(jīng)把所有應(yīng)用需要的基礎(chǔ)功能封裝好,程序員直接使用JS去調(diào)用就可以了,不再需要吭哧吭哧從零開(kāi)始寫(xiě)代碼,比如你想調(diào)用個(gè)GPS,本來(lái)要編幾千行的代碼,用中間件只需一行JS代碼即可搞定,難怪說(shuō)做中間件的廠商都說(shuō):“用了我的東西,你的程序已經(jīng)做了一大半啦!”此言不虛。
第三層,基于JAVA的JDK JDK(Java Development Kit),目前絕大部分應(yīng)用都是用這種方式來(lái)開(kāi)發(fā),對(duì)程序員的要求比較高,首先要有比較好的JAVA底子,然后要對(duì)Android平臺(tái)本身有很深的研究,門(mén)檻不算低。