Android实现仿微信朋友圈发布动态(拍照、图库选择、照片压缩、显示、保存、缩略图、点击缩略图删除对应文件等)

新鲜出炉!HTML、CSS和JavaScript仿微信朋友圈,终于码出来了! 前几天我在抖音上刷视频,刷到了很多类似于朋友圈的图文,流量还挺高的,内容也很有意思,可是一直没找到相关的代码,于是我决定码一个仿朋友圈的HTML。我的思路是这样:首先创建HTML搭建页面结构,用CSS美化界面布局,用JavaScript实现头像和图片上传、内容编辑及评论功能,并借助html2canvas将整个朋友圈保存图片!小余将这项目部署到服务器了,大家可以随时使用这是我做的样式:嘿嘿!相当的n(*≧▽≦*)n废话不多说,直接上干货,(对了:完整的代码小余我放到文章最后了) 阅读详情

原址: http://blog.csdn.net/zhang3776813/article/details/52092591


/**
 * 仿微信朋友圈发布动态
 * 拍照或图库选择 
 * 压缩图片并保存
 *
 */
public class MainActivity extends BasicActivity implements OnItemClickListener {

	// 图片 九宫格
	private GridView gv;
	// 图片 九宫格适配器
	private GridViewAdapter gvAdapter;

	// 用于保存图片资源文件
	private List<Bitmap> lists = new ArrayList<Bitmap>();
	// 用于保存图片路径
	private List<String> list_path = new ArrayList<String>();

