图片选择器,遍历系统所有图片并显示,点击查看大图,长按选中,并将结果返回


字体颜色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 }
来源:https://www.cnblogs.com/Claire6649/p/5998183.html
