当前位置:首页 » 操作系统 » dpi源码

dpi源码

发布时间: 2023-05-29 10:22:31

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社区
素材天下
素材资源库
数字驿站
图虎网
图行天下
悬赏中国
设计资源站
懒人图库
爱图网

热点内容
scratch少儿编程课程 发布:2025-04-16 17:11:44 浏览:640
荣耀x10从哪里设置密码 发布:2025-04-16 17:11:43 浏览:368
java从入门到精通视频 发布:2025-04-16 17:11:43 浏览:86
php微信接口教程 发布:2025-04-16 17:07:30 浏览:310
android实现阴影 发布:2025-04-16 16:50:08 浏览:794
粉笔直播课缓存 发布:2025-04-16 16:31:21 浏览:346
机顶盒都有什么配置 发布:2025-04-16 16:24:37 浏览:213
编写手游反编译都需要学习什么 发布:2025-04-16 16:19:36 浏览:817
proteus编译文件位置 发布:2025-04-16 16:18:44 浏览:367
土压缩的本质 发布:2025-04-16 16:13:21 浏览:594