Android仿微信图片点击全屏效果

内容摘要
废话不多说,先看下效果:
先是微信的

再是模仿的

先说下实现原理,再一步步分析
这里总共有2个Activity一个就是主页,一个就是显示我们图片效果的页面,参数通过Intent传送,素材内
文章正文

废话不多说,先看下效果:

先是微信的

再是模仿的

先说下实现原理,再一步步分析

这里总共有2个Activity一个就是主页,一个就是显示我们图片效果的页面,参数通过Intent传送,素材内容均来自网络,(感谢聪明的蘑菇) 图片都是Glide异步下的,下的,下的重要的事情说三次,然后就是用动画做放大操作然后显示出来了(并没有做下载原图的实现,反正也是一样 下载下来Set上去而且动画都不需要更简便)。

OK,我们来看分析下

obj,目录下分别创建了2个对象,一个用来使用来处理显示页面的图片尺寸信息以及位置信息,还有一个是用来附带URL和分辨率

Config这个类就是我们的URL了没其他什么内容。

我们一个一个页面来看,先看MainActivity

他做的事情很简单,就是把下个页面的一些信息初始化一下然后通过Intent传过去,本身不做什么多余操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package wjj.com.imitatewechatimage.activity;
 
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
 
import wjj.com.imitatewechatimage.R;
 
import com.apkfuns.logutils.LogUtils;
import com.bumptech.glide.Glide;
 
import wjj.com.imitatewechatimage.Config;
import wjj.com.imitatewechatimage.obj.ImageInfoObj;
import wjj.com.imitatewechatimage.obj.ImageWidgetInfoObj;
 
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
  private ImageView imageView;
  private ImageInfoObj imageInfoObj;
  private ImageWidgetInfoObj imageWidgetInfoObj;
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    findId();
    init();
    Listener();
  }
 
  private void findId() {
    imageView = (ImageView) findViewById(R.id.imageView);
  }
 
  private void init() {
    Glide.with(MainActivity.this).load(Config.IMAGE_URL).placeholder(R.mipmap.maimai).into(imageView);
 
    imageInfoObj = new ImageInfoObj();
    imageInfoObj.imageUrl = Config.IMAGE_URL;
    imageInfoObj.imageWidth = 1280;
    imageInfoObj.imageHeight = 720;
 
    imageWidgetInfoObj = new ImageWidgetInfoObj();
    imageWidgetInfoObj.x = imageView.getLeft();
    imageWidgetInfoObj.y = imageView.getTop();
    imageWidgetInfoObj.width = imageView.getLayoutParams().width;
    imageWidgetInfoObj.height = imageView.getLayoutParams().height;
 
  }
 
  private void Listener() {
    imageView.setOnClickListener(this);
  }
 
  @Override
  protected void onResume() {
    super.onResume();
    LogUtils.d("--->MainActivity onResume");
  }
 
  @Override
  protected void onPause() {
    super.onPause();
    LogUtils.d("--->MainActivity onPause");
  }
 
  @Override
  protected void onDestroy() {
    super.onDestroy();
    LogUtils.d("--->MainActivity onDestroy");
  }
 
  @Override
  public void onClick(View v) {
    switch (v.getId()) {
      case R.id.imageView:
        //携带参数跳转
        Intent intent = new Intent(MainActivity.this, howImageActivity.class);
        intent.putExtra("imageInfoObj", imageInfoObj);
        intent.putExtra("imageWidgetInfoObj", imageWidgetInfoObj);
        startActivity(intent);
        break;
      default:
        break;
    }
  }
}

具体业务类ShowImageActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
public class ShowImageActivity extends AppCompatActivity {
  private RelativeLayout MainView;
  private ImageView showImageView;
  private ImageInfoObj imageInfoObj;
  private ImageWidgetInfoObj imageWidgetInfoObj;
  Button button;
 
