Android仿微信圖片點擊全屏效果

[轉載 : https://github.com/ddwhan0123/BlogSample/tree/master/ImitateWeChatImage]

廢話不多說,先看下效果:

先是微信的

Paste_Image.png

再是模仿的

2016413154330260.gif

先說下實現原理,再一步步分析

這里總共有2個Activity一個就是主頁,一個就是顯示我們圖片效果的頁面,參數通過Intent傳送,素材內容均來自網絡,(感謝聰明的蘑菇) 圖片都是Glide異步下的,下的,下的重要的事情說三次,然后就是用動畫做放大操作然后顯示出來了(并沒有做下載原圖的實現,反正也是一樣 下載下來Set上去而且動畫都不需要更簡便)。

OK,我們來看分析下

obj,目錄下分別創建了2個對象,一個用來使用來處理顯示頁面的圖片尺寸信息以及位置信息,還有一個是用來附帶URL和分辨率

Config這個類就是我們的URL了沒其他什么內容。

我們一個一個頁面來看,先看MainActivity

他做的事情很簡單,就是把下個頁面的一些信息初始化一下然后通過Intent傳過去,本身不做什么多余操作

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



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常用的屬性:

// 相對于給定ID控件
android: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://raw.githubusercontent.com/ddwhan0123/BlogSample/master/ImitateWeChatImage/ImitateWeChatImage.zip

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容