Last time I wrote about how the MVC framework can be used in a project to encapsulate the relevant base classes. In fact, to prepare for today’s article. Photo albums, also known as picture pickers, are used a lot in our project. But as far as I know, most programmers implement this functionality by referring to third-party frameworks. But if the UI has requirements, or we have special needs of our own, they may not be met.
So today I bring you the album made by myself. Not only give you a complete album, but also give you a set of methods to do the album. At the same time, we can learn a lot from it.
Before we start, it should be noted that the album relies on the MVC framework mentioned earlier, so there are two options. One is to build that framework first and then copy and paste it without feeling. Or do your own analysis, which can be done with an existing framework.
First set up anIM under RES
There are two classes
slide_down.xml
<? The XML version = "1.0" encoding = "utf-8"? > <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="200" android:fromXDelta="0" android:fromYDelta="0" android:toXDelta="0" android:toYDelta="100%"/> </set>Copy the code
slide_up.xml
<? The XML version = "1.0" encoding = "utf-8"? > <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="200" android:fromXDelta="0" android:fromYDelta="100%" android:toXDelta="0" android:toYDelta="0"/> </set>Copy the code
These are animations for selecting folders, added in styles.xml
<style name="dir_popupwindow_anim">
<item name="android:windowEnterAnimation">@anim/slide_up</item>
<item name="android:windowExitAnimation">@anim/slide_down</item>
</style>
Copy the code
Now the animation is ready. Next we are ready to lay out some images
These are the three pictures I prepared. The two pictures on the left are the logo ICONS on the upper right corner of the picture and the most right side of the folder selection box. The third is a placeholder image before the image is loaded.
We will add two permissions to the manifest file
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Copy the code
And then we have four layouts
activity_main.xml
This layout file is the layout of the album’s main page with the following code
<? The 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:orientation="vertical"> <GridView android:id="@+id/mGridView" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:cacheColorHint="@android:color/transparent" android:horizontalSpacing="3dp" android:listSelector="@android:color/transparent" android:numColumns="4" android:stretchMode="columnWidth" android:verticalSpacing="3dp" /> <RelativeLayout android:id="@+id/mBottomly" android:layout_width="match_parent" android:layout_height="45dp" android:background="#000"> <TextView android:id="@+id/mDirName" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" Android :layout_marginLeft="15dp" Android :text=" folder name "Android :textColor="# FFF" Android :textSize="14sp" /> <TextView android:id="@+id/mDirCount" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="15dp" Android :text=" # FFF "Android :textSize="14sp" /> </LinearLayout>Copy the code
If we need to change the style of the album, do so in this layout
Then there’s item_albums.xml, which is the layout of each photo grid
<? The 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="match_parent"> <ImageView android:layout_width="match_parent" android:layout_height="100dp" android:id="@+id/id_item_image" android:src="@mipmap/noimage" android:scaleType="centerCrop"/> <ImageButton android:layout_width="15dp" android:layout_height="15dp" android:id="@+id/id_item_select" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:layout_marginRight="3dp" android:layout_marginTop="3dp" android:background="@null" android:clickable="false" android:scaleType="fitXY" android:src="@mipmap/ic_unchoose"/> </RelativeLayout>Copy the code
And then item_popup_main.xml, which is the layout of the folder selection popup
<? The 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:padding="5dp"> <ImageView android:layout_width="100dp" android:layout_height="100dp" android:id="@+id/id_id_dir_item_image" android:layout_alignParentLeft="true" android:paddingTop="9dp" android:paddingBottom="17dp" android:paddingLeft="12dp" android:paddingRight="12dp" android:scaleType="fitXY" android:src="@mipmap/noimage" android:layout_centerVertical="true"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginLeft="10dp" android:layout_toRightOf="@id/id_id_dir_item_image" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/id_dir_item_name" Android :textSize="12sp" /> <TextView Android :layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/id_dir_item_count" android:layout_gravity="center" Android :text="1212 "Android :textSize=" 10SP" Android :textColor="#444"/> </LinearLayout> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="20sp" android:src="@mipmap/ic_choose"/> </RelativeLayout>Copy the code
Finally, our folder options popbox main layout popup_main.xml
<? The 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="match_parent" android:background="@android:color/white"> <ListView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/id_list_dir" android:divider="#eee3d9" android:dividerHeight="1px"/> </RelativeLayout>Copy the code
A fierce operation such as tiger, finally put our resources in order. Now you can start writing Java code in peace. The first is our image loading class
/**
* 图片加载类
* @author WaterWood
*/
public class ImageLoader {
/**
* 单例对象
*/
private static ImageLoader mInstance;
/**
* 图片缓存的核心对象
*/
private LruCache<String,Bitmap> mLruCache;
/**
* 线程池
*/
private ExecutorService mThreadPool;
/**
* 默认线程个数
*/
private static final int DEAFAULT_THREAD_COUNT = 1;
/**
* 队列方式
*/
private Type mType = Type.LIFO;
/**
* 任务队列
*/
private LinkedList<Runnable> mTaskQueue;
/**
* 后台轮询线程
*/
private Thread mPoolThread;
/**
* 与线程绑定的Handler,对线程中的Queue发送消息
*/
private Handler mPoolThreadHandler;
/**
* UI线程的一个Handler
*/
private Handler mUIHandler;
/**
* addTask使用mPoolThreadHandler的信号量,防止mPoolThreadHandler为空
*/
private Semaphore mSemaphorePoolThreadHandler = new Semaphore(0);
/**
* 是内部队列执行完,再从TaskQueue中取下一个
*/
private Semaphore mSemaphoreThreadPool;
/**
* 私有构造方法
*/
private ImageLoader(int threadCount,Type type){
init(threadCount,type);
}
/**
* 单例获取
* @return
*/
public static ImageLoader getInstance(){
if (mInstance == null){
synchronized (ImageLoader.class){
if (mInstance == null) {
mInstance = new ImageLoader(DEAFAULT_THREAD_COUNT,Type.LIFO);
}
}
}
return mInstance;
}
/**
* 单例获取
* @return
*/
public static ImageLoader getInstance(int threadCount,Type type){
if (mInstance == null){
synchronized (ImageLoader.class){
if (mInstance == null) {
mInstance = new ImageLoader(threadCount,type);
}
}
}
return mInstance;
}
/**
* 队列类型枚举
*/
public enum Type{
FIFO,LIFO
}
/**
* 一系列的初始化操作
* @param threadCount
* @param type
*/
private void init(int threadCount,Type type){
mPoolThread = new Thread(){
@Override
public void run() {
Looper.prepare();
mPoolThreadHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
//不断从线程池中取出一个任务进行执行
mThreadPool.execute(getTask());
try {
mSemaphoreThreadPool.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
mSemaphorePoolThreadHandler.release();
Looper.loop();
}
};
mPoolThread.start();
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheMemory = maxMemory/8;
mLruCache = new LruCache<String,Bitmap>(cacheMemory){
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getRowBytes()*value.getHeight();
}
};
mThreadPool = Executors.newFixedThreadPool(threadCount);
mTaskQueue = new LinkedList<Runnable>();
mType = type;
mSemaphoreThreadPool = new Semaphore(threadCount);
}
/**
* 根据path加载图片
* @param path
* @param imageView
*/
public void loadImage(final String path, final ImageView imageView){
imageView.setTag(path);
if (mUIHandler == null){
mUIHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
//获得图片,为imageView回调设置图片
ImgBeanHolder holder = (ImgBeanHolder) msg.obj;
Bitmap bm = holder.bitmap;
ImageView imageview = holder.imageView;
String path = holder.path;
//将path与getTag存储路径进行比较
if (imageview.getTag().toString().equals(path)){
imageview.setImageBitmap(bm);
}
}
};
}
Bitmap bm = getBitmapFromLruCache(path);
if (bm!=null){
//内存中有的情况
refreshBitmap(path,imageView,bm);
}else{
//内存中没有的情况
addTask(new Runnable(){
@Override
public void run() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
ImageSize imageSize = getImageViewSize(imageView);
Bitmap bm = decodeSampledBitmapFromPath(path,imageSize.width,imageSize.height);
addBitmapToLruCache(path,bm);
refreshBitmap(path,imageView,bm);
mSemaphoreThreadPool.release();
}
}
});
}
}
private Bitmap getBitmapFromLruCache(String key){
return mLruCache.get(key);
}
private class ImgBeanHolder{
Bitmap bitmap;
ImageView imageView;
String path;
}
private synchronized void addTask(Runnable runnable){
mTaskQueue.add(runnable);
try {
if (mPoolThreadHandler==null) {
mSemaphorePoolThreadHandler.acquire();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
mPoolThreadHandler.sendEmptyMessage(0x110);
}
private Runnable getTask(){
if (mType == Type.FIFO){
return mTaskQueue.removeFirst();
}else if (mType == Type.LIFO){
return mTaskQueue.removeLast();
}
return null;
}
/**
* 计算压缩尺寸
* @param imageView
* @return
*/
private ImageSize getImageViewSize(ImageView imageView){
ImageSize imageSize = new ImageSize();
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) imageView.getLayoutParams();
DisplayMetrics displayMetrics = imageView.getContext().getResources().getDisplayMetrics();
int width = imageView.getWidth();
if (width == 0){
width = lp.width;//获取imageview在layout中声明的宽度
}
if (width<=0){
width = getImageViewFieldValue(imageView,"mMaxWidth");
}
if (width<=0){
width = displayMetrics.widthPixels;
}
int height = imageView.getHeight();
if (height == 0){
height = lp.height;//获取imageview在layout中声明的高度
}
if (height<=0){
height = getImageViewFieldValue(imageView,"mMaxHeight");
}
if (height<=0){
height = displayMetrics.heightPixels;
}
imageSize.width = width;
imageSize.height = height;
return imageSize;
}
private class ImageSize{
int width;
int height;
}
/**
* 将path转换为bimap带压缩
* @param path
* @param width
* @param height
* @return
*/
protected Bitmap decodeSampledBitmapFromPath(String path,int width,int height){
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path,options);
options.inSampleSize = caculateInSampleSize(options,width,height);
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(path,options);
return bitmap;
}
/**
* 计算压缩比
* @param options
* @param reqWidth
* @param reqHeight
* @return
*/
private int caculateInSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){
int width = options.outWidth;
int height = options.outHeight;
int inSampleSize = 1;
if (width>reqWidth || height > reqHeight){
int widthRadio = Math.round(width*1.0f/reqWidth);
int heightRadio = Math.round(height*1.0f/reqHeight);
inSampleSize = Math.max(widthRadio,heightRadio);
}
return inSampleSize;
}
/**
* 将bitmap加入内存缓存中
* @param path
* @param bm
*/
protected void addBitmapToLruCache(String path,Bitmap bm){
if (getBitmapFromLruCache(path) == null){
if (bm!=null){
mLruCache.put(path,bm);
}
}
}
/**
* 刷新图片
* @param path
* @param imageView
* @param bitmap
*/
private void refreshBitmap(String path,ImageView imageView,Bitmap bitmap){
Message message = Message.obtain();
ImgBeanHolder holder = new ImgBeanHolder();
holder.bitmap = bitmap;
holder.path = path;
holder.imageView = imageView;
message.obj = holder;
mUIHandler.sendMessage(message);
}
/**
* 通过反射获取任何对象的任何属性值
* @param object
* @param fieldName
* @return
*/
private static int getImageViewFieldValue(Object object,String fieldName){
try {
int value = 0;
Field field = ImageView.class.getDeclaredField(fieldName);
field.setAccessible(true);
int fieldValue = field.getInt(object);
if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE){
value = fieldValue;
}
return value;
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return 0;
}
}
Copy the code
Next comes the images folder entity
Public class FolderBean {/** * folder path */ private String dir; /** * private String firstImgPath; /** * private String name; /** * private int count; public String getDir() { return dir; } public void setDir(String dir) { this.dir = dir; int lastIndexOf = this.dir.lastIndexOf("/"); this.name = this.dir.substring(lastIndexOf+1); } public String getFirstImgPath() { return firstImgPath; } public void setFirstImgPath(String firstImgPath) { this.firstImgPath = firstImgPath; } public String getName() { return name; } public int getCount() { return count; } public void setCount(int count) { this.count = count; }}Copy the code
Image main interface GridView Adapter
public class ImageAdapter extends BaseAdapter { private String mDirPath; private List<String> mImgPaths; private LayoutInflater mInflater; private Context context; private static Set<String> mSeletedImg = new HashSet<String>(); public ImageAdapter(Context context, List<String> mDatas, String dirPath){ this.context = context; this.mDirPath = dirPath; this.mImgPaths = mDatas; mInflater = LayoutInflater.from(context); } @Override public int getCount() { return mImgPaths.size(); } @Override public Object getItem(int position) { return mImgPaths.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; if (convertView == null){ convertView = mInflater.inflate(R.layout.item_album,parent,false); viewHolder = new ViewHolder(); viewHolder.mImg = convertView.findViewById(R.id.id_item_image); viewHolder.mSelect = convertView.findViewById(R.id.id_item_select); / / here according to the size of the mobile phone size change on image int widthAndHeight = (CommonUtils. GetScreenWidth (context) - CommonUtils. Dp2px (context, 9)) / 4. RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) viewHolder.mImg.getLayoutParams(); params.width = widthAndHeight; params.height = widthAndHeight; viewHolder.mImg.setLayoutParams(params); convertView.setTag(viewHolder); }else{ viewHolder = (ViewHolder) convertView.getTag(); } / / reset state viewHolder. MImg. SetImageResource (R.m ipmap. Noimage); viewHolder.mSelect.setImageResource(R.mipmap.ic_unchoose); viewHolder.mImg.setColorFilter(null); ImageLoader.getInstance(3, ImageLoader.Type.LIFO).loadImage(mDirPath+"/"+mImgPaths.get(position),viewHolder.mImg); final String filePath = mDirPath+"/"+mImgPaths.get(position); final ViewHolder finalViewHolder = viewHolder; viewHolder.mImg.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mseletedimg. contains(filePath)){// already selected mseletedimg. remove(filePath); finalViewHolder.mImg.setColorFilter(null); finalViewHolder.mSelect.setImageResource(R.mipmap.ic_unchoose); }else{// not selected mseletedimg. add(filePath); finalViewHolder.mImg.setColorFilter(Color.parseColor("#77000000")); finalViewHolder.mSelect.setImageResource(R.mipmap.ic_choose); } // notifyDataSetChanged(); }}); if (mSeletedImg.contains(filePath)){ viewHolder.mImg.setColorFilter(Color.parseColor("#77000000")); viewHolder.mSelect.setImageResource(R.mipmap.ic_choose); } return convertView; } private class ViewHolder{ ImageView mImg; ImageButton mSelect; }}Copy the code
Folder pop-up box Adapter
public class ListImageDirPopupWindow extends PopupWindow{ private int mWidth; private int mHeight; private View mConvertView; private ListView mListView; private List<FolderBean> mDatas; private OnDirSelectedListener mListener; public ListImageDirPopupWindow(Context context,List<FolderBean> datas) { calWidthAndHeight(context); mConvertView = LayoutInflater.from(context).inflate(R.layout.popup_main,null); mDatas = datas; setContentView(mConvertView); setWidth(mWidth); setHeight(mHeight); setFocusable(true); setTouchable(true); setOutsideTouchable(true); setBackgroundDrawable(new BitmapDrawable()); setTouchInterceptor(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_OUTSIDE){ dismiss(); return true; } return false; }}); initView(context); initEvent(); } private void initView(Context context) { mListView = mConvertView.findViewById(R.id.id_list_dir); mListView.setAdapter(new ListDirAdapter(context,mDatas)); } private void initEvent(){ mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<? > parent, View view, int position, long id) { if (mListener! =null){ mListener.onSelected(mDatas.get(position)); }}}); } private void calWidthAndHeight(Context context) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(outMetrics); mWidth = outMetrics.widthPixels; MHeight = (int) (outMetrics. HeightPixels * 0.7); } private class ListDirAdapter extends ArrayAdapter<FolderBean>{ private LayoutInflater mInflater; private List<FolderBean> mDatas; public ListDirAdapter(Context context,List<FolderBean> objects) { super(context,0,objects); mInflater = LayoutInflater.from(context); } @NonNull @Override public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { ViewHolder holder = null; if (convertView == null){ holder = new ViewHolder(); convertView = mInflater.inflate(R.layout.item_popup_main,parent,false); holder.mImg = convertView.findViewById(R.id.id_id_dir_item_image); holder.mDirName = convertView.findViewById(R.id.id_dir_item_name); holder.mDirCount = convertView.findViewById(R.id.id_dir_item_count); convertView.setTag(holder); }else{ holder = (ViewHolder) convertView.getTag(); } FolderBean bean = getItem(position); / / reset holder. MImg. SetImageResource (R.m ipmap. Noimage); ImageLoader.getInstance().loadImage(bean.getFirstImgPath(),holder.mImg); holder.mDirCount.setText(bean.getCount()+""); holder.mDirName.setText(bean.getName()); return convertView; } private class ViewHolder{ ImageView mImg; TextView mDirName; TextView mDirCount; } } public interface OnDirSelectedListener{ void onSelected(FolderBean folderBean); } public void setmListener(OnDirSelectedListener mListener) { this.mListener = mListener; }}Copy the code
Main interface Activity
Public class MainActivity extends WaterPermissionActivity<MainModel> implements MainCallback {/** */ private GridView mGridView; private RelativeLayout mBottomly; private TextView mDirName; private TextView mDirCount; /** * private List<String> mImgs; /** * private File mCurrentDir; /** * Number of files in the current folder */ private int mMaxCount; /** * private List<FolderBean> mFolderBeans = new ArrayList<>(); /** * private ProgressDialog mProgressDialog; Private ListImageDirPopupWindow mDirPopupWindow; /** * Private Handler mHandler = new Handler(){@override public void handleMessage(Message) msg) { if (msg.what == 0x110){ mProgressDialog.dismiss(); // Disappear dialog box data2View(); initDirPopupWindow(); }}}; /** * private ImageAdapter mImgAdapter; @Override protected MainModel getModelImp() { return new MainModel(this,this); } @Override protected int getContentLayoutId() { return R.layout.activity_main; } @Override protected void initWidget() { mGridView = findViewById(R.id.mGridView); mBottomly = findViewById(R.id.mBottomly); mDirName = findViewById(R.id.mDirName); mDirCount = findViewById(R.id.mDirCount); } @Override protected void initData() { if (! Environment. GetExternalStorageState (.) the equals (Environment MEDIA_MOUNTED)) {Toast. MakeText (this, "the memory card is not available!" ,Toast.LENGTH_SHORT).show(); return; } requestPermission(READ_EXTERNAL_STORAGE); mBottomly.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mDirPopupWindow.setAnimationStyle(R.style.dir_popupwindow_anim); MDirPopupWindow. ShowAsDropDown (mBottomly, 0, 0); lightOff(); }}); } @Override protected void doSDRead() { requestPermission(WRITE_EXTERNAL_STORAGE); } @override protected void doSDWrite() {ProgressDialog = progressdialog.show (this,null,"... ); new Thread(){ @Override public void run() { Uri mImgUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; ContentResolver cr = MainActivity.this.getContentResolver(); Cursor cursor = cr.query(mImgUri,null,MediaStore.Images.Media.MIME_TYPE+"=? or "+MediaStore .Images.Media.MIME_TYPE+"=?" ,new String[]{"image/jpeg","image/png"},MediaStore .Images.Media.DATE_MODIFIED); Set<String> mDirPaths = new HashSet<String>(); while (cursor.moveToNext()){ String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); File parentFile = new File(path).getParentFile(); if (parentFile == null){ continue; } String dirPath = parentFile.getAbsolutePath(); FolderBean folderBean = null; if (mDirPaths.contains(dirPath)){ continue; }else{// Mdirpaths.add (dirPath) was not detected before the current folder; folderBean = new FolderBean(); folderBean.setDir(dirPath); folderBean.setFirstImgPath(path); } if (parentFile.list() == null){ continue; } int picSize = parentFile.list(new FilenameFilter() { @Override public boolean accept(File dir, String filename) { if (filename.endsWith(".jpg") || filename.endsWith(".jpeg") || filename.endsWith(".png")){ return true; } return false; } }).length; folderBean.setCount(picSize); mFolderBeans.add(folderBean); if (picSize > mMaxCount){ mMaxCount = picSize; mCurrentDir = parentFile; } } cursor.close(); mHandler.sendEmptyMessage(0x110); } }.start(); } protected void data2View(){if (mCurrentDir == null){toast.maketext (this," no images ", toast.length_short).show(); return; } mImgs = Arrays.asList(mCurrentDir.list()); mImgAdapter = new ImageAdapter(this,mImgs,mCurrentDir.getAbsolutePath()); mGridView.setAdapter(mImgAdapter); mDirCount.setText(mMaxCount+""); mDirName.setText(mCurrentDir.getName()); } private void initDirPopupWindow(){ mDirPopupWindow = new ListImageDirPopupWindow(this,mFolderBeans); mDirPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() { @Override public void onDismiss() { lightOn(); }}); mDirPopupWindow.setmListener(new ListImageDirPopupWindow.OnDirSelectedListener() { @Override public void onSelected(FolderBean folderBean) { mCurrentDir = new File(folderBean.getDir()); mImgs = Arrays.asList(mCurrentDir.list(new FilenameFilter() { @Override public boolean accept(File dir, String filename) { if (filename.endsWith(".jpg") ||filename.endsWith(".jpeg") ||filename.endsWith(".png")){ return true; } return false; }})); mImgAdapter = new ImageAdapter(MainActivity.this,mImgs,mCurrentDir.getAbsolutePath()); mGridView.setAdapter(mImgAdapter); mDirCount.setText(mImgs.size()+""); mDirName.setText(folderBean.getName()); mDirPopupWindow.dismiss(); }}); } private void lightOn(){ WindowManager.LayoutParams lp = getWindow().getAttributes(); Lp. Alpha = 1.0 f; getWindow().setAttributes(lp); } private void lightOff(){ WindowManager.LayoutParams lp = getWindow().getAttributes(); Lp. Alpha = 0.3 f; getWindow().setAttributes(lp); }}Copy the code
Callback and Model are omitted here.
So we can make a complete album without feeling, isn’t it very convenient? Time is limited, we can analyze the knowledge points. I can use a lot of them, and I will break them down and write separate blogs for use.