前言:
微信作为很火的社交平台广受大众推崇,作为开发者不仅要学会使用软件,更重要的是要琢磨那些吸引人的控件的研发思路。刷了好久的朋友圈,作为一个安卓开发者来说,朋友圈九宫格的图片显示,以及点击图片会有灰色蒙板的效果吸引了我,为了方便大家,也为了给自己温习知识,写下这篇博文。
效果图:
就是这样的效果!
正文:
今天我们就来实现这样的一个效果,在我们动笔写代码之前,我们必须要理清自己的思路,不能一开始就盲目的去写代码,磨刀不误砍柴工。我们唯一能够确定的是,继承自imageview。然后呢?然后重写构造方法,由于用到了点击,所以还要去手动处理一下onTouchEvent方法。看似困难的问题处理起来也会游刃有余了。想法都是对的,其实我们还少分析一个问题,图片会分为本地和远程两种形式,这样的图片如何去加一个灰色的蒙板,远程图片又如何加载呢?带着这些个问题,我们来一一探寻答案。
思考一:继承ImageView
public class GrayScaleImageView extends ImageView
思考二:重写构造方法
public GrayScaleImageView(Context context) {
super(context);
}
public GrayScaleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public GrayScaleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
我没有进行一些初始化操作,因为这里还没有什么需要初始化。
思考三:处理onTouchEvent事件
@Override
public boolean onTouchEvent(MotionEvent event) {
Drawable drawable = getDrawable();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (drawable != null) {
// drawable.mutate使得此drawable共享状态,改变时全部改变
drawable.mutate().setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
}
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (drawable != null) {
drawable.mutate().clearColorFilter();
}
break;
}
return true;
// return super.onTouchEvent(event);
}
这是整个博文最核心的一部分。首先我们通过getDrawable()获取ImageView的drawable图片,手指按下的时候需要给这个drawable加上灰色蒙板,我们通过:
drawable.mutate().setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
这段代码给drawable加上了一个颜色过滤,那么这边的mutate方法,需要看一下官方解释:
最重要的一句话,By default, all drawables instances loaded from the same resource share a common state; if you modify the state of one instance, all the other instances will receive the same modification.中文简言就是状态共享。
手指抬起的时候,就要清除我们加的过滤层。
drawable.mutate().clearColorFilter();
这里我需要特别提醒的就是,这边的事件处理完之后,需要return true,如果你return super.onTouchEvent(event);就会发现move,和up事件不会执行,只会执行down事件,觉得奇怪的同学去深入看一下安卓的事件分发处理机制。
思考四:如何设置imageview本地和远程图片
首先,我们需要确定一下我们的远程图片加载框架,网上有很多优秀的图片加载框架,在前面的博文中我也有提到过,这里我用的是Picasso。那么在什么时候去设置图片呢?
android view有以下14个周期:
1、onFinishInflate() 当View中所有的子控件均被映射成xml后触发 。
2、onMeasure( int , int ) 确定所有子元素的大小 。
3、onLayout( boolean , int , int , int , int ) 当View分配所有的子元素的大小和位置时触发 。
4、onSizeChanged( int , int , int , int ) 当view的大小发生变化时触发 。
5、onDraw(Canvas) view渲染内容的细节。
6、onKeyDown( int , KeyEvent) 有按键按下后触发 。
7、onKeyUp( int , KeyEvent) 有按键按下后弹起时触发 。
8、onTrackballEvent(MotionEvent) 轨迹球事件 。
9、onTouchEvent(MotionEvent) 触屏事件 。
10、onFocusChanged( boolean , int , Rect) 当View获取或失去焦点时触发 。
11、onWindowFocusChanged( boolean ) 当窗口包含的view获取或失去焦点时触发 。
12、onAttachedToWindow() 当view被附着到一个窗口时触发 。
13、onDetachedFromWindow() 当view离开附着的窗口时触发,Android123提示该方法和 onAttachedToWindow() 是相反的。
14、onWindowVisibilityChanged( int ) 当窗口中包含的可见的view发生变化时触发。
安卓的大致执行流程为:从构造方法开始,依次执行onAttachToWindow——>onMeasure——>onSizeChanged——>onLayout——>onMeasure——>onLayout——>onDraw——>onDetachedFromWindow
看到这边的话,就应该确定了,我们在onAttachToWindow方法中进行图片设置,在onDetachedFromWindow取消图片设置
@Override
protected void onAttachedToWindow() {
isAttachWindow = true;
if (!TextUtils.isEmpty(url)) {
if (isAttachWindow) {
Picasso.with(getContext()).load(url).placeholder(new ColorDrawable(Color.parseColor("#f5f5f5"))).into(this);
}
}
super.onAttachedToWindow();
}
@Override
protected void onDetachedFromWindow() {
Picasso.with(getContext()).cancelRequest(this);
isAttachWindow = false;
setImageBitmap(null);
super.onDetachedFromWindow();
}
如果是本地图片的话,我们直接在xml中设置android:src,如果是远程的图片的话,就需要在activity中调用这个方法。
public void setImageUrl(String url) {
if (!TextUtils.isEmpty(url)) {
this.url = url;
}
}
好了,我贴上全部代码咯,GrayScaleImageView.java:
package com.beyole.view;
import android.content.Context;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;
public class GrayScaleImageView extends ImageView {
// 图片地址
private String url;
// 是否依附在window上
private boolean isAttachWindow = false;
public GrayScaleImageView(Context context) {
super(context);
}
public GrayScaleImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public GrayScaleImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Drawable drawable = getDrawable();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (drawable != null) {
// drawable.mutate使得此drawable共享状态,改变时全部改变
drawable.mutate().setColorFilter(Color.GRAY, PorterDuff.Mode.MULTIPLY);
}
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (drawable != null) {
drawable.mutate().clearColorFilter();
}
break;
}
return true;
// return super.onTouchEvent(event);
}
@Override
protected void onAttachedToWindow() {
isAttachWindow = true;
if (!TextUtils.isEmpty(url)) {
if (isAttachWindow) {
Picasso.with(getContext()).load(url).placeholder(new ColorDrawable(Color.parseColor("#f5f5f5"))).into(this);
}
}
super.onAttachedToWindow();
}
@Override
protected void onDetachedFromWindow() {
Picasso.with(getContext()).cancelRequest(this);
isAttachWindow = false;
setImageBitmap(null);
super.onDetachedFromWindow();
}
public void setImageUrl(String url) {
if (!TextUtils.isEmpty(url)) {
this.url = url;
}
}
}
使用:MainActivity.java
package com.beyole.grayscaleimageview;
import android.app.Activity;
import android.os.Bundle;
import com.beyole.view.GrayScaleImageView;
public class MainActivity extends Activity {
private GrayScaleImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//imageView = (GrayScaleImageView) findViewById(R.id.img1);
//imageView.setImageUrl("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1461129468&di=07dab3112befff0b84bd7c5933ff5523&src=http://img5.duitang.com/uploads/item/201411/08/20141108162654_xthYT.jpeg");
}
}
activity_main.xml:
行了,其实写这篇博客是为下篇微信朋友圈九宫格显示图片做准备的,就当是下篇博文的预告了吧。
好了,今天的代码教程到此结束。赶着去改论文了,忙里偷着写这一篇博客,我真的不适合搞论文写作。。
csdn下载地址:http://download.csdn.net/detail/smarticeberg/9496918
https://github.com/xuejiawei/beyole_grayscaleimageview 欢迎fork or star
题外话:
Android交流群:279031247(广告勿入)
新浪微博:SmartIceberg