#Android學習-手把手教學實現仿微信髮帶圖片朋友圈的UI設計#html
最近本身在開發一個社交APP,發送動態(相似朋友圈)是社交APP必備的一個功能,而本身在開發過程當中也須要開發到這一個功能,可是在開發中遇到了一個問題,就是如何繪製一個相似朋友羣那樣動態添加圖片,並加號隨着本身的圖片增長然後移這一個UI,而這篇小文就是教你如何製做一個仿朋友圈髮帶圖朋友圈的UI設計。注意,這是UI設計,並非實現圖片上傳功能。android
固然,若是你想知道如何實現圖片上傳到服務器,請看個人另外一篇文章:Android學習-使用Async-Http實現圖片壓縮並上傳功能。我的水平有限,若有不足的地方,歡迎交流,勿噴。git
按照慣例,先上效果圖。github
在本身開發學習過程當中,主要遇到了兩個難點:服務器
出現第一種狀況的緣由很簡單,就是隨着咱們手機的像素愈來愈高,圖片的大小也愈來愈大,咱們普通的機拍出來照片至少也有1~2M,更不說像素高的手機。而對於一個安卓應用來講,因爲手機設備的限制,通常應用使用的RAM不能超過某個設定值,不一樣產商默認值不太同樣,通常常見的有16M,24M,32M,48M。因此一個Activity中加載幾張高清原圖,就會報Out Of Memory 錯誤,也就是所謂的OOM錯誤。因此知道了這個問題以後咱們就很容易解決了,咱們就能夠先將圖片壓縮,而後再使用ImageView加載壓縮後的圖片便可。而咱們這裏是經過對圖片的尺寸進行壓縮實現圖片的壓縮,這裏大概說一下。微信
要對圖片壓縮,首先要先將BitmapFactory.Options中的inJustDecodeBounds設置爲true。ide
final BitmapFactory.Options options = new BitmapFactory.Options(); // 若要對圖片進行壓縮,必須先設置Option的inJustDecodeBounds爲true options.inJustDecodeBounds = true;
而後經過BitmapFactory中decodeFile方法來獲取到照片的高度和寬度,這裏只要存進一個圖片地址便可。獲取圖片地址這裏就不詳講了。學習
BitmapFactory.decodeFile(pathName,options)
而後須要對BitmapFactory.Options中的inSampleSize根據你須要壓縮比例進行設置,options.inSampleSize是圖片的壓縮比,例如原來大小是100 * 100,options.inSampleSize爲1,則不變,options.inSampleSize爲2,則壓縮成50 * 50。而我這裏是根據本身設置最低寬度和最低高度來獲取inSampleSize的值:this
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { //首先獲取原圖高度和寬度的一半 final int halfHeight = height / 2; final int halfWidth = width / 2; //循環,若是halfHeight和halfWidth同時大於最小寬度和最小高度時,inSampleSize乘2, //最後獲得的寬或者高都是最接近最小寬度或者最小高度的 while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; }
獲取到inSampleSize值以後,從新設置options.inJustDecodeBounds爲false,不能修改option,調用BitmapFactory中的decodeFile方法便可獲取到壓縮後的照片,這樣在加載圖片時就能夠避免OOM的出現了。.net
options.inJustDecodeBounds = false; // 根據options從新加載圖片 Bitmap src = BitmapFactory.decodeFile(pathName, options);
綜上,我將按尺寸壓縮照片的功能包裝成BitmapUtil類,在使用時直接調用便可。
public class BitmapUtils { private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; } /** * 根據Resources壓縮圖片 * * @param res * @param resId * @param reqWidth * @param reqHeight * @return */ public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeResource(res, resId, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds = false; Bitmap src = BitmapFactory.decodeResource(res, resId, options); return src; } /** * 根據地址壓縮圖片 * * @param pathName * @param reqWidth * @param reqHeight * @return */ public static Bitmap decodeSampledBitmapFromFd(String pathName, int reqWidth, int reqHeight) { final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(pathName, options); options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); options.inJustDecodeBounds = false; Bitmap src = BitmapFactory.decodeFile(pathName, options); return src; } }
如何動態修改圖片展現欄的高度,首先我說一下我是使用GridView來實現圖片欄的展現,因此咱們能夠在第一次加載GridView時能夠獲取到下圖的參數,你們看圖會容易理解一點。
咱們在第一次加載GridView時記錄GridView的高度GridViewH。
LinearLayout.LayoutParams params =(android.widget.LinearLayout.LayoutParams) mGridView.getLayoutParams(); gridViewH = params.height;
同時記錄ImageView的高度
RelativeLayout.LayoutParams params = (android.widget.RelativeLayout.LayoutParams) holder.imageView .getLayoutParams(); imageViewH = params.height;
則上下的邊距爲
(gridViewH - imageViewH) / 2
將它寫成一個方法,在每次getView()方法中調用便可。
private void setGridView() { LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) mGridView.getLayoutParams(); if (data.size() < 4) { lp.height = gridViewH; } else if (data.size() < 8) { lp.height = gridViewH * 2 - (gridViewH - imageViewH) / 2; } else { lp.height = gridViewH * 3 - (gridViewH - imageViewH); } mGridView.setLayoutParams(lp); }
由於個人數據源是List<Bitmap>,因此能夠這麼作:
當第一次加載時,List中只有一張加號的照片
當添加了照片以後,List先移除加號照片,再添加照片,最後再把加號照片添加進去
data.remove(data.size() - 1); Bitmap bp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_addpic); data.add(newBp); data.add(bp); //將路徑設置爲空,防止在手機休眠後返回Activity調用此方法時添加照片 photoPath = null; adapter.notifyDataSetChanged();
這個問題只須要在每次添加以前判斷數據源的大小是否爲10(包括加號照片,大小就爲10)。
if (data.size() == 10) { Toast.makeText(MainActivity.this, "圖片數9張已滿", Toast.LENGTH_SHORT).show(); } else { if (position == data.size() - 1) { Toast.makeText(MainActivity.this, "添加圖片", Toast.LENGTH_SHORT).show(); // 選擇圖片 Intent intent = new Intent(Intent.ACTION_PICK, null); intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); startActivityForResult(intent, 0x1); } else { Toast.makeText(MainActivity.this, "點擊第" + (position + 1) + " 號圖片", Toast.LENGTH_SHORT).show(); } }
activity_main.xml
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#F3F6F8" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <ImageView android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="2dp" android:src="#E4E3E3" /> <EditText android:id="@+id/content_et" android:layout_width="fill_parent" android:layout_height="120dp" android:background="#FFFFFF" android:gravity="top" android:hint="隨手說出你此刻的心聲..." android:maxLength="500" android:padding="5dp" android:singleLine="false" android:textColor="#000000" android:textSize="20sp" /> <ImageView android:layout_width="match_parent" android:layout_height="1dp" android:src="#E4E3E3" /> <ImageView android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="10dp" android:src="#E4E3E3" /> <GridView android:id="@+id/gridView1" android:layout_width="fill_parent" android:layout_height="100dp" android:background="#FFFFFF" android:columnWidth="90dp" android:gravity="center" android:horizontalSpacing="5dp" android:numColumns="4" android:padding="10dp" android:stretchMode="columnWidth" android:verticalSpacing="5dp" > </GridView> <ImageView android:layout_width="match_parent" android:layout_height="1dp" android:src="#E4E3E3" /> <Button android:id="@+id/send_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginLeft="35dp" android:layout_marginRight="35dp" android:layout_marginTop="20dp" android:background="@drawable/send_btn_selector" android:gravity="center" android:text="發送" android:textColor="#FFFFFF" android:textSize="20sp" /> </LinearLayout> </ScrollView>
griditem.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="80dp" android:layout_height="80dp" android:descendantFocusability="blocksDescendants" android:gravity="center" > <ImageView android:id="@+id/imageView1" android:layout_width="80dp" android:layout_height="80dp" android:scaleType="centerCrop" android:src="@drawable/ic_addpic" /> </RelativeLayout>
Github:https://github.com/ryanlijianchang/TestUpload
CSDN: http://download.csdn.net/detail/ljcitworld/9549313
博主只是實現了這一個UI界面,咱們開發過程當中確定要實現圖片,文字的上傳等,這裏博主就再也不詳述了,你們能夠看個人另外一篇博文Android學習-使用Async-Http實現圖片壓縮並上傳功能,就這個例子而言,你們若是須要上傳多張照片,就能夠在添加完照片以後將bitmap存起來,而後經過循環容器的大小,而後每一張圖片再上傳到服務器便可。仍是那句話,我的能力有限,歡迎你們一塊兒交流學習,我也會虛心接納你們的指教,不喜勿噴。