  // 屏幕宽度
  public float Width;
  //原图高
  private float y_img_h;
  // 屏幕高度
  public float Height;
  private float size, size_h, img_w, img_h;
  protected float to_x = 0;
  protected float to_y = 0;
  private float tx;
  private float ty;
 
 
  private final Spring spring = SpringSystem
      .create()
      .createSpring()
      .addListener(new ExampleSpringListener());
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_how_image);
    LogUtils.d("--->ShowImageActivity onCreate");
    findId();
    init();
    Listener();
  }
 
  private void findId() {
    MainView = (RelativeLayout) findViewById(R.id.MainView);
    button = (Button) findViewById(R.id.button);
  }
 
  private void init() {
    DisplayMetrics dm = getResources().getDisplayMetrics();
    Width = dm.widthPixels;
    Height = dm.heightPixels;
 
    imageInfoObj = (ImageInfoObj) getIntent().getSerializableExtra("imageInfoObj");
    imageWidgetInfoObj = (ImageWidgetInfoObj) getIntent().getSerializableExtra("imageWidgetInfoObj");
    if (imageInfoObj == null) {
      LogUtils.d("--->imageInfoObj==null");
    }
    if (imageWidgetInfoObj == null) {
      LogUtils.d("--->imageWidgetInfoObj==null");
    }
 
    showImageView = new ImageView(this);
    showImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
 
    Glide.with(ShowImageActivity.this).load(imageInfoObj.imageUrl).into(showImageView);
 
    img_w = imageWidgetInfoObj.width;
    img_h = imageWidgetInfoObj.height - 300;
    size = Width / img_w;
    y_img_h = imageInfoObj.imageHeight * Width / imageInfoObj.imageWidth;
    size_h = y_img_h / img_h;
 
    RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams((int) imageWidgetInfoObj.width,
        (int) imageWidgetInfoObj.height);
    p.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
    p.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
    showImageView.setLayoutParams(p);
    p.setMargins((int) imageWidgetInfoObj.x,
        (int) imageWidgetInfoObj.y, (int) (Width - (imageWidgetInfoObj.x + imageWidgetInfoObj.width)),
        (int) (Height - (imageWidgetInfoObj.y + imageWidgetInfoObj.height)));
    MainView.addView(showImageView);
 
    new Handler().post(new Runnable() {
      public void run() {
        ShowImageView();
      }
    });
  }
 
  private void Listener() {
    showImageView.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        ShowImageView();
      }
    });
 
    button.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        ShowImageView();
      }
    });
  }
 
  @Override
  protected void onResume() {
    super.onResume();
    LogUtils.d("--->ShowImageActivity onResume");
  }
 
  @Override
  protected void onPause() {
    super.onPause();
    LogUtils.d("--->ShowImageActivity onPause");
  }
 
  @Override
  protected void onDestroy() {
    super.onDestroy();
    LogUtils.d("--->ShowImageActivity onDestroy");
  }
 
  private class ExampleSpringListener implements SpringListener {
 
    @Override
    public void onSpringUpdate(Spring spring) {
      double CurrentValue = spring.getCurrentValue();
      float mappedValue = (float) SpringUtil.mapValueFromRangeToRange(CurrentValue, 0, 1, 1, size);
      float mapy = (float) SpringUtil.mapValueFromRangeToRange(CurrentValue, 0, 1, 1, size_h);
      showImageView.setScaleX(mappedValue);
      showImageView.setScaleY(mapy);
      if (CurrentValue == 1) {
//        showImageView.setVisibility(View.GONE);
      }
    }
 
    @Override
    public void onSpringAtRest(Spring spring) {
 
    }
 
    @Override
    public void onSpringActivate(Spring spring) {
 
    }
 
    @Override
    public void onSpringEndStateChange(Spring spring) {
 
    }
  }
 
  //实现效果
  private void MoveView() {
 
    ObjectAnimator.ofFloat(MainView, "alpha", 0.8f).setDuration(0).start();
    MainView.setVisibility(View.VISIBLE);
    AnimatorSet set = new AnimatorSet();
    set.playTogether(
        ObjectAnimator.ofFloat(showImageView, "translationX", tx).setDuration(200),
        ObjectAnimator.ofFloat(showImageView, "translationY", ty).setDuration(200),
        ObjectAnimator.ofFloat(MainView, "alpha", 1).setDuration(200)
 
    );
    set.addListener(new Animator.AnimatorListener() {
      @Override
      public void onAnimationStart(Animator animator) {
 
      }
 
      @Override
      public void onAnimationEnd(Animator animator) {
        showImageView.setScaleType(ImageView.ScaleType.FIT_XY);
        spring.setEndValue(1);
      }
 
      @Override
      public void onAnimationCancel(Animator animator) {
 
      }
 
      @Override
      public void onAnimationRepeat(Animator animator) {
 
      }
    });
    set.start();
 
  }
 
  //关闭页面
  private void MoveBackView() {
    AnimatorSet set = new AnimatorSet();
    set.playTogether(
        ObjectAnimator.ofFloat(showImageView, "translationX", to_x).setDuration(200),
        ObjectAnimator.ofFloat(showImageView, "translationY", to_y).setDuration(200)
    );
    set.addListener(new Animator.AnimatorListener() {
      @Override
      public void onAnimationStart(Animator animator) {
 
      }
 
      @Override
      public void onAnimationEnd(Animator animator) {
        finish();
      }
 
      @Override
      public void onAnimationCancel(Animator animator) {
 
      }
 
      @Override
      public void onAnimationRepeat(Animator animator) {
 
      }
    });
    set.start();
  }
 
  //具体动画处理类
  private void ShowImageView() {
    if (spring.getEndValue() == 0) {
      //弹动摩擦力
      spring.setSpringConfig(SpringConfig.fromOrigamiTensionAndFriction(300, 5));
      //动画结束后出现的位置
      tx = 0;
      ty = Height / 2 - (imageWidgetInfoObj.y + img_h + 600);
      MoveView();
      return;
    }
    spring.setSpringConfig(SpringConfig.fromOrigamiTensionAndFriction(1, 5));
    spring.setEndValue(0);
    new Handler().post(new Runnable() {
      public void run() {
        MoveBackView();
      }
    });
 
  }
 
  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
 
      showImageView.setVisibility(View.VISIBLE);
      ShowImageView();
 
    }
    return true;
  }
 
}

