android開發學習筆記系列(4)--android動態布局


前言

在做一個有關蘇果APP的項目中,但是fuck的是,我完全使用相對布局之后及線性布局之后發現坑爹的事情了,屏幕不能適配,這是多大的痛,意味着,必須使用相應的代碼實現動態布局!呵呵,不做項目不知道,只有真正地下手去做某些事情的時候,才會發覺各種問題,原本打算先寫view與framgent實現tabhost功能的博客的,但是碰到了這個棘手問題必須先把他解決了!同時不知道各位網友有什么好的方法來適配所有的安卓手機屏幕

問題

  • 在xml文件中使用px之后出現了各種不適應屏幕的情況,控件不是大了就是小了,要知道在android世界里面有太對的屏幕尺寸了,真羡慕搞蘋果開發的人!
  • UI變得奇丑無比
  • 控件太多的偏差了!

解決之道

其實解決之道有很多,我選用的是使用代碼計算等比例高寬,讓其在相應的屏幕上顯示相應的比例高度就可以了!當然網上有很多都是給的建議,卻沒有實實在在解決問題的博客!(希望集思廣益,能夠得到一個適合全部屏幕類型的架包,方便所有的安卓開發人員)

關於網上的建議

網上的建議,我進行了歸納:

一、關於布局適配

  1. 不要使用絕對布局
  2. 盡量使用match_parent 而不是fill_parent 。
  3. 能夠使用權重的地方盡量使用權重(android:layout_weight)
  4. 如果是純色背景,盡量使用android的shape 自定義。
  5. 如果需要在特定分辨率下適配,可以在res目錄上新建layout-HxW.xml的文件夾。比如要適配1080x1800的屏幕(魅族MX3采用此分辨率)則新建layout-1800x1080.xml的文件夾,然后在下面定義布局。Android系統會優先查找分辨率相同的布局,如果不存在則換使用默認的layout下的布局。

二、術語和概念

  • 四種屏幕尺寸分類:: small, normal, large, and xlarge
  • 四種密度分類: ldpi (low), mdpi (medium), hdpi (high), and xhdpi (extra high)
  • 需要注意的是: xhdpi是從 Android 2.2 (API Level 8)才開始增加的分類.
  • xlarge是從Android 2.3 (API Level 9)才開始增加的分類.
  • DPI是“dot per inch”的縮寫,每英寸像素數。

一般情況下的普通屏幕:ldpi是120,mdpi是160,hdpi是240,xhdpi是320。

三、如何做到自適應屏幕大小呢?

1、界面布局方面

需要根據物理尺寸的大小准備5套布局,layout(放一些通用布局xml文件,比如界面中頂部和底部的布局,不會隨着屏幕大小變化,類似windos窗口的title bar),layout-small(屏幕尺寸小於3英寸左右的布局),layout-normal(屏幕尺寸小於4.5英寸左右),layout-large(4英寸-7英寸之間),layout-xlarge(7-10英寸之間)

2、圖片資源方面

需要根據dpi值准備5套圖片資源,drawable,drawalbe-ldpi,drawable-mdpi,drawable-hdpi,drawable-xhdpi

Android有個自動匹配機制去選擇對應的布局和圖片資源

四、兩種獲取屏幕分辨率信息的方法:

DisplayMetrics metrics = new DisplayMetrics();
Display display = activity.getWindowManager().getDefaultDisplay();
display.getMetrics(metrics);//這里得到的像素值是設備獨立像素dp
//DisplayMetrics metrics=activity.getResources().getDisplayMetrics(); 這樣獲得的參數信息不正確,不要使用這種方式。

不能使用android.content.res.Resources.getSystem().getDisplayMetrics()。這個得到的寬和高是空的。

五、關於圖片制作

關於設計

設計圖先定下一個要設計的尺寸,而且盡量采用在目前最流行的屏幕尺寸(比如目前占屏幕比重比較多的是480系列,也即是480x800或者400x854,下面的圖標制作也在次基礎上進行比例的換算)上設計。
先了解一下屏幕的級別:

