自定义ScrollView实现gallery3D效果,3D相册效果

来源:互联网 发布:手机短信软件 编辑:程序博客网 时间:2024/05/17 04:55

先看一下效果吧:

 

截图效果不是太好,大家将就着看吧。。。

有些童鞋看了效果第一反应就是用gallery就能实现。最开始我也是用gallery做的。但是gallery存在一些问题,其实我觉得也不是问题,就是设计和小头头觉得不好看,无奈之下就自己用scrollview自己写了一个。。。说多了都是眼泪啊。。。

 

其实本质上就是一个自定义的linearlayout,外面套了一个scrollview。为啥要套一个scrollview呢?当然是不套的话有问题了,听着像废话。。。具体时间什么问题你可以自己试试,把一个横向的linearlayout放几个view,超过一屏幕就能看出问题了,我也不是太会描述问题。

 

大概思想就是在onTouch里面通过scrollto和scrollby操作linearlayout的位置,达到显示不同item居中。这个view存在一个大问题,如果item太多,会OOM。我的项目里面内容不多,所以没有进行这方面的考虑。当然肯定还有其它问题,大家就根据需要改动就好了。代码里面还有很多可以优化的地方,自己动手丰衣足食~

 

下面就边看代码边讲解一下思想:

首先是addview,重写一下:

mContainer是scrollview里面的linearlayout,addview就是网scrollview的linearlayout里面添加view

  @Override
 public void addView(View child) {
      mContainer.addView(child);
 }

 

接下来是onlayout:

mChildRects是一个list,用来存放每个item的left,并且每个item都被setTag,tag就是item的位置。用来获取item位置方便。每个item的监听是执行scrollToView(v)方法,scrollToView方法就是移动到某个view的位置。

@Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
     super.onLayout(changed, l, t, r, b);
     mContainer = (LinearLayout) getChildAt(0);
     int count = mContainer.getChildCount();
     if (count > 0) {
       mChildRects.clear();
       for (int i = 0; i < count; i++) {
       View child = mContainer.getChildAt(i);
       child.setTag(i);
       mChildRects.add(child.getLeft());
       child.setOnClickListener(new OnClickListener() {

           @Override
           public void onClick(View v) {
               scrollToView(v);
           }
        });
       }
     }
 }

 

scrollToView方法:

这个方法还是很关键的。涉及到一些计算问题。因为上面说到mChildRects存放了所有item的left,当需要移动时,就需要根据item的位置(tag)进行计算移动的距离scrollto到这个位置就好了。具体怎么计算呢?懒一下示意图:

加入红色使我们要移动的item,如果我们要把item移动到屏幕左边,那么直接scrollto至item的left即可,二left存放在mChildRects中。但是我们现在要移到中间。那差了多少呢?就是中间红色的item左边缘到左边item的左边缘,差了多少?不就是scrollview的宽度一半减去item宽度的一半?代码中这部分写错了,不单独上传了,这里提醒一下。

private void scrollToView(View v) {
  int currentposition = (Integer) v.getTag();
  if (mChangeListener != null && currentposition != mSelectedPosition) {
   mChangeListener.onSelectionChange(mSelectedPosition,
     mContainer.getChildAt(mSelectedPosition), currentposition,
     mContainer.getChildAt(currentposition));
  }
  mSelectedPosition = currentposition;
  int left = mChildRects.get((Integer) v.getTag());
  // 滚动到的位置
  int scrollTo = left - (getCenterX() - v.getWidth() / 2);
  // 当前的x
  int currentX = mContainer.getScrollX();
  // 需要变化的量
  // int deltX = scrollTo - currentX;
  // mContainer.scrollBy(deltX, 0);
  ValueAnimator value = ValueAnimator.ofInt(currentX, scrollTo);
  value.addUpdateListener(new AnimatorUpdateListener() {

   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
    mContainer.scrollTo((Integer) animation.getAnimatedValue(), 0);
    calculateDelt();
    scaleView();
   }
  });
  value.setDuration(300);
  value.start();
 }

 

 

然后就是onTouch方法,完全重写了:

这里贴一下代码,就不多说了,大家下了代码自己看吧,注释我写的很清楚,相信看起来不费劲。

@Override
 public boolean onTouchEvent(MotionEvent ev) {

  int left = mChildRects.get(0);
  int right = mChildRects.get(mChildRects.size() - 1);
  // 最左边滚动到的位置
  int leftScrollTo = left
    - (getCenterX() - mContainer.getChildAt(0).getWidth() / 2);
  // 最右边滚动到的位置
  int rightScrollTo = right
    - (getCenterX() - mContainer.getChildAt(mChildRects.size() - 1)
      .getWidth() / 2);
  calculateDelt();

  int currentposition = calculateSelectedPosition();
  if (mChangeListener != null && currentposition != mSelectedPosition) {
   mChangeListener.onSelectionChange(mSelectedPosition,
     mContainer.getChildAt(mSelectedPosition), currentposition,
     mContainer.getChildAt(currentposition));
  }
  mSelectedPosition = currentposition;

  switch (ev.getAction()) {
  case MotionEvent.ACTION_DOWN:
   lastX = ev.getX();
   break;
  case MotionEvent.ACTION_MOVE:
   if (lastX == -1) {
    lastX = ev.getX();
   } else {
    float x = ev.getX();
    float deltX = x - lastX;
    if (mContainer.getScrollX() < leftScrollTo && (deltX > 0)) {// 滑到最左端不能继续
     return false;
    }
    if (deltX < 0 && mContainer.getScrollX() > rightScrollTo) {// 滑到最右端不能继续
     return false;
    }
    mContainer.scrollBy((int) (lastX - x), 0);
    lastX = x;
    scaleView();
   }
   break;
  case MotionEvent.ACTION_UP:
  case MotionEvent.ACTION_CANCEL:
   scrollToPosition(mSelectedPosition);
   lastX = -1;
   break;
  }
  return false;
 }

 

就写这么多吧,这里写的看起来也不方便。还是直接看代码比较好,代码中我给大家留了一些参数,都是做适配的时候用的,也有详细的注释,哎。。。苦逼啊。。。

代码链接:http://download.csdn.net/detail/lizhengwei1989/9052985

收1分,有时候我也需要积分下一些资料,大家就慷慨支持一下吧

 

 

 

   

0 0
原创粉丝点击