	// 拍照
	public static final int IMAGE_CAPTURE = 1;
	// 从相册选择
	public static final int IMAGE_SELECT = 2;
	// 照片缩小比例
	private static final int SCALE = 5;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		/* 不允许横竖屏切换 */
		setRequestedOrientation(1);
		/* 去除标题栏 */
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		init();
	}

	/**
	 * 初始化控件
	 */
	private void init() {
		gv = (GridView) findViewById(R.id.noScrollgridview);
		gvAdapter = new GridViewAdapter(this, lists);
		gv.setOnItemClickListener(this);
		gv.setAdapter(gvAdapter);
		gvAdapter.setList(lists);
	}
	
	@Override
	protected void onDestroy() {
		//删除文件夹及文件
		FileUtils.deleteDir();
		super.onDestroy();
	}

	/**
	 * 拍照
	 * 
	 * @param path
	 *            照片存放的路径
	 */
	public void captureImage(String path) {
		Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
		// 指定照片保存路径(SD卡),image.jpg为一个临时文件,每次拍照后这个图片都会被替换
		Uri uri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), "image.jpg"));
		intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
		startActivityForResult(intent, IMAGE_CAPTURE);
	}

	/**
	 * 从图库中选取图片
	 */
	public void selectImage() {
		 Intent intent = new Intent();
		 intent.setType("image/*");
		 intent.setAction(Intent.ACTION_PICK);
		 startActivityForResult(intent, IMAGE_SELECT);
		
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (resultCode == RESULT_OK && resultCode != RESULT_CANCELED) {
			String fileName;
			switch (requestCode) {
			case IMAGE_CAPTURE:// 拍照返回
				// 将保存在本地的图片取出并缩小后显示在界面上
				Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory() + "/image.jpg");
				Bitmap newBitmap = ImageTools.zoomBitmap(bitmap,bitmap.getWidth() / SCALE, bitmap.getHeight() / SCALE);
				// 由于Bitmap内存占用较大,这里需要回收内存,否则会报out of memory异常
				bitmap.recycle();
				// 生成一个图片文件名
				fileName = String.valueOf(System.currentTimeMillis());
				// 将处理过的图片添加到缩略图列表并保存到本地
				ImageTools.savePhotoToSDCard(newBitmap, FileUtils.SDPATH,fileName);
				lists.add(newBitmap);
				list_path.add(fileName+".jpg");
				
				for (int i = 0; i < list_path.size(); i++) {
					logI("第"+i+"张照片的地址:"+list_path.get(i));
				}
				// 更新GrideView
				gvAdapter.setList(lists);
				break;
			case IMAGE_SELECT:// 选择照片返回
				ContentResolver resolver = getContentResolver();
				// 照片的原始资源地址
				Uri originalUri = data.getData();
				try {
					// 使用ContentProvider通过URI获取原始图片
					Bitmap photo = MediaStore.Images.Media.getBitmap(resolver,originalUri);
					if (photo != null) {
						// 为防止原始图片过大导致内存溢出,这里先缩小原图显示,然后释放原始Bitmap占用的内存
						Bitmap smallBitmap = ImageTools.zoomBitmap(photo,photo.getWidth() / SCALE, photo.getHeight()/ SCALE);
						// 释放原始图片占用的内存,防止out of memory异常发生
						photo.recycle();
						// 生成一个图片文件名
						fileName = String.valueOf(System.currentTimeMillis());
						// 将处理过的图片添加到缩略图列表并保存到本地
						ImageTools.savePhotoToSDCard(smallBitmap, FileUtils.SDPATH,fileName);
						lists.add(smallBitmap);
						list_path.add(fileName+".jpg");
						
						for (int i = 0; i < list_path.size(); i++) {
							logI("第"+i+"照片的地址:"+list_path.get(i));
						}
						
						// 更新GrideView
						gvAdapter.setList(lists);
					}
				} catch (FileNotFoundException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				break;
			default:
				break;
			}
		}
	}

	@Override
	public void onItemClick(AdapterView<?> parent, View view, final int position,
			long id) {
		Toast.makeText(getApplicationContext(), "" + position + getDataSize(),Toast.LENGTH_SHORT).show();

		if (position == getDataSize()) {// 点击“+”号位置添加图片
			showAlertDialog(false, "提示", new String[] { "拍照", "从图库选择", "取消" },
					new DialogInterface.OnClickListener() {

						@Override
						public void onClick(DialogInterface dialog, int which) {
							switch (which + 1) {
							case 1:// 拍照
								captureImage(FileUtils.SDPATH);
								dialog.dismiss();
								break;
							case 2:// 从图库选择
								selectImage();
								dialog.dismiss();
								break;
							case 3:// 取消
								dialog.dismiss();
								break;

							default:
								break;
							}
						}
					});
		} else {// 点击图片删除
			showAlertDialog("提示", "是否删除此图片?", "确定", "取消", new DialogInterface.OnClickListener() {
				
				@Override
				public void onClick(DialogInterface dialog, int which) {
					lists.remove(position);
					FileUtils.delFile(list_path.get(position));
					list_path.remove(position);
					gvAdapter.setList(lists);
					dialog.dismiss();
				}
			}, new DialogInterface.OnClickListener() {
				
				@Override
				public void onClick(DialogInterface dialog, int which) {
					dialog.dismiss();
				}
			});
		}
	}

	private int getDataSize() {
		return lists == null ? 0 : lists.size();
	}

	// ----------------------------------------------------各种消息弹窗--------------------------------------------------------------------------//
	/**
	 * 带点击事件的单按钮AlertDialog
	 * 
	 * @param title
	 *            弹框标题
	 * @param message
	 *            弹框消息内容
	 * @param positiveButton
	 *            弹框单按钮文字
	 * @param dialogClickListener
	 *            弹框按钮响应事件
	 */
	public void showAlertDialog(String title, String message,
			String positiveButton,
			DialogInterface.OnClickListener dialogClickListener) {
		new AlertDialog.Builder(context).setCancelable(false).setTitle(title)
				.setMessage(message)
				.setPositiveButton(positiveButton, dialogClickListener).show();
	}

	/**
	 * 带点击事件的双按钮AlertDialog
	 * 
	 * @param title
	 *            弹框标题
	 * @param message
	 *            弹框消息内容
	 * @param positiveButton
	 *            弹框第一个按钮的文字
	 * @param negativeButton
	 *            弹框第二个按钮的文字
	 * @param positiveClickListener
	 *            弹框第一个按钮的单击事件
	 * @param negativeClickListener
	 *            弹框第二个按钮的单击事件
	 */
	public void showAlertDialog(String title, String message,
			String positiveButton, String negativeButton,
			DialogInterface.OnClickListener positiveClickListener,
			DialogInterface.OnClickListener negativeClickListener) {
		new AlertDialog.Builder(context).setCancelable(false).setTitle(title)
				.setMessage(message)
				.setPositiveButton(positiveButton, positiveClickListener)
				.setNegativeButton(negativeButton, negativeClickListener)
				.show();

	}

	/**
	 * 不带点击事件的消息弹出框
	 * 
	 * @param title
	 *            弹框标题
	 * @param message
	 *            弹框消息内容
	 * @param positiveButton
	 *            弹框按钮文字
	 */
	public void showAlertDialog(String title, String message,
			String positiveButton) {
		new AlertDialog.Builder(context)
				// 设置按系统返回键的时候按钮弹窗不取消
				.setCancelable(false)
				.setTitle(title)
				.setMessage(message)
				.setPositiveButton(positiveButton,
						new DialogInterface.OnClickListener() {

							@Override
							public void onClick(DialogInterface dialog,
									int which) {
								dialog.dismiss();
							}
						}).show();
	}

	/**
	 * 单选列表类型的弹出框
	 * 
	 * @param cancelable
	 *            设置是否能让用户主动取消弹窗
	 * 
	 * @param title
	 *            弹窗标题
	 * @param items
	 *            弹窗的列表数据源
	 * @param selectListener
	 *            弹窗列表选择事件
	 */
	public void showAlertDialog(boolean cancelable, String title,
			String items[], DialogInterface.OnClickListener selectListener) {
		new AlertDialog.Builder(context)
				// 设置按系统返回键的时候按钮弹窗不取消
				.setCancelable(cancelable).setTitle(title)
				.setItems(items, selectListener).show();
	}

	// ———————————————————————————————————————————————————————————获取当前系统时间———————————————————————————————————————————————————————————————————————————————————————————————————//
	/**
	 * 获取当前系统时间
	 * 
	 * @return 当前系统时间
	 */
	public String getTime() {
		/* 获取当前系统时间 */
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date curDate = new Date(System.currentTimeMillis());// 获取当前时间
		String time = sdf.format(curDate);
		return time;
	}
}


