当你的应用程序运行在一个电视上的时候,你应该假设用户坐在距离屏幕大约10英寸远的地方。这样的用户环境被作为10-foot UI被引用。为了给你的用户提供一个舒适和愉快的体验,你应该相应的设计和定制你的UI。
这节课程向你展示如何通过以下方式,针对电视优化你的布局:
为横屏模式提供适当的布局资源。
确保文本和控件从一定距离看,足够大保证可见。
为高清电视屏幕提供高分辨率的位图和图标。
设计横屏布局
——————————————————————————————————————————————————————————————
电视屏幕总是在横屏方向,遵循这些提示来为对电视屏幕优化,构建横屏布局:
方式屏幕导航控制在屏幕的左侧或者右侧,为内容节省垂直空间。
分部分创建UI,通过使用Fragment,和使用如GridView视图组替代ListView来更好的利用横向屏幕空间。
使用如RelativeLayout或者LinearLayout视图组排列视图。它允许Android系统针对视图大小调整位置,对齐,长宽比和电视屏幕的像素密度。
在布局控件之间添加足够的边缘来避免一个凌乱的界面。
例如,下面的布局是针对电视优化的:
在这个布局中,控制控件在左侧。UI被现实在一个GridView中,它完美适应横屏方向。在这个布局中,GridView和Fragment的宽度和高度都是设置为动态的,所以它们能适应屏幕的分辨率。控制控件在运行时动态的添加到左侧。这个UI的布局文件是red/layout-land-large/photogrid_tv.xml。(这个布局文件被放置在layout-land-large是因为电视拥有横向的大屏幕。更多信息查阅Supproting Mutiple Screens。)
res/layout-land-large/photogrid_tv.xml
<RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" > <fragment android:id="@+id/leftsidecontrols" android:layout_width="0dip" android:layout_marginLeft="5dip" android:layout_height="match_parent" /> <GridView android:id="@+id/gridview" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </RelativeLayout>
wie了在屏幕的左侧设置Action Bar选项,你也可以在你的应用程序中包含Left navigation bar library,来在屏幕的左侧设置Action选项,替代使用一个自定义的Fragment来添加控制控件:
LeftNavBar bar = (LeftNavBarService.instance()).getLeftNavBar(this);
当你有一个内容垂直滑动的Activity的时候,总是使用左侧导航栏;另一方面,你的用户必须滑动到内容的顶端,在内容视图和ActionBar之间进行切换。看Left navigation bar sample app,看到如何在你的应用中简单包含左导航栏。
使文本和控件容易看见
——————————————————————————————————————————————————————————————
在一个电视应用界面中的文本和控件,应该在一定距离内容易被看见和导航。遵循下面的这些提示是它们在一定的距离内更容易被看见:
精简文本,使用户能快速的扫描。
在一个黑暗的背景中使用高亮的文本。这种样式在电视中更容易阅读。
避免轻量级的字体,或者字体非常窄和粗。使用简单的sans-serif字体和anti-aliasing来郑强可读性。
使用Android的标准字体大小:
<TextView android:id="@+id/atext" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_vertical" android:singleLine="true" android:textAppearance="?android:attr/textAppearanceMedium"/>
确保你的视图组件对于坐在屏幕前10英寸(这个距离对于更大的屏幕会更大)远的用户,足够大至清晰可见。这样做的最好方式是使用相对布局大小而不是绝对大小,并且使用基于密度的像素单位替代绝对像素单位。例如,为了设置一个控件的宽度,使用wrap_content替代像素尺寸,并且设置控件的边距,使用dip替代像素值。
针对高密度大屏幕设计
——————————————————————————————————————————————————————————————
常见的HDTV显示分辨率是720p,1080i和1080p。针对1080p设计你的UI,然后如果又必要的话,允许Android系统缩放你的UI适应720p。通常,缩减(移除像素)不会降低UI(注意到反过来是不正确的;你需要避免放大,应为它降低UI的质量)。
为了获取图片最好的缩放结果,如果可能以9-patch提供图片。如果你在你的布局中使用低质量的图片或者小图片,它们将出现模糊或者颗粒状。这对于用户来说是不好的体验。使用高质量的图片替代。
更新关于针对大屏幕优化应用的信息,查阅Designing for multiple screens。
设计处理较大的位图
——————————————————————————————————————————————————————————————
Android系统有内存大小的限制,所以在你的应用中下载和存储高分辨率的图片,会经常导致内存溢出错误。为了避免这个,遵循下面的这些提示:
仅仅在当它们被显示的时候加载图片。例如,当在一个GridView或者Gallery中显示多张图片的时候,当在视图的Adatper中的getView()被调用的时候仅仅加载一张图片。
在不在使用的Bitmap视图上调用recyle()。
在一个内存集合中使用WeakReference存储Bitmap对象的引用。
如果从网络获取图片,使用AsyncTack获取它们,并且在SD卡上保存它们用于快速访问。不要在应用程序的UI线程中进行网络传输。
当你下载它们的时候,缩小很大的图片到一个合适的大小;另一方面,下载图片本身可能导致“内存溢出”异常。下面的例子当下载的时候缩小图片:
// Get the source image's dimensions BitmapFactory.Options options = new BitmapFactory.Options(); // This does not download the actual image, just downloads headers. options.inJustDecodeBounds = true; BitmapFactory.decodeFile(IMAGE_FILE_URL, options); // The actual width of the image. int srcWidth = options.outWidth; // The actual height of the image. int srcHeight = options.outHeight; // Only scale if the source is bigger than the width of the destination view. if(desiredWidth > srcWidth) desiredWidth = srcWidth; // Calculate the correct inSampleSize/scale value. This helps reduce memory use. It should be a power of 2. int inSampleSize = 1; while(srcWidth / 2 > desiredWidth){ srcWidth /= 2; srcHeight /= 2; inSampleSize *= 2; } float desiredScale = (float) desiredWidth / srcWidth; // Decode with inSampleSize options.inJustDecodeBounds = false; options.inDither = false; options.inSampleSize = inSampleSize; options.inScaled = false; // Ensures the image stays as a 32-bit ARGB_8888 image. // This preserves image quality. options.inPreferredConfig = Bitmap.Config.ARGB_8888; Bitmap sampledSrcBitmap = BitmapFactory.decodeFile(IMAGE_FILE_URL, options); // Resize Matrix matrix = new Matrix(); matrix.postScale(desiredScale, desiredScale); Bitmap scaledBitmap = Bitmap.createBitmap(sampledSrcBitmap, 0, 0, sampledSrcBitmap.getWidth(), sampledSrcBitmap.getHeight(), matrix, true); sampledSrcBitmap = null; // Save FileOutputStream out = new FileOutputStream(LOCAL_PATH_TO_STORE_IMAGE); scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out); scaledBitmap = null;