高仿微信本地图片选择器

在项目中经常需要选择手机系统里面的图片,但是直接启动系统页面,只能选择单张图片,而且UI不受我们自己控制,不灵活,所以这里仿照微信的大致效果,做一个图片选择器

加载图片的时候,使用的开源项目Universal-Image-Loader,示例代码如下:

MyApplication类:

package com.home.imgscan;

import android.app.Application;
import android.content.Context;

import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;

public class MyApplication extends Application {

	@Override
	public void onCreate() {
		super.onCreate();
		initImageLoader(this,false);
	}

	/**
	 * 初始化ImageLoader(在Application的onCreate()中调用)
	 *
	 * @param context
	 *            上下文对象
	 * @param isDebug
	 *            是否启用Debug模式
	 */
	public static void initImageLoader(Context context, boolean isDebug) {
		// 创建默认的ImageLoader配置参数
		ImageLoaderConfiguration.Builder builder = new ImageLoaderConfiguration.Builder(
				context);
		if (isDebug) {
			builder.writeDebugLogs();
		}
		ImageLoaderConfiguration configuration = builder.build();
		ImageLoader.getInstance().init(configuration);
	}

}

主页面:MainActivity:

package com.home.imgscan;

import java.util.ArrayList;
import java.util.List;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.GridView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener {

	// GridView控件
	private GridView gridView;

	// 进度对话框
	private ProgressDialog mProgressDialog;

	// 本地图片路径集合
	private List<String> list = new ArrayList<String>();

	// 加载完成标示
	private final static int SCAN_OK = 1;

	// 适配器
	private ScanAdapter adapter;

	// 发送按钮
	private TextView sendView;

	@SuppressLint("HandlerLeak")
	private Handler mHandler = new Handler() {

		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			switch (msg.what) {
			case SCAN_OK:
				mProgressDialog.dismiss();
				setAdapter();
				break;
			}
		}

	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.main);
		initView();
		getImages();
	}

	/**
	 * 初始化页面控件
	 */
	private void initView() {
		gridView = (GridView) findViewById(R.id.main_grid);

		// 发送按钮
		sendView = (TextView) findViewById(R.id.main_btn_send);
		sendView.setOnClickListener(this);
	}

	/**
	 * 设置适配器
	 */
	private void setAdapter() {
		if (adapter == null) {
			adapter = new ScanAdapter(MainActivity.this, list);
			gridView.setAdapter(adapter);
		} else {
			adapter.setList(list);
			adapter.notifyDataSetChanged();
		}
	}

	/**
	 * 获取手机上的图片
	 */
	private void getImages() {
		if (!Environment.getExternalStorageState().equals(
				Environment.MEDIA_MOUNTED)) {
			Toast.makeText(this, "SD卡不存在", Toast.LENGTH_SHORT).show();
			return;
		}

		mProgressDialog = ProgressDialog.show(this, null, "正在加载请稍后...");

		new Thread(new Runnable() {

			@Override
			public void run() {
				Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
				ContentResolver mContentResolver = MainActivity.this
						.getContentResolver();

				Cursor mCursor = mContentResolver.query(mImageUri, null,
						MediaStore.Images.Media.MIME_TYPE + "=? or "
								+ MediaStore.Images.Media.MIME_TYPE + "=?",
						new String[] { "image/jpeg", "image/png" },
						MediaStore.Images.Media.DATE_MODIFIED);

				while (mCursor.moveToNext()) {
					String path = mCursor.getString(mCursor
							.getColumnIndex(MediaStore.Images.Media.DATA));
					list.add(path);
				}

				mCursor.close();

				mHandler.sendEmptyMessage(SCAN_OK);

			}
		}).start();

	}

	/**
	 * 更新发送按钮
	 */
	public void updateSendBtn() {
		List<String> hasCheckedList = adapter.getHasCheckList();
		if (hasCheckedList == null || hasCheckedList.size() == 0) {
			sendView.setText("发送");
		} else {
			int size = hasCheckedList.size();
			sendView.setText("发送(" + size + "/9)");
		}
	}

	@Override
	public void onClick(View v) {
		if (v.getId() == R.id.main_btn_send) {
			List<String> hasCheckedList = adapter.getHasCheckList();
			if (hasCheckedList == null || hasCheckedList.size() == 0) {
				Toast.makeText(this, "请选择图片", Toast.LENGTH_SHORT).show();
				return;
			}
			// 发送。。。
		}
	}

}

自定义适配器ScanAdapter:

package com.home.imgscan;

import java.util.ArrayList;
import java.util.List;

import android.graphics.Bitmap;
import android.text.TextUtils;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.Toast;

import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.download.ImageDownloader.Scheme;

public class ScanAdapter extends BaseAdapter {
	private List<String> list;
	private LayoutInflater inflater;
	// 已经选择的图片本地路径集合
	private List<String> hasCheckList = new ArrayList<String>();
	private MainActivity activity;

	public ScanAdapter(MainActivity activity, List<String> list) {
		this.list = list;
		this.activity = activity;
		inflater = LayoutInflater.from(activity);
	}