gridview的适配器GridViewAdapter代码:

public class GridViewAdapter extends BaseAdapter {

	private Context mContext;
	private List<Bitmap> list = new ArrayList<Bitmap>();
	
	public GridViewAdapter() {
		super();
	}
/**
 * 获取列表数据
 * @param list
 */
	public void setList(List<Bitmap> list){
		this.list = list;
		this.notifyDataSetChanged();
		Log.e(" 3333 ", this.list.size()+"");
	}
	
	public GridViewAdapter(Context mContext,List<Bitmap> list) {
		super();
		this.mContext = mContext;
		this.list = list;
		Log.e(" 2222 ", list.size()+"");
	}

	@Override
	public int getCount() {
		Log.e("  ", list.size()+"");
		if(list==null){
			return 1;
		}else if(list.size()==9){
			return 9;
		}else{
			return list.size()+1;
		}
	}

	@Override
	public Object getItem(int position) {
		if (list != null
				&& list.size() == 9)
		{
			return list.get(position);
		}

		else if (list == null || position - 1 < 0
				|| position > list.size())
		{
			return null;
		}
		else
		{
			return list.get(position - 1);
		}
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ViewHolder holder = null;
		if(convertView==null){
			convertView = LayoutInflater.from(mContext).inflate(R.layout.item_published_grida, null);
			holder = new ViewHolder();
			holder.item_grida_image = (ImageView) convertView.findViewById(R.id.item_grida_image);
			convertView.setTag(holder);
		}else{
			holder = (ViewHolder) convertView.getTag();
		}

		if (isShowAddItem(position))
		{
			holder.item_grida_image.setImageResource(R.drawable.btn_add_pic);
			holder.item_grida_image.setBackgroundResource(R.color.bg_gray);
			
		}
		else
		{
			holder.item_grida_image.setImageBitmap(list.get(position));
			holder.item_grida_image.setBackgroundResource(R.color.bg_gray);
		}
		return convertView;
	}
	/**
	 * 判断当前下标是否是最大值
	 * @param position  当前下标
	 * @return
	 */
	private boolean isShowAddItem(int position)
	{
		int size = list == null ? 0 : list.size();
		return position == size;
	}
	
	class ViewHolder{
		ImageView item_grida_image;
	}

}

FileUtils的代码:

public class FileUtils {

