图片选择器,遍历系统所有图片并显示,点击查看大图,长按选中,并将结果返回
字体颜色res/color建立text_selecor.xml
1 <selector xmlns:android="http://schemas.android.com/apk/res/android"> 2 <item android:color="@android:color/white" android:state_enabled="true"/> 3 <item android:color="@android:color/darker_gray" android:state_enabled="false"/> 4 </selector>
图片选择按钮
1 <selector xmlns:android="http://schemas.android.com/apk/res/android"> 2 <item android:state_checked="true" android:drawable="@mipmap/sel_check"/> 3 <item android:state_checked="false" android:drawable="@mipmap/sel_nor"/> 4 </selector>
遍历之后将所有图片显示
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:layout_width="match_parent" 3 android:background="@android:color/background_dark" 4 android:layout_height="match_parent"> 5 <ImageView 6 android:id="@+id/iv_img" 7 android:layout_width="match_parent" 8 android:layout_height="match_parent" 9 android:scaleType="centerCrop" 10 android:layout_margin="10dp" 11 android:src="@mipmap/camera"/> 12 <CheckBox 13 android:id="@+id/cb_btn" 14 android:layout_margin="15dp" 15 android:layout_width="wrap_content" 16 android:layout_height="wrap_content" 17 android:layout_alignParentRight="true" 18 android:button="@drawable/item_selector"/> 19 20 </RelativeLayout>
1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:id="@+id/activity_main" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:orientation="vertical" 7 tools:context="com.example.lesson10_picselectordemo.MainActivity"> 8 9 <RelativeLayout 10 android:layout_width="match_parent" 11 android:layout_height="wrap_content" 12 android:background="@android:color/holo_blue_dark" 13 android:padding="10dp"> 14 15 <TextView 16 android:layout_width="wrap_content" 17 android:layout_height="wrap_content" 18 android:layout_centerHorizontal="true" 19 android:text="图片选择" 20 android:textColor="@android:color/white" 21 android:textSize="18sp" /> 22 23 <TextView 24 android:id="@+id/tv_finish" 25 android:layout_width="wrap_content" 26 android:layout_height="wrap_content" 27 android:layout_alignParentRight="true" 28 android:enabled="false" 29 android:text="完成" 30 android:textColor="@color/text_selector" /> 31 32 </RelativeLayout> 33 34 <GridView 35 android:id="@+id/gv_image" 36 android:layout_width="match_parent" 37 android:layout_height="wrap_content" 38 android:numColumns="4"/> 39 </LinearLayout>
适配器,当适配数据类型不确定时,可以使用泛型.继承BaseAdapter都要重写那几个方法,这里将他们抽出来
1 /** 2 * 适配数据类型不确定,可以使用泛型 3 * 也可以是使用extends限定泛型,比如接口IGetName有个getName()方法,只要T继承IGetName实现方法,就可以使用该方法 4 * Created by Administrator on 2016/10/24 0024. 5 */ 6 7 public abstract class ListItemAdapter<T> extends BaseAdapter { 8 9 //适配器需要上下文,数据 10 //使用ptotected修饰符,使子类也可以用 11 protected Context mContext; 12 protected List<T> mList; 13 14 public ListItemAdapter(Context mContext,List<T> mList){ 15 this.mContext = mContext; 16 this.mList = mList; 17 } 18 19 @Override 20 public int getCount() { 21 return mList.size(); 22 } 23 24 @Override 25 public T getItem(int position) { 26 return mList.get(position); 27 } 28 29 @Override 30 public long getItemId(int position) { 31 return position; 32 } 33 }
然后ImageAdapter只要继承ListItemAdapter重写getView即可
1 public class ImageAdapter extends ListItemAdapter<File> { 2 3 private boolean select = false; 4 5 public void open(int position){ 6 select = true; 7 booleanArray.put(position,true); 8 if(onImageCheckedListener != null){ 9 onImageCheckedListener.onImageChecked(true); 10 } 11 this.notifyDataSetChanged(); 12 } 13 14 public void close(){ 15 select = false; 16 booleanArray.clear(); 17 this.notifyDataSetChanged(); 18 } 19 20 public ImageAdapter(Context mContext, List<File> mList) { 21 super(mContext, mList); 22 } 23 24 @Override 25 public int getCount() { 26 //多出来的第一张为照相机,点击进入照相机 27 return super.getCount()+1; 28 } 29 30 31 /** 32 * 这里布局重用,使用checkbox会导致很多问题, 33 * 勾选了一个,下拉之后发现下面也被勾选了一个 34 * 这时,我们可以使用HashMap<Integer,Boolean>,是否被勾选 35 * 36 * 这里推荐使用另外一个类SparseBooleanArray 37 * 38 * @param position 39 * @param convertView 40 * @param parent 41 * @return 42 */ 43 SparseBooleanArray booleanArray = new SparseBooleanArray(); 44 45 public SparseBooleanArray getBooleanArray() { 46 return booleanArray; 47 } 48 49 @Override 50 public View getView(final int position, View convertView, ViewGroup parent) { 51 ViewHolder viewHolder; 52 if(convertView == null){ 53 convertView = View.inflate(mContext,R.layout.item_image,null); 54 viewHolder = new ViewHolder(convertView); 55 convertView.setTag(viewHolder); 56 } 57 58 viewHolder = (ViewHolder) convertView.getTag(); 59 60 if(position == 0){ 61 //照相机 62 viewHolder.iv_img.setImageResource(R.mipmap.camera); 63 viewHolder.cb_btn.setVisibility(View.GONE); 64 }else{ 65 66 //设置图片 67 viewHolder.iv_img.setImageURI(Uri.fromFile(mList.get(position - 1))); 68 69 if(select) { 70 viewHolder.cb_btn.setVisibility(View.VISIBLE); 71 //是否需要勾选呢? 72 Boolean b = booleanArray.get(position); 73 if (b == null || b == false) { 74 viewHolder.cb_btn.setChecked(false); 75 } else { 76 viewHolder.cb_btn.setChecked(true); 77 } 78 79 80 //checkbox不能设置onCheckChange监听,因为上面setChecked导致下面isCheck也会跟着变化 81 /*viewHolder.cb_btn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { 82 @Override 83 public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { 84 booleanArray.put(position,isChecked); 85 } 86 });*/ 87 viewHolder.cb_btn.setOnClickListener(new View.OnClickListener() { 88 @Override 89 public void onClick(View v) { 90 //position有可能不存在,为空,这里必须给Boolean 91 Boolean b = booleanArray.get(position); 92 if (b == null || b == false) { 93 b = true; 94 } else { 95 b = false; 96 } 97 booleanArray.put(position, b); 98 99 //判断所有boolean ,如果没有一个true,则关闭 100 for (int i = 0; i <booleanArray.size() ; i++) { 101 //i一定存在,所以可以给boolean 102 boolean isChecked = booleanArray.get(booleanArray.keyAt(i)); 103 if(isChecked){ 104 //说明有被勾选的值 105 if(onImageCheckedListener != null){ 106 onImageCheckedListener.onImageChecked(true); 107 } 108 return; 109 } 110 } 111 //没有被勾选的值, 112 if(onImageCheckedListener != null) 113 onImageCheckedListener.onImageChecked(false); 114 //关闭 115 close(); 116 } 117 }); 118 }else { 119 viewHolder.cb_btn.setVisibility(View.GONE); 120 } 121 } 122 return convertView; 123 } 124 125 //回调方法 126 //写在需要执行方法的地方 127 //实现,在需要返回的地方 128 public interface OnImageCheckedListener{ 129 void onImageChecked(boolean b); 130 } 131 132 private OnImageCheckedListener onImageCheckedListener; 133 134 //alt + insert 135 public void setOnImageCheckedListener(OnImageCheckedListener onImageCheckedListener) { 136 this.onImageCheckedListener = onImageCheckedListener; 137 } 138 139 140 class ViewHolder{ 141 ImageView iv_img; 142 CheckBox cb_btn; 143 144 public ViewHolder(View convertView){ 145 146 iv_img = (ImageView) convertView.findViewById(R.id.iv_img); 147 int width = mContext.getResources().getDisplayMetrics().widthPixels / 4 -2; 148 RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width,width); 149 iv_img.setLayoutParams(params); 150 cb_btn = (CheckBox) convertView.findViewById(R.id.cb_btn); 151 } 152 } 153 }
点击查看大图
1 public class ShowBigImage extends AppCompatActivity{ 2 3 @Override 4 protected void onCreate(@Nullable Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 ImageView img = new ImageView(this); 7 8 File file = (File) getIntent().getSerializableExtra("img"); 9 img.setImageURI(Uri.fromFile(file)); 10 setContentView(img); 11 } 12 }
1 public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener, AdapterView.OnItemLongClickListener, ImageAdapter.OnImageCheckedListener, View.OnClickListener { 2 private static final int CAMERA_CODE = 1; 3 //SD卡所有图片 4 List<File> filesList = new ArrayList<>(); 5 6 ProgressDialog dialog; 7 8 GridView gv_image; 9 TextView tv_finish; 10 ImageAdapter adapter; 11 12 @Override 13 protected void onCreate(Bundle savedInstanceState) { 14 super.onCreate(savedInstanceState); 15 setContentView(R.layout.activity_main); 16 17 //加载数据 18 loadData(); 19 //初始化视图 20 initView(); 21 22 } 23 24 private void initView() { 25 gv_image = (GridView) findViewById(R.id.gv_image); 26 tv_finish = (TextView) findViewById(R.id.tv_finish); 27 adapter = new ImageAdapter(this,filesList); 28 tv_finish.setOnClickListener(this); 29 adapter.setOnImageCheckedListener(this); 30 gv_image.setAdapter(adapter); 31 //点击图片查看大图 32 gv_image.setOnItemClickListener(this); 33 //长按选择图片 34 gv_image.setOnItemLongClickListener(this); 35 } 36 37 public ProgressDialog showDialog(){ 38 //显示Dialog 39 dialog = new ProgressDialog(this); 40 dialog.setTitle("加载数据"); 41 dialog.setMessage("正在加载数据,请稍等..."); 42 dialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 43 dialog.show(); 44 45 return dialog; 46 } 47 48 public void loadData(){ 49 dialog = showDialog(); 50 51 //数据加载不能阻塞UI 52 //在子线程中加载 53 new Thread(){ 54 @Override 55 public void run() { 56 super.run(); 57 //开始递归遍历SD卡根目录 58 /*public static File getExternalStorageDirectory() { 59 throwIfUserRequired(); 60 return sCurrentUser.getExternalDirs()[0];//获取第0张SD卡如果想要其他SD卡,只要重写这个方法即可 61 }*/ 62 File SDDir = Environment.getExternalStorageDirectory(); 63 getFiles(SDDir); 64 65 //数据加载完毕,要关闭Dialog 66 runOnUiThread(new Runnable() { 67 @Override 68 public void run() { 69 dialog.dismiss(); 70 //刷新适配器 71 adapter.notifyDataSetChanged(); 72 } 73 }); 74 } 75 }.start(); 76 } 77 78 public void getFiles(File dir){ 79 File[] files = dir.listFiles(); 80 81 if(files == null){ 82 return; 83 } 84 85 //开始遍历 86 for (File file : files) { 87 if(file.isDirectory()){ 88 getFiles(file); 89 }else{ 90 if(file.getName().endsWith("jpg") || file.getName().endsWith("png")){ 91 filesList.add(file); 92 } 93 } 94 } 95 } 96 97 File cameraFile; 98 @Override 99 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 100 //点击查看大图 101 if(position == 0){ 102 //getAbsolutePath默认没有带"/" 103 cameraFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/DCIM/"+System.currentTimeMillis()+".png"); 104 //打开照相机 105 Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); 106 //图片保存位置 107 intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cameraFile)); 108 startActivityForResult(intent,CAMERA_CODE); 109 110 }else{ 111 //打开大图 112 File file = filesList.get(position - 1); 113 //带数据点开大图 114 Intent intent = new Intent(this,ShowBigImage.class); 115 intent.putExtra("img",file); 116 startActivity(intent); 117 } 118 119 } 120 121 @Override 122 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 123 super.onActivityResult(requestCode, resultCode, data); 124 if(requestCode == requestCode && resultCode == RESULT_OK){ 125 //照相机的图片永远放在第一个 126 filesList.add(0,cameraFile); 127 adapter.notifyDataSetChanged(); 128 } 129 } 130 131 @Override 132 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { 133 //长按选择图片 134 //照相机不能长按 135 if(position == 0){ 136 return false; 137 }else{ 138 adapter.open(position); 139 } 140 141 return true; 142 } 143 144 @Override 145 public void onImageChecked(boolean b) { 146 //b代表适配器中有没有被勾选的值 147 tv_finish.setEnabled(b); 148 } 149 150 @Override 151 public void onClick(View v) { 152 //选择的图片 153 //不能使用泛型,ArrayList才实现了序列化,List没有实现 154 ArrayList<File> resultList = new ArrayList<>(); 155 //点击完成,带参返回 156 //需要知道哪些数据被选中 157 //通过是是适配器中的boolArray的为true的选中项来加载file 158 SparseBooleanArray booleanArray = adapter.getBooleanArray(); 159 for (int i = 0; i <booleanArray.size() ; i++) { 160 boolean isSelected = booleanArray.get(booleanArray.keyAt(i)); 161 if(isSelected){ 162 int position = booleanArray.keyAt(i); 163 //剔除掉第一张照相机图片 164 resultList.add(filesList.get(position-1)); 165 } 166 } 167 Intent intent = new Intent(); 168 intent.putExtra("list",resultList); 169 //返回数据 170 setResult(RESULT_OK,intent); 171 finish(); 172 } 173 }
AndroidManifest.xml设置权限,注册活动
设置intent-filter <action> 并设置出口exported
1 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 2 package="com.example.lesson10_picselectordemo"> 3 4 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 5 6 <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" 7 android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> 8 <activity android:name=".MainActivity" 9 android:exported="true"> 10 <intent-filter> 11 <action android:name="SelectPicture"/> 12 <action android:name="android.intent.action.MAIN" /> 13 <category android:name="android.intent.category.DEFAULT"/> 14 <category android:name="android.intent.category.LAUNCHER" /> 15 </intent-filter> 16 </activity> 17 <activity android:name=".ShowBigImage"/> 18 </application> 19 20 </manifest>
测试类
点击Buttong,打开图片选择器
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:id="@+id/activity_main" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 tools:context="com.example.lesson10_picselectordemotest.MainActivity"> 7 8 <Button 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:onClick="toPicSelectorDemo" 12 android:layout_centerInParent="true" 13 android:text="图片选择器启动另一个Module" /> 14 </RelativeLayout>
1 public class MainActivity extends AppCompatActivity { 2 3 @Override 4 protected void onCreate(Bundle savedInstanceState) { 5 super.onCreate(savedInstanceState); 6 setContentView(R.layout.activity_main); 7 } 8 9 public void toPicSelectorDemo(View v){ 10 11 startActivityForResult(new Intent("SelectPicture"),1); 12 } 13 14 @Override 15 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 16 super.onActivityResult(requestCode, resultCode, data); 17 if(resultCode == RESULT_OK){ 18 ArrayList<File> file = (ArrayList<File>) data.getSerializableExtra("list"); 19 Toast.makeText(this,file.toString(),Toast.LENGTH_SHORT).show(); 20 } 21 } 22 }