	@Override
	public int getCount() {
		return list == null ? 0 : list.size();
	}

	@Override
	public Object getItem(int position) {
		return list.get(position);
	}

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

	@Override
	public View getView(int position, View convertView, ViewGroup arg2) {
		if (convertView == null) {
			convertView = inflater.inflate(R.layout.grid_content, null);
		}

		String path = list.get(position);

		// 选择框
		ImageView box = getAdapterView(convertView, R.id.grid_content_box, path);
		box.setOnClickListener(new MyOnClickListener());

		// 图片控件
		ImageView iv = getAdapterView(convertView, R.id.grid_content_iv, path);
		setLocalImg(iv, path);
		return convertView;
	}

	private class MyOnClickListener implements OnClickListener {

		@Override
		public void onClick(View v) {
			if (v.getId() != R.id.grid_content_box) {
				return;
			}
			String path = (String) v.getTag();
			if (TextUtils.isEmpty(path)) {
				return;
			}

			if (hasCheckList.contains(path)) {
				hasCheckList.remove(path);
				v.setBackgroundResource(R.drawable.box_unchecked);
			} else {
				if (hasCheckList.size() >= 9) {
					Toast.makeText(activity, "最多只能选择9张图片", Toast.LENGTH_SHORT)
							.show();
					return;
				}
				hasCheckList.add(path);
				v.setBackgroundResource(R.drawable.box_checked);
			}
			activity.updateSendBtn();
		}

	}

	@SuppressWarnings("unchecked")
	public <T extends View> T getAdapterView(View convertView, int id,
			Object tag) {
		SparseArray<View> viewHolder = null;
		try {
			if (convertView.getTag(R.id.view_holder) instanceof SparseArray<?>) {
				viewHolder = (SparseArray<View>) convertView
						.getTag(R.id.view_holder);
			}
		} catch (ClassCastException e) {
		}
		if (viewHolder == null) {
			viewHolder = new SparseArray<View>();
			convertView.setTag(R.id.view_holder, viewHolder);
			convertView.setTag(R.id.path, tag);
		}
		View childView = viewHolder.get(id);
		if (childView == null) {
			childView = convertView.findViewById(id);
			childView.setTag(tag);
			viewHolder.put(id, childView);
		}
		return (T) childView;
	}

	/**
	 * 加载本地图片
	 *
	 * @param imageView
	 *            图片ImageView控件
	 * @param imagePath
	 *            图片本地路径
	 */
	public static void setLocalImg(ImageView imageView, String imagePath) {

		// 显示图片的配置
		DisplayImageOptions.Builder builder = new DisplayImageOptions.Builder();
		builder.cacheInMemory(true).cacheOnDisk(true)
				.bitmapConfig(Bitmap.Config.RGB_565);

		DisplayImageOptions options = builder.build();

		ImageLoader.getInstance().displayImage(Scheme.FILE.wrap(imagePath),
				imageView, options);

	}

	public List<String> getList() {
		return list;
	}

	public void setList(List<String> list) {
		this.list = list;
	}

	public List<String> getHasCheckList() {
		return hasCheckList;
	}

	public void setHasCheckList(List<String> hasCheckList) {
		this.hasCheckList = hasCheckList;
	}

}

布局文件main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/background_dark" >

        <ImageView
            android:id="@+id/main_iv_back"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_margin="10dp"
            android:background="@drawable/back" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="图片"
            android:textColor="@android:color/white"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/main_btn_send"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginTop="10dp"
            android:background="@android:color/holo_green_light"
            android:padding="10dp"
            android:text="发送"
            android:textColor="@android:color/white"
            android:textSize="18sp" />
    </RelativeLayout>

    <GridView
        android:id="@+id/main_grid"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white"
        android:cacheColorHint="@android:color/transparent"
        android:gravity="center"
        android:horizontalSpacing="1dp"
        android:listSelector="@android:color/transparent"
        android:numColumns="3"
        android:scrollbars="none"
        android:stretchMode="columnWidth"
        android:verticalSpacing="1dp" >
    </GridView>

</LinearLayout>

布局文件grid_content.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@android:color/black" >

    <ImageView
        android:id="@+id/grid_content_iv"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:scaleType="centerCrop" />

    <ImageView
        android:id="@+id/grid_content_box"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="6dp"
        android:layout_marginTop="6dp"
        android:background="@drawable/box_unchecked" />

</RelativeLayout>

示例下载链接:http://download.csdn.net/detail/u010142437/8854871

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-03 14:56:11

高仿微信本地图片选择器的相关文章

Android 高仿微信图片选择器(瀑布流)

前言 在很多很多的项目中,都有选择本地图片的功能,现在就带大家做一个仿微信的图片选择器 1.和微信相比,由于博主是平板,微信在博主的平板中的图片是很模糊的,而我们的这个比微信的清晰,但是代价基本就是内存的多消耗,但是现在的收集基本上这点内存还是有的,图片也是经过压缩的 2.和鸿洋封装的相比,有些人可能会说和大神的有可比性么?我可以很直白的说这个图片选择器就是参考鸿洋大神以前封装的图片选择器,并且进行代码的分层.逻辑的重新梳理.优化显示效果.去除很多难懂的代码,用浅显易懂的代码实现之!,并且图片的