	/**
	 * 生成文件夹路径
	 */
	public static String SDPATH = Environment.getExternalStorageDirectory()
			+ "/TEST_PY/";

	/**
	 * 将图片压缩保存到文件夹
	 * 
	 * @param bm
	 * @param picName
	 */
	public static void saveBitmap(Bitmap bm, String picName) {
		try {

			// 如果没有文件夹就创建一个程序文件夹
			if (!isFileExist("")) {
				File tempf = createSDDir("");
			}
			File f = new File(SDPATH, picName + ".JPEG");
			// 如果该文件夹中有同名的文件,就先删除掉原文件
			if (f.exists()) {
				f.delete();
			}
			FileOutputStream out = new FileOutputStream(f);
			bm.compress(Bitmap.CompressFormat.JPEG, 90, out);
			out.flush();
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 质量压缩 并返回Bitmap
	 * 
	 * @param image
	 *            要压缩的图片
	 * @return 压缩后的图片
	 */
	private Bitmap compressImage(Bitmap image) {

		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		image.compress(Bitmap.CompressFormat.JPEG, 100, baos);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
		int options = 100;
		while (baos.toByteArray().length / 1024 > 100) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
			baos.reset();// 重置baos即清空baos
			image.compress(Bitmap.CompressFormat.JPEG, options, baos);// 这里压缩options%,把压缩后的数据存放到baos中
			options -= 10;// 每次都减少10
		}
		ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());// 把压缩后的数据baos存放到ByteArrayInputStream中
		Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);// 把ByteArrayInputStream数据生成图片
		return bitmap;
	}

	/**
	 * 质量压缩
	 * 
	 * @param bitmap
	 * @param picName
	 */
	public static void compressImageByQuality(final Bitmap bitmap,
			String picName) {
		// 如果没有文件夹就创建一个程序文件夹
		if (!isFileExist("")) {
			try {
				File tempf = createSDDir("");
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		File f = new File(SDPATH, picName + ".JPEG");
		// 如果该文件夹中有同名的文件,就先删除掉原文件
		if (f.exists()) {
			f.delete();
		}

		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		int options = 100;
		// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
		bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);
		// 循环判断如果压缩后图片是否大于200kb,大于继续压缩
		while (baos.toByteArray().length / 1024 > 500) {
			// 重置baos即让下一次的写入覆盖之前的内容
			baos.reset();
			// 图片质量每次减少5
			options -= 5;
			// 如果图片质量小于10,则将图片的质量压缩到最小值
			if (options < 0)
				options = 0;
			// 将压缩后的图片保存到baos中
			bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);
			// 如果图片的质量已降到最低则,不再进行压缩
			if (options == 0)
				break;
		}
		// 将压缩后的图片保存的本地上指定路径中
		FileOutputStream fos;
		try {
			fos = new FileOutputStream(new File(SDPATH, picName + ".JPEG"));
			fos.write(baos.toByteArray());
			fos.flush();
			fos.close();
		} catch (FileNotFoundException e) {

			e.printStackTrace();
		} catch (IOException e) {

			e.printStackTrace();
		}
	}

	/**
	 * 创建文件夹
	 * 
	 * @param dirName
	 *            文件夹名称
	 * @return 文件夹路径
	 * @throws IOException
	 */
	public static File createSDDir(String dirName) throws IOException {
		File dir = new File(SDPATH + dirName);
		if (Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {
			System.out.println("createSDDir:" + dir.getAbsolutePath());
			System.out.println("createSDDir:" + dir.mkdir());
		}
		return dir;
	}

	/**
	 * 判断改文件是否是一个标准文件
	 * 
	 * @param fileName
	 *            判断的文件路径
	 * @return 判断结果
	 */
	public static boolean isFileExist(String fileName) {
		File file = new File(SDPATH + fileName);
		file.isFile();
		return file.exists();
	}

	/**
	 * 删除指定文件
	 * 
	 * @param fileName
	 */
	public static void delFile(String fileName) {
		File file = new File(SDPATH + fileName);
		if (file.isFile()) {
			file.delete();
		}
		file.exists();
	}

	/**
	 * 删除指定文件
	 * @param file
	 */
	public static void deleteFile(File file) {
		if (file.exists()) { // 判断文件是否存在
			if (file.isFile()) { // 判断是否是文件
				file.delete(); // delete()方法 你应该知道 是删除的意思;
			} else if (file.isDirectory()) { // 否则如果它是一个目录
				File files[] = file.listFiles(); // 声明目录下所有的文件 files[];
				for (int i = 0; i < files.length; i++) { // 遍历目录下所有的文件
					deleteFile(files[i]); // 把每个文件 用这个方法进行迭代
				}
			}
			file.delete();
		} else {
			Log.i("TAG", "文件不存在!");
		}
	}

	/**
	 * 删除指定文件夹中的所有文件
	 */
	public static void deleteDir() {
		File dir = new File(SDPATH);
		if (dir == null || !dir.exists() || !dir.isDirectory())
			return;
		
		for (File file : dir.listFiles()) {
			if (file.isFile())
				file.delete();
			else if (file.isDirectory())
				deleteDir();
		}
		dir.delete();
	}

	/**
	 * 判断是否存在该文件
	 * 
	 * @param path
	 *            文件路径
	 * @return
	 */
	public static boolean fileIsExists(String path) {
		try {
			File f = new File(path);
			if (!f.exists()) {
				return false;
			}
		} catch (Exception e) {

			return false;
		}
		return true;
	}

}


