dpi源碼
A. dp的定義原理和dpi,ppi,px,pt,sp之間的區別
dp = dip : device independent pixels(設備獨立像素). 不同設備有不同的顯示效果,這個和設備硬體有關,一般我們為了支持WVGA、HVGA和QVGA 推薦使用這個,不依賴像素。
px: pixels(像素). 不同設備顯示效果相同,一般我們HVGA代表320x480像素,這個用的比較多。
pt: point,是一個標準的長度單位,1pt=1/72英寸,用於印刷業,非常簡單易用;
sp: scaled pixels(放大像素). 主要用於字體顯示best for textsize。
由此,根據 google 的建議,TextView 的字型大小最好使用 sp 做單位,而且查看
TextView
的源碼可知 Android 默認使用 sp 作為字型大小單位。
在 Android 中, 1pt 大概等於 2.22sp
以上供參考,如果 UI 能夠以 sp 為單位提供設計是最好的,如果設計中沒有 sp
的概念,則開發人員也可以通過適當的換算取近似值。
過去,程序員通常以像素為單位設計計算機用戶界面。例如,定義一個寬度為300像素的表單欄位,列之間的間距為5個像素,圖標大小為16×16像素 等。這樣拿讓如處理的問題在於,如果在一個每英寸點數(dpi)更高的新顯示器上運行該程序,則用戶界面會顯得很小。在有些情況下,用戶滑雹界面可能會小到難以看清 內容。
與解析度無關的度量單位可消啟以解決這一問題。Android支持下列所有單位。
px(像素):屏幕上的點。
in(英寸):長度單位。
mm(毫米):長度單位。
pt(磅):1/72英寸。
dp(與密度無關的像素):一種基於屏幕密度的抽象單位。在每英寸160點的顯示器上,1dp = 1px。
dip:與dp相同,多用於android/ophone示例中。
sp(與刻度無關的像素):與dp類似,但是可以根據用戶的字體大小首選項進行縮放。
為了使用戶界面能夠在現在和將來的顯示器類型上正常顯示,建議大家始終使用sp作為文字大小的單位,將dip作為其他元素的單位。當然,也可以考慮使用矢量圖形,而不是用點陣圖
B. my-ui中的地圖怎麼使用
大家下載MYUI倉庫後,切換到 Branch_csdn_study 分支,用 VS2019 打開 MYUI.sln 文件,按 F5 即可運行 myui 的 demo。
如果想使用 myui ,你可以把 myui 項目編譯成 lib 或 dll ,然後再自己的項目中引用 myui.h 頭文件即可。當然你也可以將 myui 集成到你的項目中,只需要將代碼拷貝一下即可,MYUI 以簡單方便為主,不會讓開發者進行復雜的操作的。
MYUI窗口創建流程:
在講解 demo 之前,我先告訴大家MYUI窗口創建的基本流程,以便大家更好地理解 demo 中的代碼:
第一步:在需要使用UI的線程中(一般就是主線程,也就是WinMain 函數)對MYUI進行初始化
第二步:創建一個繼承 CWindowUI 的類,並實現 OnNotify 和 OnEvent 兩個回調函數
第三步:在OnEvent 的 EnumEvent::WindowInit 事件通知裡面,利用 CBuilder 類和 xml 文件創建UI界面。然後再利用 CWindowUI::AttachFrameView 函數,把UI界面附加到窗口之上。
第四步:在 OnNotify 回調中實現你對控制項通知的處理,比如按鈕點擊事件的處理。
第五步:既然窗口類已經實現了,那麼你就可以在 WinMain 中創建一個窗口對象,並用 ShowModal 函數把窗口展示出來。
demo 講解:
哈哈,看上去挺簡單把,那麼接來下讓我們來看看 demo 的相關源碼:
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR szCmdLine, int iCmdShow)
{
TCHAR strFloder[MAX_PATH];
GetCurrentDirectory(MAX_PATH, strFloder);
//_Mole.Init( 0, hInstance);
ARGBREF refColor = RGB(1, 2, 3);
ARGBREF refColor2 = ARGB(5, 1, 2, 3);
MYUI::CUIThread::Init(hInstance);
CSysFunction::SetThreadDpiAwarenessContext(CSysFunction::UIDPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
CFrameWindow * window = new CFrameWindow();
RECT rect;
rect.left = 0;
rect.top = 0;
rect.right = 800;
rect.bottom = 640;
window->CreateEx(hInstance,NULL, WS_EX_LAYERED * 0 , WS_VISIBLE | WS_OVERLAPPEDWINDOW,
//WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_SYSMENU,
TEXT("HelloWin"), TEXT("HelloWin"), &rect);
window->SetIcon(IDI_ICON1);
window->CenterWindow();
window->ShowModal();
delete window;
MYUI::CUIThread::Uninit();
//_Mole.Term();
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
先解釋一下 MYUI::CUIThread::Init() ,這個是用來初始化UI庫的。MYUI 只支持單線程使用,要知道單線程UI才是最規范的操作,那如果其他線程想彈出一個對話框怎麼辦?你可以SendMessage 或 PostMessage 到主線程的窗口進行彈出,特別說明一下 SendMessage 函數保證了多線程安全的。其實MYUI 也提供了 CUIThread::WorkerActive 和 CUIThread::WorkerExecute 兩個函數來支持線程操作。這兩個函數的作用很大,我們後面的文章會介紹,有興趣的同學可以自己看看實現源碼。
MYUI::CUIThread::Init() 函數要求在使用MYUI的線程上調用(一般主線程就是UI線程),當不再需要MYUI 後,要記得調用 MYUI::CUIThread::Uninit() 函數。
demo 中還調用了 CSysFunction::SetThreadDpiAwarenessContext 函數,CSysFunction 類是為了實現不同系統和編譯器中的函數兼容而封裝的。而 SetThreadDpiAwarenessContext 加上 demo 中的參數,意思是啟用當前線程對DPI的響應。
由於MYUI內部實現了DPI自適應機制,控制項和文本都會自動放大縮小。如果你還想在不同的 DPI 下,提供對應大小的高清倍圖。比如在200%DPI 下提供二倍圖,那麼你可以在 CWindowUI::OnEvent 回調中,監聽 DpiChange 事件。當匹配到 200%DPI 時,調用 SetSkin 函數,設置新的皮膚路徑(這個路徑下的文件,當然就是二倍圖了,注意文件名的統一)。
當UI庫初始化完成,也啟用了DPI響應,我們 new 了一個 CFrameWindow 對象,不用說,這個就是我們的窗口對象了。而 WinMain 函數中對 CFrameWindow 對象的調用過程在干嗎,相信不用我解釋,大家都知道它在干什麼了。那麼我們直接進入 CFrameWindow 內部代碼的講解。看看 CFrameWindow.h 頭文件的部分定義:
class CBuilderControl : public IBuilderCallback
{
public:
virtual CControlUI * CreateControl(LPCTSTR strClass);
};
class CFrameWindow : public CWindowUI , public IControlHooker
{
public:
CFrameWindow();
~CFrameWindow();
void OnNotify(MUINOTIFY¬ify);
LRESULT OnEvent(MUIEVENT &event);
public:
virtual bool OnBefore(CControlUI* pControl, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT &lResule);
virtual bool OnAfter(CControlUI* pControl, HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam, LRESULT &lResule);
protected:
virtual LRESULT CALLBACK WndProc(UINT message, WPARAM wParam, LPARAM lParam);
LRESULT OnCreate2(WPARAM wParam, LPARAM lParam);
LRESULT OnCreate(WPARAM wParam, LPARAM lParam);
LRESULT OnReady(WPARAM wParam, LPARAM lParam);
LRESULT OnTimer(WPARAM wParam, LPARAM lParam);
private:
CMenuUI * m_pMenUI;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
先說一下 CFrameWindow ,前面已經說過,想實現MYUI窗口對象,只需要繼承 CWindowUI 這個類,並且實現 OnNotify 和 OnEvent 這兩個虛函數即可,是不是很簡單。
OnNotify 是控制項通知回調,當控制項產生點擊之類的事件,便會發出通知。而 OnEvent 是窗口事件通知。關於兩個回調會通知哪些事件,這里貼一下代碼
enum EnumNotify
{
//處理消息後,如果返回false,表明不需要調用OnNotify
NonMessage = 0,
ClickItem,//控制項單擊消息
DbClickItem,//控制項雙擊消息
SelectChange,//滾動條
CheckItem, //用法跟SelectItem一樣,主要是STATE_CHECK狀態會配合特殊標志,如:STATE_UNKNOW
//存在多項的控制項,選擇(左擊或右擊)了某一項,wParam是控制項的狀態,
//通過判斷wParam,來判斷選中還是取消選中
SelectItem,
ActiveItem,//存在多項的控制項,左雙擊了某一項
TextChange,//文本發生了改變,一般關聯編輯框
SetFocus,//控制項獲得焦點
KillFocus,//控制項失去焦點
TimerCall,//消息通知
ShowTip,//請求展示tip
};
enum EnumEvent
{
WindowInit = 0,//WM_NCCREATE
RequestRenderEngine,//WM_CREATE
WindowReady,//WM_CREATE
WindowDestroy,//WM_NCDESTROY
WindowShow,//WM_SHOWWINDOW
OnFinal,//最後一條消息,一般在裡面執行delete this
DpiChange,
SetFocued,//WM_SETFOCUS
KillFocued,//WM_KILLFOCUS
OnTimer ,//WM_TIMER
DragOver,//一般是拖動結束時,觸發的消息
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
初次使用某些控制項,大家可以不知道會觸發哪些事件,到時候跟蹤一下代碼,或者在 OnNotify 和 OnEvent 打個斷點,很容易就能夠測試出來。
再說 OnEvent 回調中的 EnumEvent::WindowInit 事件,其實對應的是 WM_CREATE 消息通知,這個事件中 demo 調用了 OnCreate 函數,讓我們看看這個函數在干嗎:
LRESULT CFrameWindow::OnCreate(WPARAM wParam, LPARAM lParam)
{
TCHAR strSkin[MAX_PATH] = {0};
#if 0
wsprintf(strSkin, _T("file='%s'"), _T("skin/"));
#else
wsprintf(strSkin, _T("file='%s'"), _T("../Debug/skin/"));
#endif
SetSkin(strSkin);
//SetSkin(_T("skin\\"));
CControlUI * pRootLayout = nullptr;
CBuilderControl * pCallback = new CBuilderControl();
CBuilder * pBuilder = new CBuilder(this, pCallback);
pRootLayout = pBuilder->Create(strSkin, _T("frame.xml"));
delete pBuilder;
delete pCallback;
this->AttachFrameView(pRootLayout);
m_pMenUI = new CMenuUI();
m_pMenUI->Create(m_hInstance, _T("MYMENU"), strSkin, _T("menu.xml"));
CControlUI * pControl = pRootLayout->FindControlByName(_T("btnMenu"));
if (pControl)
{
pControl->SetMenu(m_pMenUI);
}
CControlUI* pEdit = FindControl(_T("edtMessage"));
if (pEdit)
{
//pEdit->SetText(_T("床前\t明月光\n疑是\t\t地上霜\n舉頭\t\t\t望明月\r\n低頭\t\t\t\t思故鄉"));
pEdit->SetText(_T("床前\n明月光\r\n疑是\n\n地上霜\n舉頭\n望\n明月"));
//pEdit->SetText(_T("床前\t明月光\r\n疑是\t\t地上霜\n"));
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
總的來說,OnCreate 中,首先調用了 SetSkin 設置皮膚路徑,然後通過 CBuilder 類,利用 frame.xml 文件來創建了控制項。這里有兩點需要跟大家介紹一下。
一,CBuilder 默認只能夠創建MYUI已經提供的控制項,如果 xml 中包含了自定義控制項,那麼 CBuilder 會尋求 IBuilderCallback 介面的幫助(這里我們的 CBuilderControl 類繼承了 IBuilderCallback 介面),當 IBuilderCallback 介面不為空,則調用裡面 CreateControl 函數,讓 CreateControl 函數來幫我們實現自定義控制項的創建,很明顯,這個 CreateControl 的實現需要開發者提供。
二,一個窗口只能包含一個主控制項。所謂主控制項你可以理解為樹根,而子控制項為樹枝樹葉。窗口對控制項的管理,大部分都是通過這種樹結構,從樹根往樹葉方向執行的。如果你熟悉窗口原理,就會知道WIN32中窗口和控制項其實是同一種東西。但在MYUI中,窗口和控制項的概念是完全分離的,它們是兩個概念的東西。如果你想把主控制項附加到窗口之上,必須像 demo 一樣調用 AttachFrameView 函數。
此外 OnCreate 函數中還創建了一個特殊的控制項 —— 菜單。菜單特殊是因為它的本質是彈出一個窗口,所以它的創建動作跟 WinMain 中創建窗口的動作有點相似。至於菜單的大致使用方法,大家可以先參考 demo ,更詳細的我們在後面的文章再介紹。
OnCreate 函數介紹完了,有些同學可能會好奇 OnReady 函數和它對應的 EnumEvent::WindowReady 消息是幹嘛的。EnumEvent::WindowReady 其實是在 WM_CREATE 消息中通過 PostMessage 發出的。為什麼要這樣做呢?因為開發者在 WM_CREATE 創建控制項後,由於 WM_SIZE 消息還沒到達,這個時候控制項的一些屬性的值是還沒完全確定下來的。PostMessage - EnumEvent::WindowReady 消息就是為了在控制項屬性完全確定下來後,再發一條消息給用戶,讓用戶自己判斷是否需要修改某些東西。
上面的說法,貌似在告訴開發者,EnumEvent::WindowInit 消息是用來創建對象的,而 EnumEvent::WindowReady 消息時用來設置對象屬性的。嗯,這樣做確實比較規范,但如果不是特別的需要,其實你在 EnumEvent::WindowReady 不用處理任何東西。
當窗口和控制項都初始化完畢後,界面正式呈現在用戶眼前,如果對控制項進行操作,將會再 OnNotify 回調中產生對應的事件,開發者也可以在裡面寫入業務處理邏輯。
好了,關於demo 的代碼就介紹到這里了,其實它並不難,大家多看幾遍就會明白。然後我們再說說用來創建UI的 xml 文件。在 CFrameWindow::OnCreate 中,我們知道UI界面主要是通過 frame.xml 的描述來創建的。常規的 xml 文件格式如下:
<myui>
<全局聲明 1/> <!--窗口用到的一些屬性定義-->
<全局聲明 2/>
<全局聲明 3/>
<window> <!--所有窗口屬性 -->
<Control/> <!--所有子控制項 -->
</window>
</myui>
1
2
3
4
5
6
7
8
1
2
3
4
5
6
7
8
其中myui這個標簽是必須的,只有檢測到這個標簽,MYUI界面庫才會往下解析其他語句。至於其他屬性,大家可以對 demo 調試來知道它的作用,也可以查看 Attribute.xml 文檔說明。
資源打包:
好了,我們已經知道一個最基礎的MYUI窗口已經創建出來,但實際的項目中,資源往往需要打包到 exe 中,那我們再來介紹一下 MYUI 的資源打包方法。
C. android app界面設計規范(dpi,dp,px等)
PPI(Pixels per inch):每英寸所擁有的像素數,即像素密度。
DPI(dots per inch):即每英寸上,所能印刷的網點數,一般稱為像素密度。ppi計算公式:ppi = 屏幕對角線像素數/屏幕對角線英寸數,通過勾股定理計算屏幕對角線像素數。
Screen Size(屏幕尺寸):手機屏幕尺寸大小,如3英寸、4英寸、4.3英寸、5.7英寸,指的是對角線的長度。
DIP(device independent pixel):即dip/dp,設備獨立像素。 1px = 1dp density(由dpi決定)
Resolution(解析度):指手機屏幕垂直和水平方向上的像素個數。eg解析度480 800,指該設備垂直方向有800個像素點,水平方向有480個像素點。
px(Pixel像素):相同像素的ui,在不同解析度的設備上效果不同。在小解析度設備上會放大導致失真,大解析度上被縮小。
Android Design里把主流設備的 dpi 歸成了四個檔次: 120 dpi、160 dpi、240 dpi、320 dpi ,具體見如下表格。
實際開發當中,我們經常需要對這幾個尺寸進行相互轉換(比如先在某個解析度下完成設計,然後縮放到其他尺寸微調後輸出),一般按照 dpi 之間的比例即 2:1.5:1:0.75 來給界面中的元素來進行尺寸定義。
也就是說如果以 160 dpi 作為基準的話,只要尺寸的 DP 是 4 的公倍數,XHDPI 下乘以 2,HDPI 下乘以 1.5,LDPI 下乘以 0.75 即可滿足所有尺寸下都是整數 pixel 。但假設以 240 dpi 作為標准,那需要 DP 是 3 的公倍數,XHDPI 下乘以 1.333,MDPI 下乘以 0.666 ,LDPI 下除以 2。而以 LDPI 和 XHDPI 為基準就更復雜了。同時第一款Android設備(HTC的T-Mobile G1)是屬於160dpi的。鑒於以上各種原因, 標准dpi=160
谷歌官方對dp的解釋如下:
A virtual pixel unit that you should use when defining UI layout, to express layout dimensions or position in a density-independent way.
The density-independent pixel is equivalent to one physical pixel on a 160 dpi screen, which is the baseline density assumed by the system for a "medium" density screen. At runtime, the system transparently handles any scaling of the dp units, as necessary, based on the actual density of the screen in use. The conversion of dp units to screen pixels is simple: px = dp * (dpi / 160). For example, on a 240 dpi screen, 1 dp equals 1.5 physical pixels. You should always use dp units when defining your application's UI, to ensure proper display of your UI on screens with different densities.
簡單來說,以160dpi的設備為准,該設備上1dp = 1px;如果屏幕密度大,1dip代表的px就多,比如在320dpi的屏幕上,1dip=2px(即1dp代表2個像素)。在app開發時,最好用dp來做界面的布局,以保證適配不同屏幕密度的手機。
dp和px的換算公式:
我的理解,該公式表示px的數值等於dp的數值*(設備dpi/160)
注意,px、dp是單位,但density沒單位。
applyDimension的源碼如下,可參考:
android的尺寸眾多,建議使用解析度為 720x1280 的尺寸設計。這個尺寸 720x1280中顯示完美,在 1080x1920 中看起來也比較清晰;切圖後的圖片文件大小也適中,應用的內存消耗也不會過高。
app啟動圖標為48*48dp,對應各dpi設備,圖像資源像素如下:
| mdpi | hdpi | xhdpi | xxhdpi |
| ---:| ---: | ---:| ---:| ---:|
|48 48px|72 72px|94 96px|144px 144px|
操作欄圖標為32*32dp,對應各dpi設備,圖像資源像素如下:其中圖形區域尺寸是24*24dp,可參考平時ui切圖會有部分留白。
| mdpi | hdpi | xhdpi | xxhdpi |
| ---:| ---: | ---:| ---:| ---:|
|32 32px|48 48px|64 64px|96px 96px|
通知欄圖標為24*24dp,對應各dpi設備,圖標像素如下:
| mdpi | hdpi | xhdpi | xxhdpi |
| ---:| ---: | ---:| ---:| ---:|
|24 24px|36 36px|48 48px|72px 72px|
某些場景需要用到小圖標,大小應當是16*16dp,其中圖形區域尺寸12*12dp。
| mdpi | hdpi | xhdpi | xxhdpi |
| ---:| ---: | ---:| ---:| ---:|
|16 16px|24 24px|32 32px|48px 48px|
D. 新手Android中px=dp*(dpi/160)的解釋
在160dpi的手機上1px=1dp,這句話的以上是說,手機屏幕寬頻被分割成了160塊,每一塊有一個像素點,每一塊就是一個dp。 那麼1dp=1px
而320dpi的手機上,解析度是上一個手機的兩倍,手機屏幕寬頻也被分割成了160塊,每一塊有兩個像素點,每一塊也是一個dp,那麼1dp=2px
上面分析來自於android學習手冊,360手機助手中可以下載,裡面有108個android例子,源碼文檔都可在裡面看,下面是截圖
java">importandroid.content.Context;
publicclassDensityUtil{
/**
*根據手機的解析度從dp的單位轉成為px(像素)
*/
publicstaticintdip2px(Contextcontext,floatdpValue){
finalfloatscale=context.getResources().getDisplayMetrics().density;
return(int)(dpValue*scale+0.5f);
}
/**
*根據手機的解析度從px(像素)的單位轉成為dp
*/
publicstaticintpx2dip(Contextcontext,floatpxValue){
finalfloatscale=context.getResources().getDisplayMetrics().density;
return(int)(pxValue/scale+0.5f);
}
}
E. Android 關於"尺寸"的那些事(dp,dip,sp,pt,px...)
屏幕大小:屏幕大小是手機對角線的物理尺寸,以英寸inch為單位。比如我的Mix 2手機屏幕大小為5.99 inches,意味著我的屏幕對角線長度為5.99inches = 5.99 * 2.54 = 15.2146cm
解析度:屏幕的像素點數,一般表示為a*b。例如某手機解析度為21601080,意味著手機屏幕的豎直方向(長)有2160個像素點,水平方向(寬)有1080個像素點。
px :Pixels ,像素;對應屏幕上的實際像素,是畫面中最小的點(單位色塊),像素大小沒有固定長度值,不同設備上1個單位像素色塊大小不同。
這么說可能有點陌生,用屏幕解析度來說,今年流行起來的「全面屏」解析度是 2160*1080,但是你也可以發現,雖然很多全面屏手機解析度一樣,但是明顯看得出來屏幕大小不一樣,這也解釋了「不同設備像素色塊大小是不同的」。
pt :1pt=1/72 inch,用於印刷業,非常簡單易用;
dpi :Dots Per Inch,每英寸點數;詳見ppi
ppi :Pixels Per Inch,每英寸像素數;數值越大顯示越細膩。計算式:ppi = 屏幕對角線像素數 / 屏幕對角線長度。
還是舉全面屏的例子,解析度2160*1080,屏幕大小是5.9inches,勾股定理可以得到對角線像素數大約是2415,那麼ppi = 2415 / 5.99 = 403.
事實上dpi 和 ppi 一定程度上可以劃等號,都表示像素密度,計算方式完全一致,只不過使用場景不一樣。dpi中的dots點屬於列印或印刷等領域,例如drawable 文件對應的就是dpi,而ppi中的pixel屬於屏幕顯示等領域
dp/dip : Density-independent Pixels,密度無關像素 - 基於屏幕物理密度的抽象單位。1dp等於 160 dpi 屏幕上的dpx,這是 系統為「中」密度屏幕假設的基線密度。在運行時,系統 根據使用中屏幕的實際密度按需要以透明方式處理 dp 單位的任何縮放 。dp 單位轉換為屏幕像素很簡單:px = dp * (dpi / 160)。 例如,在 240 dpi 屏幕上,1 dp 等於 1.5 物理像素。在定義應用的 UI 時應始終使用 dp 單位 ,以確保在不同密度的屏幕上正常顯示 UI。
如果看完文章還是覺得很懵,那麼可以直接記住: 1dp單位在設備屏幕上總是等於1/160 inch。
sp :Scale-independent Pixels ,與 dp 單位相似,也會根據用戶的字體大小偏好進行縮放。
首先我們放上源碼中對尺寸單位的轉換
可以看到,輸入值類型為dp時,返回 value * DisplayMetrics.density,到這里我們可能會發懵:嗯?不對啊,前面我們不是通過px 和 dp 的換算公式來計算的么,怎麼這里就簡簡單單乘了一個DisplayMetrics.density?不要慌,我們先看看源碼中對DisplayMetrics.density的介紹。
源碼注釋中說到「在160dpi的屏幕下,density的值為1,而在120dpi的屏幕下,density的值為0.75」,我們可以大膽的猜測一下,120dpi下的density=0.75的原因是120dpi * 1 /160dpi=0.75。實際上,也就是這么回事。我們下面會仔細的分析。
需要補充一下,通常意義上Android 屏幕的密度,指的是像素密度dpi/ppi,對應於源碼中的DisplayMetrics.densityDpi。
為什麼引入dp?
Android 引入了dp這一單位,使得不論多大屏幕,多大dpi,顯示的效果始終保持一致。
但是根據前面我們提到的px與dp的換算公式px = dp * (dpi / 160),很顯然,由於相同解析度但不同屏幕大小的設備dpi是不同的,導致px和dp的基本不存在一個固定的換算關系,為了方便屏幕適配,Android設置了6個通用的密度,換算px與dp時採取通用密度計算,而非設備實際的密度。
以下為6種通用密度,以及其最小的解析度
得到上面通用密度之後,我們換算dp與px多了一種簡便方式。前面我們提到Android將mdpi作為基準,此時1px = 1dp,又有px = dp * (dpi / 160),所以我們可以很容易的得到以下換算:
還記不記得前面源碼中的density屬性,實際上DisplayMetrics.density = dpi / 160 ,表示的就是在某個通用密度下dp與px的換算比(1dp/1px的值)
這部分其實和程序員自身已經關系不大了,畢竟參與工作之後這些都是UI人員的活兒了。不過鑒於現在我還只是一枚在校生,還是記下來以免自己遺漏吧。
建議在xhdpi中作圖
原因嘛,首先現在主流解析度是1080p,以及最近流行起來的全面屏18:9,而xhdpi對應720p,向低dpi兼容自然沒問題,即便在xxhdpi中顯示,也會有個不錯的效果。而如果以1920*1080作圖,顯然圖片素材佔用的內存很大,而且也會增大應用安裝包的大小。
只有一個原則:資源放入對應dpi的文件夾中,Android會機智的載入合適的資源。
以drawable資源為例:
我們平時開發小項目&對UI要求不高時,只使用一套xhdpi的資源就足夠了,雖然這可能會導致在hdpi及以下的手機中有些卡頓,因為xhdpi的圖片運行在hdpi及以下的手機上會比較吃內存,不過無傷大雅。
而如果不為圖片資源犯愁時(有UI人員的支持,就是任性),就可以添加所有dpi的資源。當然,重點還是要滿足ldpi:mdpi:hdpi:xhdpi:xxhdpi=3:4:6:8:12的規律。
好像說了不少廢話,哈哈,大概就這么多吧。
F. 隨機顯示一組圖片的ASP源碼
asp隨機顯示圖象<%dim p,ppic,dpic
ppic=12
randomize
p=Int((ppic*rnd)+1)
dpic="graphix/randompics/"&p&".gif"
%>
顯示 < img src="<%=dpic%>" >
G. Java源碼做的網站,如何做到自適應屏幕
1. 使用HTML中的viewport來實現
viewport語法如下:
HTML代碼
<!--在html代碼的<head>...</head>中嵌入下面代碼-->
<meta name="viewport"
content="
height = [pixel_value | device-height] ,
width = [pixel_value | device-width ] ,
initial-scale = 0.5 ,
minimum-scale = float_value ,
maximum-scale = float_value ,
user-scalable = [yes | no] ,
"
/>
[HTML] view plain
<!--在html代碼的<head>...</head>中嵌入下面代碼-->
<meta name="viewport"
content="
height = [pixel_value | device-height] ,
width = [pixel_value | device-width ] ,
initial-scale = 0.5 ,
minimum-scale = float_value ,
maximum-scale = float_value ,
user-scalable = [yes | no] ,
"
/>
width
控制 viewport 的大小,可以指定的一個值或者特殊的值,如 device-width 為設備的寬度(單位為縮放為 100% 時的 CSS 的像素)。
height
和 width 相對應,指定高度。
initial-scale
初始縮放。即頁面初始縮放程度。這是一個浮點值,是頁面大小的一個乘數。例如,如果你設置初始縮放為「1.0」,那麼,web頁面在展現的時候就會以target density解析度的1:1來展現。如果你設置為「2.0」,那麼這個頁面就會放大為2倍。
maximum-scale
最大縮放。即允許的最大縮放程度。這也是一個浮點值,用以指出頁面大小與屏幕大小相比的最大乘數。例如,如果你將這個值設置為「2.0」,那麼這個頁面與target size相比,最多能放大2倍。
user-scalable
用戶調整縮放。即用戶是否能改變頁面縮放程度。如果設置為yes則是允許用戶對其進行改變,反之為no。默認值是yes。如果你將其設置為no,那麼minimum-scale 和 maximum-scale都將被忽略,因為根本不可能縮放。
(設置屏幕寬度為設備寬度,禁止用戶手動調整縮放)
HTML代碼
<meta name="viewport" content="width=device-width,user-scalable=no" />
[HTML] view plain
<meta name="viewport" content="width=device-width,user-scalable=no" />
(設置屏幕密度為高頻,中頻,低頻自動縮放,禁止用戶手動調整縮放)
HTML代碼
<meta
name="viewport" content="width=device-width,target-densitydpi=high-dpi,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
[HTML] view plain
<meta
name="viewport" content="width=device-width,target-densitydpi=high-dpi,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"
/>
註:1). 所有的縮放值都必須在0.01–10的范圍之內。
2). minimum-scale、maximum-scale要麼寫值,要不留這兩個
2. 不使用絕對寬度
由於網頁會根據屏幕寬度調整布局,所以不能使用絕對寬度的布局,也不能使用具有絕對寬度的元素。這一條非常重要。
具體說,CSS代碼不能指定像素寬度:
width:xxx px;
只能指定百分比寬度:
width: xx%;
或者
width:auto;
3. CSS的@media規則
同一個CSS文件中,也可以根據不同的屏幕解析度,選擇應用不同的CSS規則。
HTML代碼
@media screen and (max-device-width: 400px) {
.column {
float: none;
width:auto;
}
#sidebar {
display:none;
}
}
[HTML] view plain
@media screen and (max-device-width: 400px) {
.column {
float: none;
width:auto;
}
#sidebar {
display:none;
}
}
上面的代碼意思是,如果屏幕寬度小於400像素,則column塊取消浮動(float:none)、寬度自動調節(width:auto),sidebar塊不顯示(display:none)。
4. 流動布局
各個區塊的位置都是浮動的,不是固定不變的。
HTML代碼
.main {
float: right;
width: 70%;
}
.leftBar {
float: left;
width: 25%;
}
[HTML] view plain
.main {
float: right;
width: 70%;
}
.leftBar {
float: left;
width: 25%;
}
float的好處是,如果寬度太小,放不下兩個元素,後面的元素會自動滾動到前面元素的下方,不會在水平方向overflow(溢出),避免了水平滾動條的出現。
另外,絕對定位(position: absolute)的使用,也要非常小心。
5. 圖片的自適應
圖片的寬度和高度要按百分比來設定,千萬不可以設定成固定大小。
HTML代碼
<img width="95%" src="" alt="" />
[HTML] view plain
<img width="95%" src="" alt="" />
H. 雷蛇滑鼠連鍵怎麼辦
問題一:雷蛇滑鼠驅動怎麼設置側鍵為滑鼠左鍵連點 10分 錄制一個只有左鍵單擊操作的宏,設置好延遲時間,然後配給那個功能鍵,循環播放就可以了。你還是換雲驅動吧,這個老版的驅動我都忘了有沒有我說的這些功能了。
問題二:Razer 雷蛇 煉獄蝰蛇 底下調DPI的按鍵連按了好多下滑鼠死掉了怎麼辦 目測買到假貨。我之前也有一隻蝰蛇。。即插即用。驅動只是調節DPI。可有可無。
問題三:我有一個煉獄蝰蛇的滑鼠左鍵總是點兩下,該怎麼修啊? 建議: 3. 檢查源代碼編輯無誤後,在VBA窗口中打開菜單「運行」/「運行宏」,將彈出「宏」窗口,你只需單擊「運行」即可。
問題四舉禪:雷蛇煉獄蝰蛇的滑鼠出現滑鼠左鍵的連鍵現象,不知道怎麼去找客服,在網路上也搜不到客服, 您好,這個問題我恰好在4天前處理過,只需要您拿著滑鼠和發票去您買的地方找他,就可以以舊換新了,如果發票掉了的話,可以用滑鼠背後的S/N碼來證明及查詢。保修期為2年。
問題五:怎麼用雷蛇雲驅動設置滑鼠左鍵連點 我現在在用雷柏V300游戲滑鼠,DPI很高,手感還不錯,游戲滑鼠挺好用的,樓主也可以試試。塵則
問題六:雷蛇 雷雲左鍵連點滑鼠宏 怎麼設置啊 老鐵 5分 如果就是想連續開槍,那麼直接錄制一個單擊左鍵的操作就可以了,配置按鍵時選擇連續播放。
如果是有規律的開槍,比如按鍵後連開3槍然後結束,那就要相對麻煩一些,建議在玩游戲的過程中錄制宏(進入游戲玩一會兒,開啟宏錄制,進行連發操作,關閉宏錄制)然後根據錄制結果,調整各個單擊操作的間隔時間(最好多試幾次,以確定最有效的操作間隔時間)。配置按鍵時選擇播放一次。
問題七:我的雷蛇滑鼠是雷蛇那伽梵蛇,左鍵點一下有連點兩下到三下的效果,就是好一會然後就出現這個狀況,求解釋 這是滑鼠的微動開關問題,雷蛇的滑鼠一般都使用國產歐姆龍白點微動,這種微動品相一般,極易出現雙擊或連擊的問題。建議自行購買品相更好的微動開關進行更換,如日產灰點歐姆龍微動。再請修電腦的或者自己參考網上教程進行更換,問題就可以解決。
來自UC瀏覽器
問題八:想問問 煉獄蝰蛇 怎麼能把 滑鼠 左右鍵 設置成 連點模式 滑鼠點擊派答棚一次變成兩次,是滑鼠連點了,一般是微動開關點擊後無法正常彈起造成的,需要更換壞掉的滑鼠微動開關。
滑鼠更換微動,需要的工具如下:
十字螺絲刀、小號電烙鐵、焊錫。
更換方法:
1,購買新的微動開關;
2,使用十字螺絲刀拆開滑鼠;
3,使用電烙鐵,焊開並取下壞掉的微動開關;
4,更換新的微動開關,並用電烙鐵和焊錫,重新焊接微動開關;
5,安裝好滑鼠,即可更換完成。
問題九:razer滑鼠在筆記本上用,原來的設置是12個鍵對應小鍵盤,現在連接到筆記本上了,失去原來的功能了,怎麼辦 20分 當你使用FN鍵把筆記本的小鍵盤開啟時,就有用了。(實際就是Numlock)
問題十:雷蛇宏怎麼設置一直按住左鍵不放,再按設置的那個鍵松開,再按就在打開? 10分 您好,我也需要這樣的宏,請問您的問題解決了嗎?能不能幫幫我.就是左鍵一直按著不放的那個宏
I. 有哪些好的平面設計素材網站
素材聯盟VeryCD社區
素材天下
素材資源庫
數字驛站
圖虎網
圖行天下
懸賞中國
設計資源站
懶人圖庫
愛圖網
PSD 設計素材
素材世界
藝術中國網
素材酷
素材庫
站酷
3lian素材網
素材聯盟
素材黃頁
素材中國
設計動力
迷星素材網
當我吧素材網
聚吧設計素材
素材聯盟VeryCD社區
素材天下
素材資源庫
數字驛站
圖虎網
圖行天下
懸賞中國
設計資源站
懶人圖庫
愛圖網