Android高仿微信图片选择上传工具

源码托管地址:https://github.com/SleepyzzZ/photo-selector 话不多说,先上效果图(高仿微信图片选择器): 图片选择界面: 图片预览界面: 批量上传图片: 实现的功能介绍: 1.图片异步加载,使用Glide开源库实现加载; 2.图片的预览界面,支持左右滑动,双击放大浏览; 3.图片批量上传,使用OkHttp来实现与Servlet服务器的通信; 使用方法(Android Studio): 新建工程,File->New->Import Module导入pho

android高仿微信拍照、多选、预览、删除(去除相片)相册功能

先声明授人与鱼不如授人与渔,只能提供一个思路,当然需要源码的同学可以私下有偿问我要源码:QQ:508181017 工作了将近三年时间了,一直没正儿八经的研究系统自带的相册和拍照,这回来个高仿微信的拍照.多选.预览.删除(去除相片)相册功能,之前开发的所有应用都带有这需求,但是一直都不实用!废话就不多说了,先来捋一下思路: 1.拍照能实时保存到本地并实时查询(不必用广播或者服务) 2.拍照保存到到自定义路径并根据不同文件夹显示文件夹下的相片 3.多选规定张数图片 4.用到的集合有: (1).所有相

Android 高仿微信实时聊天 基于百度云推送

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/38799363 ,本文出自:[张鸿洋的博客] 一直在仿微信界面,今天终于有幸利用百度云推送仿一仿微信聊天了~~~ 首先特别感谢:weidi1989分享的Android之基于百度云推送IM ,大家可以直接下载:省了很多事哈,本例中也使用了weidi的部分代码,凡是@author way的就是weidi1989的代码~~ 1.效果图 核心功能也就上面的两张图了~~~我拿着手机和模拟器

Android高仿微信头像裁剪

最近公司的APP很多用户反应无法上传头像,于是打算修改原来头像裁剪的代码.参考微信.QQ.唱吧头像裁剪的操作,决定就仿微信头像裁剪来上传用户头像,在Android大神鸿洋的一篇高仿微信头像的博客(博客地址结尾会贴出来)的基础上加了一些代码,加的代码主要增加如下的功能: 1.增加对大图的处理,缩放到我们裁剪框的大小. 2.裁剪后的图片保存到临时文件里,把临时文件的路径返回到需要处理的界面,因为在三星S4传byte数组返回数据时会闪退,传路径则正常. 3.对有些系统返回旋转过的图片进行处理. 这个功

Android ActionBar应用实战,高仿微信主界面的设计

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/26365683 经过前面两篇文章的学习,我想大家对ActionBar都已经有一个相对较为深刻的理解了.唯一欠缺的是,前面我们都只是学习了理论知识而已,虽然知识点已经掌握了,但是真正投入到项目实战当中时会不会掉链子还很难说.那么不用担心,本篇文章我就将带领大家一起进入ActionBar的应用实战,将理论和实践完美结合到一起. 如果你还没有看过我的前两篇文章,建议先去阅读一下 Andr

Android 高仿微信头像截取 打造不一样的自定义控件

转载请表明出处:http://blog.csdn.net/lmj623565791/article/details/39761281,本文出自:[张鸿洋的博客] 1.概述 前面已经写了关于检测手势识别的文章,如果不了解可以参考:Android 手势检测实战 打造支持缩放平移的图片预览效果(下).首先本篇文章,将对之前博客的ZoomImageView代码进行些许的修改与改善,然后用到我们的本篇博客中去,实现仿微信的头像截取功能,当然了,个人觉得微信的截取头像功能貌似做得不太好,本篇博客准备去其糟粕

Android 高仿微信头像截取 打造不一样的自己定义控件

转载请表明出处:http://blog.csdn.net/lmj623565791/article/details/39761281,本文出自:[张鸿洋的博客] 1.概述 前面已经写了关于检測手势识别的文章.假设不了解能够參考:Android 手势检測实战 打造支持缩放平移的图片预览效果(下).首先本篇文章,将对之前博客的ZoomImageView代码进行些许的改动与改善,然后用到我们的本篇博客中去,实现仿微信的头像截取功能.当然了.个人觉得微信的截取头像功能貌似做得不太好.本篇博客准备去其糟粕

iOS高仿微信完整源码,网易爱玩APP源码等

iOS精选源码 iOS一种弹出视图效果带动画 一个快速便捷.无侵入.可扩展的动画弹框库 高仿Elk - 旅行货币转换器 iOS内分享的界面.功能一体化解决方案 使用Olami sdk实现一个语音查询股票的iOS程序 iOS高仿微信完整项目源码 分段绘制折线指示图, 点击效果 最新环信推送封装 v3.0[附代码] 仿照网易爱玩APP APP启动视频 iOS优质博客 iOS 一行代码搞定 KVO 前言发现好久没有研究.学习iOS优秀开源代码,现在大部分时间都在写业务代码, 学习其他语言及一些杂七杂八