說明:

  • 屏幕級別:
    注意屏幕級別是按照密度分級,和像素沒有關系。如果非要讓密度和像素扯上關系,則需要一個參照系,android使用mdpi級別作為標准參照屏幕,也就是說在320x480分辨率的手機上一個密度可以容納一個像素。然后其他密度級別則在此基礎上進行對比。如果理想情況下,480x800的屏幕一個密度可以容納1.5個像素。

  • 物理大小:
    單位是英寸而不是像素,也就說一個英寸在任何分辨率下顯示的大小都是一樣的,但是像素在密度不同的手機里面顯示的實際的大小是不一樣的(這就是為什么android手機需要適配的原因)。
    然后就是重點。

假設1像素在160密度下顯示1英寸,則1像素在240密度基礎上顯示大約0.67英寸,在320密度下顯示0.5英寸。於是就出現一種情況,在電腦上的一個像素,在不同的手機上看實際的大小不一樣。那么怎么讓“設計效果”在不同的手機上看起來顯示的區域一樣呢?

還是假設一個像素在160密度下的顯示在一個密度內,也假設就是一英寸。那么需要幾個像素才能在240密度級別下顯示在一英寸范圍內呢?答案是1.5個像素(根據上圖的比率換算)。
了解了這個關系,接下來就是圖標的制作。

關於切圖

關於切圖有幾個建議:

  1. 長寬最好是3的倍數(根據android的推薦logo圖標的大小是48(mdpi),72(hdpi),96(xhdpi)得出的最小公約數)。
  2. 長寬最好是偶數。因為奇數在進行等比壓縮的時候可能有問題。
  3. 根據上面兩條,如果長寬是6的倍數最理想。
  4. 如果可以拉伸而不改變設計意圖的情況下,比如純色背景,則使用android的9path工具制作成.9的圖片。

關於圖標的適配。

然后接下來的一切就和設計稿沒什么關系。在切好圖的基礎上,根據屏幕密度、像素和實際大小的比例關系。假如設計司在480x800的分辨率下做好了設計圖,並且切好圖,如果你需要適配720x1280屏幕,該怎么做?根據比例,他們的關系是2:3,於是你需要按照1.5倍比例制作圖標,比如你在480x800的設計稿上切下來一個20*20像素的圖,那么你就需要制作一個等比放大成30x30像素的圖標,這樣同一個圖標在480x800的屏幕和720x1280的屏幕上顯示的實際大小才一樣。同理,如果你需要適配xxhdpi則需要在20x20的基礎上制作一個等比放大成40x40像素的圖標。

關於圖標的目錄

480*800切下來的圖我們放在drawable-hdpi目錄下,按照2:3放大的圖標放在drawable-xhdpi目錄下,按照2倍放大的圖標放在drawable-xxhdpi目錄下。

android會根據手機的密度優先查找對應的目錄的資源,
比如408800分辨率下的手機如果密度是160,則自動加載drawable-hdpi這個目錄下的圖標,
如果720
1280密度是240的手機自動加載drawable-xhdpi這個目錄下的圖標。如果沒有這個文件夾,則查找和240最接近的對應密度文件夾。

有關個人的解決方法

我個人得到的啟示就是我在設計過程中盡量使控件不是使用數值,也就是說我在xml文件所使用的基本都是layout_weight\android:gravity="center"等,如果迫不得得以使用的話,就先寫着,然后通過相應的代碼來適配動態布局

代碼實現動態布局

目前我所使用的方法呢就是自己寫個類,將view傳進去進行適配,同時注意了我的方案是可以更改你原來所假設的屏幕寬度,然后一次性地進行適配!

package com.samuel.demosuguo;

import android.content.Context;
import android.util.DisplayMetrics;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
/**
 * Created by samuelwnb on 2015/3/14.
 */
public class Autosize {

    int screenwidth = 640;//默認屏幕寬度為640

    /***
     * 得到默認屏幕寬度
     * @return
     */
    public int getScreenwidth() {
        return screenwidth;
    }

    /***
     * 更改默認屏幕寬度
     * @param screenwidth
     */
    public void setScreenwidth(int screenwidth) {
        this.screenwidth = screenwidth;
    }

    //實際屏幕大小
    static int screensize = 0;
    public static void setScreensize(int screensize) {
        Autosize.screensize = screensize;
    }


