話很少說,直接上效果圖css

imagereview.gif
ImageReview
在這個庫裏面用到了第三方的縮放圖片查看庫java
一、要實現效果圖的方案,須要操做重寫ViewPager的事件處理。
二、下滑透明的方案可使用設置背景來實現android
下拉縮放的效果須要重寫onInterceptTouchEvent和onTouchEvent,
在onInterceptTouchEvent中不攔截down事件,而且在move事件中判斷是否知足下滑縮放的條件;
在onTouchEvent中實現具體的縮放以及透明度變化的效果;
同時在ViewPager的滑動要與下滑縮放區分開,所以須要監聽OnPageChangeListener,並在onTouchEvent判斷是否ViewPager在滑動中git
public class DragViewPager extends ViewPager implements View.OnClickListener { public static final int STATUS_NORMAL = 0;//正常瀏覽狀態 public static final int STATUS_MOVING = 1;//滑動狀態 public static final int STATUS_RESETTING = 2;//返回中狀態 public static final String TAG = "DragViewPager"; public static final float MIN_SCALE_SIZE = 0.3f;//最小縮放比例 public static final int BACK_DURATION = 300;//ms public static final int DRAG_GAP_PX = 50; private int currentStatus = STATUS_NORMAL; private int currentPageStatus; private float mDownX; private float mDownY; private float screenHeight; /** * 要縮放的View */ private View currentShowView; /** * 滑動速度檢測類 */ private VelocityTracker mVelocityTracker; private IAnimClose iAnimClose; public void setIAnimClose(IAnimClose iAnimClose) { this.iAnimClose = iAnimClose; } public DragViewPager(Context context) { super(context); init(context); } public DragViewPager(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public void init(Context context) { screenHeight = ScreenUtils.getScreenHeight(context); setBackgroundColor(Color.BLACK); addOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { currentPageStatus = state; } }); } public void setCurrentShowView(View currentShowView) { this.currentShowView = currentShowView; if (this.currentShowView != null) { this.currentShowView.setOnClickListener(this); } } //配合SubsamplingScaleImageView使用,根據須要攔截ACTION_MOVE @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (getAdapter() instanceof ImagePagerAdapter) { ImagePagerAdapter adapter = ((ImagePagerAdapter) getAdapter()); SubsamplingScaleImageView mImage = (SubsamplingScaleImageView) adapter.getItem(getCurrentItem()).getView().findViewById(R.id.image); switch (ev.getAction()){ case MotionEvent.ACTION_DOWN: Log.e("jc","onInterceptTouchEvent:ACTION_DOWN"); mDownX = ev.getRawX(); mDownY = ev.getRawY(); break; case MotionEvent.ACTION_MOVE: Log.e("jc","onInterceptTouchEvent:ACTION_MOVE"); if (mImage.getCenter() != null && mImage.getCenter().y <= mImage.getHeight() / mImage.getScale() / 2) { Log.e("jc","onInterceptTouchEvent:ACTION_MOVE"); int deltaX = Math.abs((int) (ev.getRawX() - mDownX)); int deltaY = (int) (ev.getRawY() - mDownY); if (deltaY > DRAG_GAP_PX && deltaX <= DRAG_GAP_PX) {//往下移動超過臨界,左右移動不超過臨界時,攔截滑動事件 return true; } } break; case MotionEvent.ACTION_UP: Log.e("jc","onInterceptTouchEvent:ACTION_UP"); break; } } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent ev) { if (currentStatus == STATUS_RESETTING) return false; switch (ev.getActionMasked()) { case MotionEvent.ACTION_DOWN: mDownX = ev.getRawX(); mDownY = ev.getRawY(); addIntoVelocity(ev); break; case MotionEvent.ACTION_MOVE: addIntoVelocity(ev); int deltaY = (int) (ev.getRawY() - mDownY); //手指往上滑動 if (deltaY <= DRAG_GAP_PX && currentStatus != STATUS_MOVING) return super.onTouchEvent(ev); //viewpager不在切換中,而且手指往下滑動,開始縮放 if (currentPageStatus != SCROLL_STATE_DRAGGING && (deltaY > DRAG_GAP_PX || currentStatus == STATUS_MOVING)) { moveView(ev.getRawX(), ev.getRawY()); return true; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (currentStatus != STATUS_MOVING) return super.onTouchEvent(ev); final float mUpX = ev.getRawX(); final float mUpY = ev.getRawY(); float vY = computeYVelocity();//鬆開時必須釋放VelocityTracker資源 if (vY >= 1200 || Math.abs(mUpY - mDownY) > screenHeight / 4) { //下滑速度快,或者下滑距離超過屏幕高度的一半,就關閉 if (iAnimClose != null) { iAnimClose.onPictureRelease(currentShowView); } } else { resetReviewState(mUpX, mUpY); } break; } return super.onTouchEvent(ev); } //返回瀏覽狀態 private void resetReviewState(final float mUpX, final float mUpY) { currentStatus = STATUS_RESETTING; if (mUpY != mDownY) { ValueAnimator valueAnimator = ValueAnimator.ofFloat(mUpY, mDownY); valueAnimator.setDuration(BACK_DURATION); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float mY = (float) animation.getAnimatedValue(); float percent = (mY - mDownY) / (mUpY - mDownY); float mX = percent * (mUpX - mDownX) + mDownX; moveView(mX, mY); if (mY == mDownY) { mDownY = 0; mDownX = 0; currentStatus = STATUS_NORMAL; } } }); valueAnimator.start(); } else if (mUpX != mDownX) { ValueAnimator valueAnimator = ValueAnimator.ofFloat(mUpX, mDownX); valueAnimator.setDuration(BACK_DURATION); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float mX = (float) animation.getAnimatedValue(); float percent = (mX - mDownX) / (mUpX - mDownX); float mY = percent * (mUpY - mDownY) + mDownY; moveView(mX, mY); if (mX == mDownX) { mDownY = 0; mDownX = 0; currentStatus = STATUS_NORMAL; } } }); valueAnimator.start(); } else if (iAnimClose != null) iAnimClose.onPictureClick(); } //移動View private void moveView(float movingX, float movingY) { if (currentShowView == null) return; currentStatus = STATUS_MOVING; float deltaX = movingX - mDownX; float deltaY = movingY - mDownY; float scale = 1f; float alphaPercent = 1f; if (deltaY > 0) { scale = 1 - Math.abs(deltaY) / screenHeight; alphaPercent = 1 - Math.abs(deltaY) / (screenHeight / 2); } ViewHelper.setTranslationX(currentShowView, deltaX); ViewHelper.setTranslationY(currentShowView, deltaY); scaleView(scale); setBackgroundColor(getBlackAlpha(alphaPercent)); } //縮放View private void scaleView(float scale) { scale = Math.min(Math.max(scale, MIN_SCALE_SIZE), 1); ViewHelper.setScaleX(currentShowView, scale); ViewHelper.setScaleY(currentShowView, scale); } private int getBlackAlpha(float percent) { percent = Math.min(1, Math.max(0, percent)); int intAlpha = (int) (percent * 255); return Color.argb(intAlpha,0,0,0); } private void addIntoVelocity(MotionEvent event) { if (mVelocityTracker == null) mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker.addMovement(event); } private float computeYVelocity() { float result = 0; if (mVelocityTracker != null) { mVelocityTracker.computeCurrentVelocity(1000); result = mVelocityTracker.getYVelocity(); releaseVelocity(); } return result; } private void releaseVelocity() { if (mVelocityTracker != null) { mVelocityTracker.clear(); mVelocityTracker.recycle(); mVelocityTracker = null; } } @Override public void onClick(View v) { if (iAnimClose != null) { iAnimClose.onPictureClick(); } } public interface IAnimClose { void onPictureClick(); void onPictureRelease(View view); } }
須要進行縮放的View我這裏在Adapter中添加回調設置,而且adapter能夠實現更新的效果github
public class ImagePagerAdapter extends FragmentStatePagerAdapter { private DragViewPager mPager; private ArrayList<Fragment> mFragmentList; public ImagePagerAdapter(FragmentManager fm, List<String> datas,DragViewPager pager) { super(fm); mPager=pager; mPager.setAdapter(this); updateData(datas); } public void updateData(List<String> dataList) { ArrayList<Fragment> fragments = new ArrayList<>(); for (int i = 0, size = dataList.size(); i < size; i++) { final ImageDetailFragment fragment = ImageDetailFragment.newInstance(dataList.get(i)); fragment.setOnImageListener(new ImageDetailFragment.OnImageListener() { @Override public void onInit() { View view = fragment.getView(); mPager.setCurrentShowView(view); } }); fragments.add(fragment); } setViewList(fragments); } private void setViewList(ArrayList<Fragment> fragmentList) { if (mFragmentList != null) { mFragmentList.clear(); } mFragmentList = fragmentList; notifyDataSetChanged(); } @Override public int getCount() { return mFragmentList==null?0:mFragmentList.size(); } public int getItemPosition(Object object) { return POSITION_NONE; } @Override public Fragment getItem(int position) { return mFragmentList.get(position); } }
要實現透明度變化的效果還須要對activity設置themeide
<style name="translucent" parent="AppTheme"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> <item name="android:windowIsTranslucent">true</item> <item name="android:windowBackground">@android:color/transparent</item> </style>
<activity android:name=".ui.ImagePagerActivity" android:theme="@style/translucent"/>
在須要使用的頁面只須要調用便可post
ImagePagerActivity.startImagePage(MainActivity.this, urls,pos,recyclerView.getLayoutManager().findViewByPosition(pos));
在整個demo中採用的轉場動畫,須要設置共享元素,所以在須要使用的頁面須要設置以下:動畫
首先設置轉場動畫的共享元素,由於跳轉和返回時都會調用onMapSharedElements,須要判斷bundle是否爲空,bundle會在返回的時候在onActivityReenter獲取到ui
//設置轉場動畫的共享元素,由於跳轉和返回時都會調用onMapSharedElements,須要判斷bundle是否爲空 setExitSharedElementCallback(new SharedElementCallback() { @Override public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) { if (bundle!=null){ int index = bundle.getInt(ImagePagerActivity.STATE_POSITION,0); sharedElements.clear(); sharedElements.put("img", recyclerView.getLayoutManager().findViewByPosition(index)); bundle=null; } } });
其次在返回的時候獲取數據bundlethis
@Override public void onActivityReenter(int resultCode, Intent data) { super.onActivityReenter(resultCode, data); bundle = data.getExtras(); int currentPosition = bundle.getInt(ImagePagerActivity.STATE_POSITION,0); //作相應的滾動 recyclerView.scrollToPosition(currentPosition); //暫時延遲 Transition 的使用,直到咱們肯定了共享元素的確切大小和位置才使用 //postponeEnterTransition後不要忘記調用startPostponedEnterTransition ActivityCompat.postponeEnterTransition(this); recyclerView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { recyclerView.getViewTreeObserver().removeOnPreDrawListener(this); // TODO: figure out why it is necessary to request layout here in order to get a smooth transition. recyclerView.requestLayout(); //共享元素準備好後調用startPostponedEnterTransition來恢復過渡效果 ActivityCompat.startPostponedEnterTransition(MainActivity.this); return true; } }); }
完整的調用頁面的代碼以下:
public class MainActivity extends AppCompatActivity { private RecyclerView recyclerView; private MainAdapter mainAdapter; //圖片集合 private ArrayList<String> urls; //存放返回時當前頁碼 private Bundle bundle; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); urls=new ArrayList<>(); //爲了顯示效果,重複添加了三次 urls.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1524477979306&di=3eb07e9302606048abe13d7b6a2bc601&imgtype=0&src=http%3A%2F%2Fimg4.duitang.com%2Fuploads%2Fitem%2F201406%2F12%2F20140612211118_YYXAC.jpeg"); urls.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1524133463580&di=1315bc4db30999f00b89ef79c3bb06e5&imgtype=0&src=http%3A%2F%2Fpic36.photophoto.cn%2F20150710%2F0005018721870517_b.jpg"); urls.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1524133463575&di=6221f21bcb761675c5d161ebc53d5948&imgtype=0&src=http%3A%2F%2Fimg5.duitang.com%2Fuploads%2Fitem%2F201410%2F03%2F20141003112442_AkkuH.thumb.700_0.jpeg"); urls.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1524477979306&di=3eb07e9302606048abe13d7b6a2bc601&imgtype=0&src=http%3A%2F%2Fimg4.duitang.com%2Fuploads%2Fitem%2F201406%2F12%2F20140612211118_YYXAC.jpeg"); urls.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1524133463580&di=1315bc4db30999f00b89ef79c3bb06e5&imgtype=0&src=http%3A%2F%2Fpic36.photophoto.cn%2F20150710%2F0005018721870517_b.jpg"); urls.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1524133463575&di=6221f21bcb761675c5d161ebc53d5948&imgtype=0&src=http%3A%2F%2Fimg5.duitang.com%2Fuploads%2Fitem%2F201410%2F03%2F20141003112442_AkkuH.thumb.700_0.jpeg"); urls.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1524477979306&di=3eb07e9302606048abe13d7b6a2bc601&imgtype=0&src=http%3A%2F%2Fimg4.duitang.com%2Fuploads%2Fitem%2F201406%2F12%2F20140612211118_YYXAC.jpeg"); urls.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1524133463580&di=1315bc4db30999f00b89ef79c3bb06e5&imgtype=0&src=http%3A%2F%2Fpic36.photophoto.cn%2F20150710%2F0005018721870517_b.jpg"); urls.add("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1524133463575&di=6221f21bcb761675c5d161ebc53d5948&imgtype=0&src=http%3A%2F%2Fimg5.duitang.com%2Fuploads%2Fitem%2F201410%2F03%2F20141003112442_AkkuH.thumb.700_0.jpeg"); initView(); } private void initView() { recyclerView = (RecyclerView) findViewById(R.id.recycler); recyclerView.setLayoutManager(new GridLayoutManager(this, 2)); mainAdapter = new MainAdapter(urls); mainAdapter.setOnItemClickListener(new MainAdapter.OnItemClickListener() { @Override public void onItemClick(int pos) { ImagePagerActivity.startImagePage(MainActivity.this, urls,pos,recyclerView.getLayoutManager().findViewByPosition(pos)); } }); recyclerView.setAdapter(mainAdapter); //設置轉場動畫的共享元素,由於跳轉和返回都會調用,須要判斷bundle是否爲空 setExitSharedElementCallback(new SharedElementCallback() { @Override public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) { if (bundle!=null){ int index = bundle.getInt(ImagePagerActivity.STATE_POSITION,0); sharedElements.clear(); sharedElements.put("img", recyclerView.getLayoutManager().findViewByPosition(index)); bundle=null; } } }); } //返回的時候獲取數據 @Override public void onActivityReenter(int resultCode, Intent data) { super.onActivityReenter(resultCode, data); bundle = data.getExtras(); int currentPosition = bundle.getInt(ImagePagerActivity.STATE_POSITION,0); //作相應的滾動 recyclerView.scrollToPosition(currentPosition); //暫時延遲 Transition 的使用,直到咱們肯定了共享元素的確切大小和位置才使用 //postponeEnterTransition後不要忘記調用startPostponedEnterTransition ActivityCompat.postponeEnterTransition(this); recyclerView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { recyclerView.getViewTreeObserver().removeOnPreDrawListener(this); // TODO: figure out why it is necessary to request layout here in order to get a smooth transition. recyclerView.requestLayout(); //共享元素準備好後調用startPostponedEnterTransition來恢復過渡效果 ActivityCompat.startPostponedEnterTransition(MainActivity.this); return true; } }); } }
須要查看完整代碼點擊這裏,喜歡的請給個star,謝謝