ImageTools的代码:

public final class ImageTools {

	/**
	 * Transfer drawable to bitmap
	 * 
	 * @param drawable
	 * @return
	 */
	public static Bitmap drawableToBitmap(Drawable drawable) {
		int w = drawable.getIntrinsicWidth();
		int h = drawable.getIntrinsicHeight();

		Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
				: Bitmap.Config.RGB_565;
		Bitmap bitmap = Bitmap.createBitmap(w, h, config);
		Canvas canvas = new Canvas(bitmap);
		drawable.setBounds(0, 0, w, h);
		drawable.draw(canvas);
		return bitmap;
	}

	/**
	 * Bitmap to drawable
	 * 
	 * @param bitmap
	 * @return
	 */
	public static Drawable bitmapToDrawable(Bitmap bitmap) {
		return new BitmapDrawable(bitmap);
	}

	/**
	 * Input stream to bitmap
	 * 
	 * @param inputStream
	 * @return
	 * @throws Exception
	 */
	public static Bitmap inputStreamToBitmap(InputStream inputStream)
			throws Exception {
		return BitmapFactory.decodeStream(inputStream);
	}

	/**
	 * Byte transfer to bitmap
	 * 
	 * @param byteArray
	 * @return
	 */
	public static Bitmap byteToBitmap(byte[] byteArray) {
		if (byteArray.length != 0) {
			return BitmapFactory
					.decodeByteArray(byteArray, 0, byteArray.length);
		} else {
			return null;
		}
	}

	/**
	 * Byte transfer to drawable
	 * 
	 * @param byteArray
	 * @return
	 */
	public static Drawable byteToDrawable(byte[] byteArray) {
		ByteArrayInputStream ins = null;
		if (byteArray != null) {
			ins = new ByteArrayInputStream(byteArray);
		}
		return Drawable.createFromStream(ins, null);
	}

	/**
	 * Bitmap transfer to bytes
	 * 
	 * @param byteArray
	 * @return
	 */
	public static byte[] bitmapToBytes(Bitmap bm) {
		byte[] bytes = null;
		if (bm != null) {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
			bytes = baos.toByteArray();
		}
		return bytes;
	}

	/**
	 * Drawable transfer to bytes
	 * 
	 * @param drawable
	 * @return
	 */
	public static byte[] drawableToBytes(Drawable drawable) {
		BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
		Bitmap bitmap = bitmapDrawable.getBitmap();
		byte[] bytes = bitmapToBytes(bitmap);
		return bytes;
	}

	/**
	 * Base64 to byte[]
//	 */
//	public static byte[] base64ToBytes(String base64) throws IOException {
//		byte[] bytes = Base64.decode(base64);
//		return bytes;
//	}
//
//	/**
//	 * Byte[] to base64
//	 */
//	public static String bytesTobase64(byte[] bytes) {
//		String base64 = Base64.encode(bytes);
//		return base64;
//	}

	/**
	 * Create reflection images
	 * 
	 * @param bitmap
	 * @return
	 */
	public static Bitmap createReflectionImageWithOrigin(Bitmap bitmap) {
		final int reflectionGap = 4;
		int w = bitmap.getWidth();
		int h = bitmap.getHeight();

		Matrix matrix = new Matrix();
		matrix.preScale(1, -1);

		Bitmap reflectionImage = Bitmap.createBitmap(bitmap, 0, h / 2, w,
				h / 2, matrix, false);

		Bitmap bitmapWithReflection = Bitmap.createBitmap(w, (h + h / 2),
				Config.ARGB_8888);

		Canvas canvas = new Canvas(bitmapWithReflection);
		canvas.drawBitmap(bitmap, 0, 0, null);
		Paint deafalutPaint = new Paint();
		canvas.drawRect(0, h, w, h + reflectionGap, deafalutPaint);

		canvas.drawBitmap(reflectionImage, 0, h + reflectionGap, null);

		Paint paint = new Paint();
		LinearGradient shader = new LinearGradient(0, bitmap.getHeight(), 0,
				bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff,
				0x00ffffff, TileMode.CLAMP);
		paint.setShader(shader);
		// Set the Transfer mode to be porter duff and destination in
		paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
		// Draw a rectangle using the paint with our linear gradient
		canvas.drawRect(0, h, w, bitmapWithReflection.getHeight()
				+ reflectionGap, paint);

		return bitmapWithReflection;
	}

	/**
	 * Get rounded corner images
	 * 
	 * @param bitmap
	 * @param roundPx
	 *            5 10
	 * @return
	 */
	public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, float roundPx) {
		int w = bitmap.getWidth();
		int h = bitmap.getHeight();
		Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
		Canvas canvas = new Canvas(output);
		final int color = 0xff424242;
		final Paint paint = new Paint();
		final Rect rect = new Rect(0, 0, w, h);
		final RectF rectF = new RectF(rect);
		paint.setAntiAlias(true);
		canvas.drawARGB(0, 0, 0, 0);
		paint.setColor(color);
		canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
		paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
		canvas.drawBitmap(bitmap, rect, rect, paint);

		return output;
	}

	/**
	 * Resize the bitmap
	 * 
	 * @param bitmap
	 * @param width
	 * @param height
	 * @return
	 */
	public static Bitmap zoomBitmap(Bitmap bitmap, int width, int height) {
		int w = bitmap.getWidth();
		int h = bitmap.getHeight();
		Matrix matrix = new Matrix();
		float scaleWidth = ((float) width / w);
		float scaleHeight = ((float) height / h);
		matrix.postScale(scaleWidth, scaleHeight);
		Bitmap newbmp = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
		return newbmp;
	}

	/**
	 * Resize the drawable
	 * @param drawable
	 * @param w
	 * @param h
	 * @return
	 */
	public static Drawable zoomDrawable(Drawable drawable, int w, int h) {
		int width = drawable.getIntrinsicWidth();
		int height = drawable.getIntrinsicHeight();
		Bitmap oldbmp = drawableToBitmap(drawable);
		Matrix matrix = new Matrix();
		float sx = ((float) w / width);
		float sy = ((float) h / height);
		matrix.postScale(sx, sy);
		Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height,
				matrix, true);
		return new BitmapDrawable(newbmp);
	}
	
	/**
	 * Get images from SD card by path and the name of image
	 * @param photoName
	 * @return
	 */
	public static Bitmap getPhotoFromSDCard(String path,String photoName){
		Bitmap photoBitmap = BitmapFactory.decodeFile(path + "/" +photoName +".png");
		if (photoBitmap == null) {
			return null;
		}else {
			return photoBitmap;
		}
	}
	
	/**
	 * Check the SD card 
	 * @return
	 */
	public static boolean checkSDCardAvailable(){
		return android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
	}
	
	/**
	 * Get image from SD card by path and the name of image
	 * @param fileName
	 * @return
	 */
	public static boolean findPhotoFromSDCard(String path,String photoName){
		boolean flag = false;
		
		if (checkSDCardAvailable()) {
			File dir = new File(path);
			if (dir.exists()) {
				File folders = new File(path);
				File photoFile[] = folders.listFiles();
				for (int i = 0; i < photoFile.length; i++) {
					String fileName = photoFile[i].getName().split("\\.")[0];
					if (fileName.equals(photoName)) {
						flag = true;
					}
				}
			}else {
				flag = false;
			}
//			File file = new File(path + "/" + photoName  + ".jpg" );
//			if (file.exists()) {
//				flag = true;
//			}else {
//				flag = false;
//			}
			
		}else {
			flag = false;
		}
		return flag;
	}
	
	/**
	 * Save image to the SD card 
	 * @param photoBitmap
	 * @param photoName
	 * @param path
	 */
	public static void savePhotoToSDCard(Bitmap photoBitmap,String path,String photoName){
		if (checkSDCardAvailable()) {
			File dir = new File(path);
			if (!dir.exists()){
				dir.mkdirs();
			}
			
			File photoFile = new File(path , photoName + ".jpg");
			FileOutputStream fileOutputStream = null;
			try {
				fileOutputStream = new FileOutputStream(photoFile);
				if (photoBitmap != null) {
					if (photoBitmap.compress(Bitmap.CompressFormat.JPEG, 90, fileOutputStream)) {
						fileOutputStream.flush();
//						fileOutputStream.close();
					}
				}
			} catch (FileNotFoundException e) {
				photoFile.delete();
				e.printStackTrace();
			} catch (IOException e) {
				photoFile.delete();
				e.printStackTrace();
			} finally{
				try {
					fileOutputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		} 
	}
	
	/**
	 * Delete the image from SD card
	 * @param context
	 * @param path
	 * file:///sdcard/temp.jpg
	 */
	public static void deleteAllPhoto(String path){
		if (checkSDCardAvailable()) {
			File folder = new File(path);
			File[] files = folder.listFiles();
			for (int i = 0; i < files.length; i++) {
				files[i].delete();
			}
		}
	}
	
	public static void deletePhotoAtPathAndName(String path,String fileName){
		if (checkSDCardAvailable()) {
			File folder = new File(path);
			File[] files = folder.listFiles();
			for (int i = 0; i < files.length; i++) {
				if (files[i].getName().split("\\.")[0].equals(fileName)) {
					files[i].delete();
				}
			}
		}
	}

}


效果图:


仿微信朋友圈发表图片拖拽删除功能 阅读详情

相关推荐

Android-DragDismissLayout仿微信朋友圈浏览大图下拉返回交互

DragDismissLayout:仿微信朋友圈浏览大图下拉返回交互

Android实现仿微信朋友圈发布动态拍照图库选择照片压缩显示保存缩略图点击缩略图删除对应文件等)附源码