    /**
     * 獲取屏幕的大小
     * @param context//為activity
     * @return 實際屏幕的打下
     */
    public int Metricwidth(Context context){
        DisplayMetrics metric = new DisplayMetrics();
        metric = context.getResources().getDisplayMetrics();
        return metric.widthPixels;
    }
    //獲取直接獲取屏幕的實際寬度
    public void GetrealScreenwidth(Context context){
        DisplayMetrics metric = new DisplayMetrics();
        metric = context.getResources().getDisplayMetrics();
        setScreensize(metric.widthPixels);
    }
    //設置線性布局下的線性高度
    public void llinearlayoutheight(int px, LinearLayout linearLayout) {
        LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) linearLayout.getLayoutParams();
        if(screensize != 0) {
            layoutParams.height = px * screensize / screenwidth;
            linearLayout.setLayoutParams(layoutParams);
        }
    }

    /***********************
    控件設置
     */
    //自動設置設置字體的大小
    public int autosettextsize(int sp){
        if(screensize != 0) {
            return sp * screensize / screenwidth;
        }
        else {
            return sp;
        }

    }
    /**
     * 相對布局中的不同設置高度
     */
    //設置相對布局下的相對布局高度
    public void relativeLayoutheight(int px, RelativeLayout relativeLayout) {
        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) relativeLayout.getLayoutParams();
        if(screensize != 0) {
            layoutParams.height = px * screensize / screenwidth;
            relativeLayout.setLayoutParams(layoutParams);
        }
    }
    //設置相對布局中的相對高度帶Margintop設置
    public void relativeLayoutheightwithmargintop(int px,int margintop, RelativeLayout relativeLayout){
        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) relativeLayout.getLayoutParams();
        if(screensize != 0) {
            layoutParams.height = px * screensize / screenwidth;
            layoutParams.topMargin = margintop * screensize / screenwidth;
            relativeLayout.setLayoutParams(layoutParams);
        }
    }
    public void relativeLayoutheightmargintop(int margintop, RelativeLayout relativeLayout){
        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) relativeLayout.getLayoutParams();
        if(screensize != 0) {
            layoutParams.topMargin = margintop * screensize / screenwidth;
            relativeLayout.setLayoutParams(layoutParams);
        }
    }
    //設置相對布局下的線性布局高度
    public void rlinearlayoutheight(int px, LinearLayout linearLayout) {
        RelativeLayout.LayoutParams relativelayout = (RelativeLayout.LayoutParams) linearLayout.getLayoutParams();
        if(screensize != 0) {
            relativelayout.height = px * screensize / screenwidth;
            linearLayout.setLayoutParams(relativelayout);
        }
    }
    public void rlinearlayoutheightwithmargintop(int px,int margintop,LinearLayout linearLayout) {
        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) linearLayout.getLayoutParams();
        if(screensize != 0) {
            layoutParams.height = px * screensize / screenwidth;
            layoutParams.topMargin = margintop * screensize / screenwidth;
            linearLayout.setLayoutParams(layoutParams);
        }
    }
    public void rlinearlayoutheightmargintop(int margintop,LinearLayout linearLayout) {
        RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) linearLayout.getLayoutParams();
        if(screensize != 0) {
            layoutParams.topMargin = margintop * screensize / screenwidth;
            linearLayout.setLayoutParams(layoutParams);
        }
    }
   }

在這里我來舉個例子:

Autosize autosize = new Autosize();
        autosize.GetrealScreenwidth(getActivity());
        RelativeLayout tophome = (RelativeLayout) findViewById(R.id.tophome);
        autosize.relativeLayoutheight(88,tophome);

步驟:

  • 先實例化我寫的類
  • 獲取屏幕寬度
  • 得到RelativeLayout的ID
  • 直接送入適配,但注意這里要知道你想在屏幕上顯示多大!

注意的地方

一定要注意你到底是哪個布局下的一個布局,必須找到父view才可以使用!如果想知道為什么的話,大家可以去找layoutparams有關的內容!

給讀者的話

那個撒,你看我如此賣命地寫博客,而且還是自己在攻克難點,就來關注我的博客唄!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM