Android學習-手把手教學實現仿微信髮帶圖片朋友圈的UI設計

#Android學習-手把手教學實現仿微信髮帶圖片朋友圈的UI設計#html

功能需求

最近本身在開發一個社交APP,發送動態(相似朋友圈)是社交APP必備的一個功能,而本身在開發過程當中也須要開發到這一個功能,可是在開發中遇到了一個問題,就是如何繪製一個相似朋友羣那樣動態添加圖片,並加號隨着本身的圖片增長然後移這一個UI,而這篇小文就是教你如何製做一個仿朋友圈髮帶圖朋友圈的UI設計。注意,這是UI設計,並非實現圖片上傳功能。android

固然,若是你想知道如何實現圖片上傳到服務器,請看個人另外一篇文章:Android學習-使用Async-Http實現圖片壓縮並上傳功能。我的水平有限,若有不足的地方,歡迎交流,勿噴。git

效果圖

按照慣例,先上效果圖。github

困難

在本身開發學習過程當中,主要遇到了兩個難點:服務器

  1. 添加過多圖片時,會出現OOM。
  2. 如何動態修改圖片展現欄的高度。
  3. 加號如何伴隨圖片的增長然後移。
  4. 如何保證最多添加照片爲9張。

難點解決

添加過多圖片時,會出現OOM

出現第一種狀況的緣由很簡單,就是隨着咱們手機的像素愈來愈高,圖片的大小也愈來愈大,咱們普通的機拍出來照片至少也有1~2M,更不說像素高的手機。而對於一個安卓應用來講,因爲手機設備的限制,通常應用使用的RAM不能超過某個設定值,不一樣產商默認值不太同樣,通常常見的有16M,24M,32M,48M。因此一個Activity中加載幾張高清原圖,就會報Out Of Memory 錯誤,也就是所謂的OOM錯誤。因此知道了這個問題以後咱們就很容易解決了,咱們就能夠先將圖片壓縮,而後再使用ImageView加載壓縮後的圖片便可。而咱們這裏是經過對圖片的尺寸進行壓縮實現圖片的壓縮,這裏大概說一下。微信

  1. 要對圖片壓縮,首先要先將BitmapFactory.Options中的inJustDecodeBounds設置爲true。ide

    final BitmapFactory.Options options = new BitmapFactory.Options();
     // 若要對圖片進行壓縮,必須先設置Option的inJustDecodeBounds爲true
     options.inJustDecodeBounds = true;
  2. 而後經過BitmapFactory中decodeFile方法來獲取到照片的高度和寬度,這裏只要存進一個圖片地址便可。獲取圖片地址這裏就不詳講了。學習

    BitmapFactory.decodeFile(pathName,options)
  3. 而後須要對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;
     }
  4. 獲取到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的高度不變
  • 若是照片有兩欄,則高度設置爲gridViewH * 2 - (gridViewH - imageViewH) / 2
  • 若是有三欄,則GrideView的高度設置爲gridViewH * 3 - (gridViewH - imageViewH)

  1. 咱們在第一次加載GridView時記錄GridView的高度GridViewH。

    LinearLayout.LayoutParams params =(android.widget.LinearLayout.LayoutParams) mGridView.getLayoutParams();
    
     gridViewH = params.height;
  2. 同時記錄ImageView的高度

    RelativeLayout.LayoutParams params = (android.widget.RelativeLayout.LayoutParams) holder.imageView
     			.getLayoutParams();
     imageViewH = params.height;
  3. 則上下的邊距爲

    (gridViewH - imageViewH) / 2
  4. 將它寫成一個方法,在每次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();

如何保證最多添加照片爲9張

這個問題只須要在每次添加以前判斷數據源的大小是否爲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>

Demo下載

Github:https://github.com/ryanlijianchang/TestUpload

CSDN: http://download.csdn.net/detail/ljcitworld/9549313

後話

博主只是實現了這一個UI界面,咱們開發過程當中確定要實現圖片,文字的上傳等,這裏博主就再也不詳述了,你們能夠看個人另外一篇博文Android學習-使用Async-Http實現圖片壓縮並上傳功能,就這個例子而言,你們若是須要上傳多張照片,就能夠在添加完照片以後將bitmap存起來,而後經過循環容器的大小,而後每一張圖片再上傳到服務器便可。仍是那句話,我的能力有限,歡迎你們一塊兒交流學習,我也會虛心接納你們的指教,不喜勿噴。

參考資料

Android Developer:Loading Large Bitmaps Efficiently

相關文章
相關標籤/搜索