大致流程:
1.在 init()获取了屏幕信息,上一个类传来的参数,以及对坐标点进行了一些计算 ,然后用Handler来启动动画的效果

2.ShowImageView()处理了动画的实现,(动画效果是compile 'com.facebook.rebound:rebound:0.3.8' 实现的,这边不做教程了给出传送门:http://facebook.github.io/rebound/)

总结:

总体实现并不是太难,因为有框架的关系,使得复杂的动画部分不用自己去写,调用下在回调里做业务就行,这里补充下一些过程中用到的技术点

1.图片的缩放模式:
android:scaleType是控制图片如何resized/moved来匹对ImageView的size。

ImageView.ScaleType / android:scaleType值的意义区别:

CENTER /center  按图片的原来size居中显示,当图片长/宽超过View的长/宽,则截取图片的居中部分显示

CENTER_CROP / centerCrop  按比例扩大图片的size居中显示,使得图片长(宽)等于或大于View的长(宽)

CENTER_INSIDE / centerInside  将图片的内容完整居中显示,通过按比例缩小或原来的size使得图片长/宽等于或小于View的长/宽

FIT_CENTER / fitCenter  把图片按比例扩大/缩小到View的宽度,居中显示

FIT_END / fitEnd   把图片按比例扩大/缩小到View的宽度,显示在View的下部分位置

FIT_START / fitStart  把图片按比例扩大/缩小到View的宽度,显示在View的上部分位置

FIT_XY / fitXY  把图片不按比例扩大/缩小到View的大小显示

MATRIX / matrix 用矩阵来绘制,动态缩小放大图片来显示。

** 要注意一点,Drawable文件夹里面的图片命名是不能大写的

2.Layout常用的属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 相对于给定ID控件
<a href="http://lib.csdn.net/base/15" class="replace_word" title="undefined" target="_blank" style="color: rgb(223, 52, 52); font-weight: bold;">android</a>:layout_above 将该控件的底部置于给定ID的控件之上;
android:layout_below 将该控件的底部置于给定ID的控件之下;
android:layout_toLeftOf 将该控件的右边缘与给定ID的控件左边缘对齐;
android:layout_toRightOf 将该控件的左边缘与给定ID的控件右边缘对齐;
  
android:layout_alignBaseline 将该控件的baseline与给定ID的baseline对齐;
android:layout_alignTop 将该控件的顶部边缘与给定ID的顶部边缘对齐;
android:layout_alignBottom 将该控件的底部边缘与给定ID的底部边缘对齐;
android:layout_alignLeft 将该控件的左边缘与给定ID的左边缘对齐;
android:layout_alignRight 将该控件的右边缘与给定ID的右边缘对齐;
// 相对于父组件
android:layout_alignParentTop 如果为true,将该控件的顶部与其父控件的顶部对齐;
android:layout_alignParentBottom 如果为true,将该控件的底部与其父控件的底部对齐;
android:layout_alignParentLeft 如果为true,将该控件的左部与其父控件的左部对齐;
android:layout_alignParentRight 如果为true,将该控件的右部与其父控件的右部对齐;
// 居中
android:layout_centerHorizontal 如果为true,将该控件的置于水平居中;
android:layout_centerVertical 如果为true,将该控件的置于垂直居中;
android:layout_centerInParent 如果为true,将该控件的置于父控件的中央;
// 指定移动像素
android:layout_marginTop 上偏移的值;
android:layout_marginBottom 下偏移的值;
android:layout_marginLeft   左偏移的值;
android:layout_marginRight   右偏移的值;

这个例子只是例子,部分坐标和样式是写死的,如果要运用到实际项目中还是要些许就该,在操作的过程中还对加载多图片进行了测试,暂未发生OOM的情况,补上内存使用情况图(一直很稳定)

这里写图片描述

代码地址:https://github.com/ddwhan0123/BlogSample/tree/master/ImitateWeChatImage
源码下载地址:https://github.com/ddwhan0123/BlogSample/blob/master/ImitateWeChatImage/ImitateWeChatImage.zip?raw=true

以上就是本文的全部内容,希望能够帮助大家实现Android仿微信图片点击全屏效果,谢谢大家的阅读。


代码注释

作者:喵哥笔记

IDC笔记

学的不仅是技术,更是梦想!