原创作品,转载请注明出处: 最近项目需求中要用到类似微信朋友圈发布动态选择图片的UI效果,研究了一下,特来分享成果,多的不说来看代码。 Activity类 package com.whfp.circle_of_friends; import java.io.File; import java.io.FileNotFoundException; import java.io.IOEx

8724

仿微信上传照片拍照和相册都在gridview里,多选返回显示照片

仿微信上传照片拍照和相册都在gridview里,多选返回显示照片 第一页显示选中的多张照片,最后有加号,点加号跳转到相册gridview,第一张是拍照,选中多张照片确定返回第一个界面,选中照片gridview显示

2024很火的仿朋友圈PHP源码带后台

搭建网站需要修改/conn/conn.php配置文件,并导入数据库。后端:建议使用PHP 5.4+,推荐版本在PHP 5.5以下。前端:HTML + CSS + JavaScript。后台登录账号为admin,密码设定为123456。

egrhwd的博客 1122

仿微信选取图片发表朋友圈功能

一、思路 第一,图片拖拽位置互换/删除,参照第三方; 第二,图片用scrollview浏览,缩放用zoomToRect,不用CGAffineTransformScale; 其次,还要返回当前缩放图片 //放回当前缩放图片 - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { for (UIV...

weixin_30666943的博客 293

仿微信朋友圈网站源码 新增视频发布功能的PHP源码

仿微信朋友圈网站源码 新增视频发布功能的PHP源码

软希网分享源码的博客 1013

Android仿微信朋友圈5实现朋友圈列表

