正如我的GitHub上的README上说的,偶然之间发现了一个接口,觉得挺有意思的,于是乎,就开始着手的写一个壁纸类应用了,其实之前就一直有这样的想法,但是奈何没有接口,我们先来看下这个项目在初期的时候的预览图




Android 壁纸预览解析_锁屏


这是写了三天的效果,但是这个其实只是一个完整的框架,后台又写了几天,算是把大部分的功能都完善了


Android 壁纸预览解析_ide_02


后来又坚持的修改了一下,最后推送到Gank上去了,到这里,我就可以慢慢的来修改这些小细节的东西了,我们来看下具体的实现步骤吧!

一.使用的开源

先来看下我的build.gradle,也就是项目目前所用到的东西

dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.1.0' testCompile 'junit:junit:4.12' //Material Design compile 'com.android.support:cardview-v7:25.0.1' compile 'com.android.support:appcompat-v7:25.0.1' compile 'com.android.support:design:25.0.1' //Retrofit2.0 compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0' //PhotoView compile 'com.github.chrisbanes:PhotoView:1.3.0' //Glide compile 'com.github.bumptech.glide:glide:3.6.1' //CircleImageView compile 'de.hdodenhof:circleimageview:2.1.0' //RxVolley compile 'com.kymjs.rxvolley:rxvolley:1.1.4' compile 'com.kymjs.rxvolley:okhttp:1.1.4' //JC Play compile 'fm.jiecao:jiecaovideoplayer:5.3'}

在这里,使用了Material Design就不多说了,网络解析我使用了两个库,一个是RxVolley,一个是Retrofit2.0,Retrofit2.0在天气模块进行了尝试,PhotoView还没有使用,但是图片肯定要进行缩放的,图片加载使用了Glide,圆形的头像CircleImageView,已经最后的节操播放器,因为我有准备加入小视频的模块,所有引入了这个源,但是目前还没有使用到,可以看到,其实我们真实的用到的东西并没有很多,但是你这个项目也不大,对吧!

二.项目架构

项目采用的是NavigationView + Fragment的组织架构去搭建的,这也是比较直观和流行的架构了可以看到


Android 壁纸预览解析_锁屏_03


项目很舒服,我的Fragment的切换策略采用的是show/hide的方式来处理的,其他倒没有没什么可说的

三.模块的具体实现

关于实现各功能的逻辑,我这里挑一些重点,其他的大家就自己去看Github了

1.首页

主页的实现是ViewPager的轮播加上一个GridView,外部通过一个ScrollView嵌套,这里有几个问题,首先,初始化后GridView会抢占焦点,这是因为两个滑动的冲突导致测量的问题,所有我一进去就手动的滑动到顶部

//滚动到顶部mHandler.post(new Runnable() { @Override public void run() { mScrollView.fullScroll(ScrollView.FOCUS_UP); }});

并且Gridview也无法计算,所以到导致只出现一个item的现象,这里我是重写了GridView,只需要更改他的测量方法

@Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); super.onMeasure(widthMeasureSpec, expandSpec); }

2.相册

相册采用了好几种的加载方式,首先,我会通过内容提供者去查询内存卡的图片

//获取本地相册 private void getAllImagePath() { Cursor cursor = getActivity().getContentResolver().query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null); //遍历相册 while (cursor.moveToNext()) { String path = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA)); //将图片路径添加到集合 paths.add(path); } cursor.close(); }

同时,因为采用了show/hide的形式,所以,我添加了一个监听

//视图改变 @Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if(!hidden){ getAllImagePath(); albumGridAdapter.notifyDataSetChanged(); } }

这样切换后也会去刷新,并且我加入了下拉加载SwipeRefreshLayout去做及时的处理

3.预览

这也是比较重要的环节,我们先看下截图


Android 壁纸预览解析_android_04


这里下面下面有几个操作的按钮,首先是分享,然后是点赞,这些没什么问题,这个设置壁纸,还有下载,是核心点,最有边的菜单我会弹出一个PopupWindow来,其实就是游戏和定制,看下我的PopupWindow实现

//显示菜单window
 private void showMenuWindow() {
 contentView = LayoutInflater.from(this).inflate(R.layout.pop_item_layout, null);
 popWnd = new PopupWindow(this);
 popWnd.setContentView(contentView);
 popWnd.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
 popWnd.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
 popWnd.setOutsideTouchable(true);
 popWnd.setBackgroundDrawable(new BitmapDrawable());
 popWnd.showAtLocation(ll_bottom_bar, Gravity.BOTTOM
 , ScreenUtils.getInstance(this).getScreenWidth() / 2
 , 350);
 //这里的350 应该按照View的思路 去进行测量,这里暂时未处理
 }

代码很简单,接着看下载,下载我是用的是RxVolley的下载方式,可以看下他的源码

/** * 下载 * * @param storeFilePath 本地存储绝对路径 * @param url 要下载的文件的url * @param progressListener 下载进度回调 * @param callback 回调 */ public static FileRequest download(String storeFilePath, String url, ProgressListener progressListener, HttpCallback callback) { RequestConfig config = new RequestConfig(); config.mUrl = url; config.mRetryPolicy = new DefaultRetryPolicy(DefaultRetryPolicy.DEFAULT_TIMEOUT_MS, 20, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT); FileRequest request = new FileRequest(storeFilePath, config, callback); request.setTag(url); request.setOnProgressListener(progressListener); new Builder().setRequest(request).doTask(); return request; }

最后就是设置壁纸了,这里我有好几个选项


Android 壁纸预览解析_android_05


虽然有几个选项,但是都是很简单的,设置桌面壁纸可以直接通过WallpaperManager的setBitmap去实现,锁屏就比较麻烦了,我们通过反射

//设置锁屏壁纸 private void setLockScreenWallpaper() { Glide.with(this).load(mListBigUrl.get(mGallery.getSelectedItemPosition())).asBitmap().into(new SimpleTarget() { @Override public void onResourceReady(Bitmap resource, GlideAnimation super Bitmap> glideAnimation) { try { //获取类名 Class class1 = wpManager.getClass(); //获取设置锁屏壁纸的函数 Method setWallPaperMethod = class1.getMethod("setBitmapToLockWallpaper