無意中打開了一年前做過的一個android應用的代碼,看到里面實現的一個小功能點(如題),現寫篇文章做個筆記。當時面臨的問題是,在旋轉屏幕的時候需要讓gridview的列數與寬度能自適應屏幕寬度,每個單元格之間還需要保留一定的間距。因為每款手機的屏幕寬度不都相同,我們在指定了單元格的寬度與間距之后,並不能確定每行中所能容納的單元格數量,這個數量必須在運行時通過計算得出,同樣,我們設置的單元格寬度和間距不能保證剛好容納在屏幕寬度內,為了解決這個問題,設計了一個簡單的算法,首先需要預先指定單元格的寬度和間距,然后根據屏幕寬度通過計算得出調整后的單元格寬度與每行所能容納的單元格數量,對於每個單元格來說,調整后寬度與初始寬度的誤差小於:單元格初始寬度 / ( 2 * 調整后每行單元格數量 ),當單元格寬度小於屏幕寬度時極端情況下的最大誤差為:單元格初始寬度 / 4。經過試驗,很好的解決了自適應的問題。
算法流程如下:
- 指定單元格初始寬度值width和間距padding,並獲取屏幕寬度值
- 計算屏幕中是否剛好能容納下整數個單元格,如果能,計算出單元格數量,然后直接跳到第6步,否則繼續下一步
- 計算單元格總寬度超出屏幕的寬度值,如果超出的寬度值小於單元格初始寬度值的一半,繼續下一步,否則跳到第5步
- 計算單元格數量,並將超出屏幕的寬度值按單元格數量進行平分(負值),添加到每個單元格上,即:cellWidth = cellWidth - avgSpace,然后跳到第6步
- 計算單元格數量,並將單元格寬度減去超出屏幕寬度后的值按單元格數量進行平分(正值),添加到每個單元格上,即:cellWidth = cellWidth + avgSpace
- 根據單元格數量算出總間距,將總間距平分(負值),添加到每個單元格上,即:cellWidth = cellWidth - avgPadding
- 最后得出的就是自適應單元格數量與寬度
這樣我們就實現了一個小算法,通過指定列間距(不需要可設為零)和初始列寬(這個值只是一個大概寬度),就能在運行時根據手機屏幕的寬度自動計算出屏幕可容納的精確列寬和列數,從而屏蔽了眾多手機屏幕尺寸不同的問題,達到了自適應的目的,該方法也可適用於其他類似的場景。
下圖是分析問題時畫得草圖:
①是超出屏幕的寬度小於單元格初始寬度的一半,對應算法流程的第3、4、6步
②是超出屏幕的寬度大於單元格初始寬度的一半,對應算法流程的第3、5、6步
將計算單元格寬度的代碼放到onCreateView方法中,這樣每次旋轉屏幕時就會自動調整gridview中每行的單元格數和寬度,使其剛好容納在屏幕寬度內。
下面是運行截圖(仔細看會發現豎屏和橫屏中的單元格寬度是不一樣的,自適應的結果):
代碼如下(省去了部分不必要的代碼):
public class FragmentAllBushou extends Fragment { GridView gridView = null; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { WindowManager manger = getActivity().getWindowManager(); Display display = manager.getDefaultDisplay(); //屏幕高度 int screenHeight = display.getHeight(); //屏幕寬度 int screenWidth = display.getWidth(); gridView = new GridView(getActivity()); ColumnInfo colInfo = calculateColumnWidthAndCountInRow(screenWidth, 100,2); int rowNum = cursor.getCount()%colInfo.countInRow == 0 ? cursor.getCount()/colInfo.countInRow:cursor.getCount()/colInfo.countInRow+1; gridView.setLayoutParams(new LayoutParams(screenWidth,rowNum*colInfo.width+(rowNum-1)*2)); gridView.setNumColumns(colInfo.countInRow); gridView.setGravity(Gravity.CENTER); gridView.setHorizontalSpacing(2); gridView.setVerticalSpacing(2); gridView.setStretchMode(GridView.STRETCH_COLUMN_WIDTH); } //存放計算后的單元格相關信息 class ColumnInfo{ //單元格寬度 public int width = 0; //每行所能容納的單元格數量 public int countInRow = 0; } /** * 根據手機屏幕寬度,計算gridview每個單元格的寬度 * @param screenWidth 屏幕寬度 * @param width 單元格預設寬度 * @param padding 單元格間距 * @return */ private ColumnInfo calculateColumnWidthAndCountInRow(int screenWidth,int width,int padding){ ColumnInfo colInfo = new ColumnInfo(); int colCount = 0; //判斷屏幕是否剛好能容納下整數個單元格,若不能,則將多出的寬度保存到space中 int space = screenWidth % width; if( space == 0 ){ //正好容納下 colCount = screenWidth / width; }else if( space >= ( width / 2 ) ){ //多出的寬度大於單元格寬度的一半時,則去除最后一個單元格,將其所占的寬度平分並增加到其他每個單元格中 colCount = screenWidth / width; space = width - space; width = width + space / colCount; }else{ //多出的寬度小於單元格寬度的一半時,則將多出的寬度平分,並讓每個單元格減去平分后的寬度 colCount = screenWidth / width + 1; width = width - space / colCount; } colInfo.countInRow = colCount; //計算出每行的間距總寬度,並根據單元格的數量重新調整單元格的寬度 colInfo.width = width - (( colCount + 1 ) * padding ) / colCount; return colInfo; } }