微信朋友圈网上有很多开源的例子,本文是自己手写,之前的几篇都是单个功能,感觉很零散,这次放出完整的点赞评论和朋友圈列表功能. 1.定义四种item类型,和后台接口匹配: 2.CircleAdapter实现代码: 部分核心代码截图: 完整代码: /** * @作者: njb * @时间: 2019/7/25 10:47 * @描述: 朋友圈适配器 */ public ...

u012556114的博客 1万+

android开发--仿微信朋友圈界面

话不多说,先来看两张效果图 看图片效果还凑合,就是“朋友圈”三个字和头像的动画过渡效果和微信朋友圈的实际效果还是有点差距,可以的话以后慢慢再优化吧,这里贴出相关的代码,可能部分代码比较多余,以后再做修改吧 一:界面布局代码: &lt;?xml version="1.0" encoding="utf-8"?&gt; &lt;android.support.design.widget....

James0703的博客 3万+

android图片选择控件(仿微信图片多选[附源码])

背景: 最近公司有一个项目需要支持手机本地图片的多选,就像微信那样的。 OK,不能调用系统的图片选择控件,那就自己写个吧,基本思路就是使用ContentProvider扫描手机中的图片,然后以Gridview的方式展示图片,同时为了保证能图片能快速加载,需要对图片进行缓存(内存缓存是必须的,由于本来就是本地的图片,暂时可以不用再在SD卡中缓存)。 ContentProvider扫描手机中的图

如竹的技术博 6409

Android 仿微信拍摄视频,相册选择图片实现(基本上全部适配)

首先集成两个lib库 compile 'com.github.f15997123593.fzqLib:cameralib:v4.0' compile 'com.github.f15997123593.fzqLib:takephoto_library:v4.0' 然后添加权限, <uses-permission android:name="android.permissio...

fengzhiqi1993的博客 1149

Android kotlin 实现仿微信朋友圈全文与收起功能(RecyclerView+BRVAH3.0.6+androidx)

RecyclerView+BRVAH3.0.6+androidx

彬sir哥的博客 2428

安卓仿微信朋友圈动态数据加载(包括评论和点赞,以及动态详情页)

在项目里面使用到了类似微信朋友圈的功能,所以就研究了一下,大家先看看效果吧! 效果图一: 效果图二: 效果图三: 效果图四: 效果图五: 效果图六: 效果图七: 效果图八: 有需要学习后者使用的可以去下载源码: http://download.csdn.net/detail/u014388322/938

u014388322的专栏 4453

(flutter版本、kotlin版本)仿微信服务端代码-朋友圈

(flutter版本、kotlin版本)仿微信服务端代码-朋友圈

maoning20080808的专栏 760

Android平台的仿朋友圈源码

【源码】Android平台的仿朋友圈源码 朋友圈项目概述 .项目为Android Studio开发,软件为联网软件,基于Bmob后端服务器,主打纯原生代码,代码整体简洁,方法注释清晰,没有众多看不懂的类,适合新手,使得后期修改与创作更加简便。 .可发多图,无图,纯文字,也支持动态图发表与显示,支持登录注册,添加头像,大图浏览,裁剪,支持头像,评论,点赞,删除,分享,评论时会显示评论者的头像。...

qq_20918563的博客 4554

Android Studio完成微信朋友圈界面的设计

源码在最下面,基本上下载下来自己改改图片就可以用了首先看结果:这里面的圆角头像使用一个工具类实现的RounRectImageView代码来源于这个博主。

m0_56760139的博客 3116

2024 Lan仿朋友圈系统源码 开源版

支持前端用户注册 支持消息提示 用户注册可设置必须验证邮箱账号(可防止部分用户恶意注册)支持匿名发布(可做表白墙)推荐安装环境Nginx ≥1.22 PHP =7.4 MySQL ≥5.6。访问 https://你的域名/install 进行安装。可用于表白墙微商相册,商品图册等。

502

2023 仿朋友圈源码 带后台

搭建网站需要修改/conn/conn.php配置文件,并导入数据库。后端:建议使用PHP 5.4+,推荐版本在PHP 5.5以下。前端:HTML + CSS + JavaScript。后台登录账号为admin,密码设定为123456。

senteym的博客 569
上一篇: android 图片点击一下就放大到全屏,再点一下就回到原界面
下一篇: Android之 Animation动画的使用
小向光
博客等级 码龄14年 56粉丝 231原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值