RecyclerView实现VR效果外加拖动换位 带dome

这些都是通过在网上找到的方法和群里大神的帮助写的一个动画列表 这个列表并没什么特别难点,只不过我把这些融合在一起 方便一次性找到 不用挨个百度 。最下方附带dome

简介:自定义Recyalerview 折叠效果

adapter里面的图片使用自定义的imagview VR效果

MyItemTouchCallback 制作拖动效果

首先自定义RecyclerView  这个只是为了达到折叠

//自定义view 
public class ParallaxRecyclerView extends RecyclerView {

    public ParallaxRecyclerView(Context context) {
        this(context, null);
    }

    public ParallaxRecyclerView(final Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        if (isInEditMode()) {
            return;
        }

        setLayoutManager(new LinearLayoutManager(context));

        addItemDecoration(new ItemDecoration() {
            @Override
            public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) {
                super.getItemOffsets(outRect, view, parent, state);
                //获取当前项的下标
                final int currentPosition = parent.getChildLayoutPosition(view);
                //获取最后一项的下标
                final int lastPosition = state.getItemCount() - 1;
                if (currentPosition != lastPosition) {
                    outRect.bottom = -dp2px(context, 10);
                }
            }
        });

        addOnScrollListener(new OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                //   final GridLayoutManager layoutManager = new GridLayoutManager(getActivity(),2);
                GridLayoutManager layoutManager = (GridLayoutManager) recyclerView.getLayoutManager();
                int firstPosition = layoutManager.findFirstVisibleItemPosition();
                int lastPosition = layoutManager.findLastVisibleItemPosition();
                int visibleCount = lastPosition - firstPosition;
                //重置控件的位置及高度
                int elevation = 2;
                for (int i = firstPosition - 1; i <= (firstPosition + visibleCount) + 1; i++) {
                    View view = layoutManager.findViewByPosition(i);
                    if (view != null) {
                        if (view instanceof CardView) {
                            firstPosition ++;
                            ((CardView) view).setCardElevation(dp2px(context, elevation));
                            elevation += 5;
                        }
                        float translationY = view.getTranslationY();
                        if (i > firstPosition && translationY != 0) {
                            view.setTranslationY(0);
                        }
                    }
                }

                View firstView = layoutManager.findViewByPosition(firstPosition);
                if (firstView != null) {
                    float firstViewTop = firstView.getTop();
                    firstView.setTranslationY(-firstViewTop / 2.0f);
                }
//这里这段 如果不是两列的可以删掉
                View firstViews = layoutManager.findViewByPosition(firstPosition+1);
                if (firstViews != null) {
                    float firstViewTop = firstViews.getTop();
                    firstViews.setTranslationY(-firstViewTop / 2.0f);
                }
            }
        });
    }

    private int dp2px(Context context, float dipValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }

}
集成进来 大家就会发现  滑动列表时候最上面的两条item有个折叠效果,网站有很多例子 这个 特别的就是集成了一个两列的  得到群里一个大神的帮助写出来的 ,本人表示这些代码根本看不懂!

接下来是vr效果 首先拿 也是集成一个自定义view 

这个控件继承了 picasso的效果 附带集成代码,dome上使用的比较旧 打包的时候出错了 下面是最新的picasso 

compile 'com.squareup.picasso:picasso:2.5.2'
/**
 * 创建时间: 2018/01/12 12:13 <br>
 * 作者: jiangye <br>  
 * 描述: 可随陀螺仪滑动的自定义 ImageView 控件
 */
//以上是作者的名字  
public class GyroscopeImageView extends ImageView {

  private double mScaleX;
  private double mScaleY;
  private float mLenX;
  private float mLenY;
  protected double mAngleX;
  protected double mAngleY;
  private float mOffsetX;
  private float mOffsetY;

  public GyroscopeImageView(Context context) {
    super(context);
    init();
  }

  public GyroscopeImageView(Context context, @Nullable AttributeSet attrs) {
    super(context, attrs);
    init();
  }

  public GyroscopeImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
  }

  private void init() {
    setScaleType(ScaleType.CENTER);
  }

  @Override
  public void setScaleType(ScaleType scaleType) {
    super.setScaleType(ScaleType.CENTER);
  }

  public float getOffsetX() {
    return mOffsetX;
  }

  public float getOffsetY() {
    return mOffsetY;
  }

  @Override
  protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    GyroscopeManager gyroscopeManager = GyroscopeManager.getInstance();
    if (gyroscopeManager != null) {
      gyroscopeManager.addView(this);
    }
  }

  @Override
  protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    GyroscopeManager gyroscopeManager = GyroscopeManager.getInstance();
    if (gyroscopeManager != null) {
      gyroscopeManager.removeView(this);
    }
  }

  public void update(double scaleX, double scaleY) {
    mScaleX = scaleX;
    mScaleY = scaleY;
    invalidate();
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
    int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
    if (getDrawable() != null) {
      int drawableWidth = getDrawable().getIntrinsicWidth();
      int drawableHeight = getDrawable().getIntrinsicHeight();
      mLenX = Math.abs((drawableWidth - width) * 0.5f);
      mLenY = Math.abs((drawableHeight - height) * 0.5f);
    }
  }

  @Override
  protected void onDraw(Canvas canvas) {
    if (getDrawable() == null || isInEditMode()) {
      super.onDraw(canvas);
      return;
    }
    mOffsetX = (float) (mLenX * mScaleX);
    mOffsetY = (float) (mLenY * mScaleY);
    canvas.save();
    canvas.translate(mOffsetX, mOffsetY);
    super.onDraw(canvas);
    canvas.restore();
  }

  @Override
  public boolean equals(Object obj) {
    return super.equals(obj);
  }

  @Override
  public int hashCode() {
    return super.hashCode();
  }
}

以下这两个直接复制粘贴就可以 

package com.example.jiangye.demo.gyroscope;

import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.view.View;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 创建时间: 2018/01/12 12:13 <br>
 * 作者: jiangye <br>
 * 描述: GyroscopeImageView的 陀螺仪 控制器
 */

public class GyroscopeManager implements SensorEventListener {

  private static final String TAG = GyroscopeManager.class.getSimpleName();

  /**
   * 将纳秒转化为秒
   */
  private static final float NS2S = 1.0f / 1000000000.0f;

  /**
   * 维护 GyroscopeImageView 的 状态, 需要传感器处理的 GyroscopeImageView 其对应的 value 为 true
   */
  private Map<GyroscopeImageView, Boolean> mViewsMap = new HashMap<>(9);

  /**
   * 维护需要传感器处理的 Activity
   */
  private List<Activity> mActivityList = new ArrayList<>();

  private SensorManager sensorManager;
  private long mLastTimestamp;
  private double mMaxAngle = Math.PI / 2;

  private GyroscopeManager() {
  }

  private static class InstanceHolder {
    private static final GyroscopeManager sGyroscopeManager = new GyroscopeManager();
  }

  public static GyroscopeManager getInstance() {
    return InstanceHolder.sGyroscopeManager;
  }

  protected void addView(GyroscopeImageView gyroscopeImageView) {
    if (mActivityList.contains(getActivityFromView(gyroscopeImageView))) {
      mViewsMap.put(gyroscopeImageView, true);
    } else {
      mViewsMap.put(gyroscopeImageView, false);
    }
  }

  protected void removeView(GyroscopeImageView gyroscopeImageView) {
    mViewsMap.remove(gyroscopeImageView);
  }

  public void register(Activity activity) {
    mActivityList.add((activity));
    for (GyroscopeImageView view : mViewsMap.keySet()) {
      for (Activity a : mActivityList) {
        if (getActivityFromView(view) == a) {
          mViewsMap.put(view, true);
        }
      }
    }

    if (sensorManager == null) {
      sensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
    }

    Sensor sensor;

    if (sensorManager != null) {
      sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
      //灵敏度从快到慢 可选择: SENSOR_DELAY_FASTEST; SENSOR_DELAY_GAME; SENSOR_DELAY_NORMAL; SENSOR_DELAY_UI
      sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME);
      mLastTimestamp = 0;
    }
  }

  public void unregister(Activity activity) {
    mActivityList.remove((activity));
    for (GyroscopeImageView view : mViewsMap.keySet()) {
      if (getActivityFromView(view) == activity) {
        mViewsMap.put(view, false);
      }
    }
    sensorManager.unregisterListener(this);
    sensorManager = null;
  }

  @Override public void onSensorChanged(SensorEvent event) {

    if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
      if (mLastTimestamp != 0) {
        for (Map.Entry<GyroscopeImageView, Boolean> entry : mViewsMap.entrySet()) {
          //只处理集合中 value 为 true 的 view
          if (entry.getValue()) {
            entry.getKey().mAngleX +=
                event.values[0] * (event.timestamp - mLastTimestamp) * NS2S * 2.0f;
            entry.getKey().mAngleY +=
                event.values[1] * (event.timestamp - mLastTimestamp) * NS2S * 2.0f;
            if (entry.getKey().mAngleX > mMaxAngle) {
              entry.getKey().mAngleX = mMaxAngle;
            }
            if (entry.getKey().mAngleX < -mMaxAngle) {
              entry.getKey().mAngleX = -mMaxAngle;
            }
            if (entry.getKey().mAngleY > mMaxAngle) {
              entry.getKey().mAngleY = mMaxAngle;
            }
            if (entry.getKey().mAngleY < -mMaxAngle) {
              entry.getKey().mAngleY = -mMaxAngle;
            }
            entry.getKey()
                .update(entry.getKey().mAngleY / mMaxAngle, entry.getKey().mAngleX / mMaxAngle);
          }
        }
      }
      mLastTimestamp = event.timestamp;
    }
  }

  @Override public void onAccuracyChanged(Sensor sensor, int accuracy) {

  }

  private Activity getActivityFromView(View view) {
    return (Activity) view.getContext();
  }
}

 

public class GyroscopeTransFormation implements Transformation {

  private int mWidgetWidth;   //控件宽度
  private int mWidgetHeight;  //控件高度
  private double mTargetWidth;    //目标宽度
  private double mTargetHeight;   //目标高度

  public GyroscopeTransFormation(int widgetWidth, int widgetHeight) {
    mWidgetWidth = widgetWidth;
    mWidgetHeight = widgetHeight;
  }

  @Override public Bitmap transform(Bitmap source) {

    if (source.getWidth() == 0 || source.getHeight() == 0) {
      return source;
    }

    mTargetWidth = source.getWidth();
    mTargetHeight = source.getHeight();

    double ratio = mTargetWidth / mTargetHeight;     //图片的宽高比
    int distance;                                    //图片缩放后与控件边的距离

    if (mWidgetHeight <= mWidgetWidth) {
      distance = mWidgetHeight / 8;
      mTargetWidth = mWidgetWidth + 2 * distance;
      mTargetHeight = mTargetWidth / ratio;
    } else {
      distance = mWidgetWidth / 8;
      mTargetHeight = mWidgetHeight + 2 * distance;
      mTargetWidth = mTargetHeight * ratio;
    }

    int desiredWidth = (int) mTargetWidth;
    int desiredHeight = (int) mTargetHeight;

    Bitmap result = Bitmap.createScaledBitmap(source, desiredWidth, desiredHeight, false);

    if (result != source) {
      // Same bitmap is returned if sizes are the same
      source.recycle();
    }
    return result;
  }

  @Override public String key() {
    return "";
  }
}

这是在引用adapter的activity 的两个监听器

@Override protected void onResume() {
    super.onResume();
    //利用我们的 GyroscopeManager 来注册传感器监听
    GyroscopeManager.getInstance().register(this);
  }

  @Override protected void onPause() {
    super.onPause();
    //利用我们的 GyroscopeManager 来注销监听
    GyroscopeManager.getInstance().unregister(this);
  }

引用自定义view就不bb了 然后就是每个time的显示imagview的代码  其实这个可以用你原本写的显示图片的的代码 只不过使用picasso可控制里面可以控制图片的大小,有些从网络上获取的参数图片大小不一样 如果不进行拉伸或者缩小 效果会很差,transform里面就是给图片固定的宽高  不管图片多大 都把图片的宽高写死 ps:VR效果根据图片的宽高做的效果 只要不小于view就可以显示效果  

我这边是用的这个控件 不懂就去百度  

int displayHeight = DeviceDimensionsHelper.getDisplayWidth(iv_cover.getContext());
  Picasso.with(context)
                .load(item.getCover())
//这里宽高 ,别无脑复制 (w,h) 
                .transform(new GyroscopeTransFormation(displayHeight / 2 - 20, displayHeight / 2 - 20))
                .into(iv_cover);

ok!运行 晃动下手机 !是不是炫

 

下面在做拖动效果 这个比上面的稍微复杂一点   你们只需要耐心的看完我的BB就可以继承进来 

首先 写adapter 这个用过rv的同学都有基础 因为我项目的adapter是自定义的 解释起来比较麻烦,所以只给部分需要的代码 ,你们就按照你们的rv开始写 

首先

final GridLayoutManager layoutManager = new GridLayoutManager(getActivity(),2);//两列
mRecyclerView.setLayoutManager(layoutManager);//继承两列
mRecyclerView.setItemAnimator(new DefaultItemAnimator());//嘿嘿 

在添加数据后 setadapter前添加

MyItemTouchCallback callback = new MyItemTouchCallback(mHomeAdapter);
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(callback);
itemTouchHelper.attachToRecyclerView(mRecyclerView);

MyItemTouchCallback

public class MyItemTouchCallback extends ItemTouchHelper.Callback {

    private HomeAdapter<IndexListBean.DataBean> adapter;

    private int mBackgroundColor = Color.WHITE;
    private int mDragcolor = Color.parseColor("#f5f5f5");

    public MyItemTouchCallback(HomeAdapter<IndexListBean.DataBean> adapter){
        this.adapter = adapter;
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        if (recyclerView.getLayoutManager() instanceof GridLayoutManager) {
            final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
            final int swipeFlags = 0;
            return makeMovementFlags(dragFlags, swipeFlags);
        } else {
            final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
            //final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
            final int swipeFlags = 0;
            return makeMovementFlags(dragFlags, swipeFlags);
        }
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        int fromPosition = viewHolder.getAdapterPosition();//得到拖动ViewHolder的position
        int toPosition = target.getAdapterPosition();//得到目标ViewHolder的position
        adapter.onMove(fromPosition,toPosition);
        return true;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        int position = viewHolder.getAdapterPosition();
        adapter.onSwiped(position);
    }

    @Override
    public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
//            滑动时改变Item的透明度
            final float alpha = 1 - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
            viewHolder.itemView.setAlpha(alpha);
            viewHolder.itemView.setTranslationX(dX);
        } else {
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }
    }

    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
            viewHolder.itemView.setBackgroundColor(mDragcolor);
        }
        super.onSelectedChanged(viewHolder, actionState);
    }

    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        viewHolder.itemView.setAlpha(1.0f);
        viewHolder.itemView.setBackgroundColor(mBackgroundColor);
    }

    /**
     * 设置普通状态的背景色
     * @param backgroundColor
     */
    public void setBackgroundColor(int backgroundColor){
        mBackgroundColor = backgroundColor;
    }

    /**
     * 设置被拖动时候的背景色
     * @param dragcolor
     */
    public void setDragcolor(int dragcolor){
        mDragcolor = dragcolor;
    }



}

在这个关联的adapter里面添加抽象类 

implements DragMethod

DragMethod

public interface DragMethod {
    public void onMove(int fromPosition, int toPosition);
    public void onSwiped(int position);
}

在adapter里面添加代码

  @Override
    public void onMove(int fromPosition, int toPosition) {
        if (fromPosition == mData.size() - 1 || toPosition == mData.size() - 1) {
            return;
        }
        if (fromPosition < toPosition) {
            for (int i = fromPosition; i < toPosition; i++) {
                Collections.swap(mData, i, i + 1);
            }
        } else {
            for (int i = fromPosition; i > toPosition; i--) {
                Collections.swap(mData, i, i - 1);
            }
        }
        notifyItemMoved(fromPosition, toPosition);
    }

    @Override
    public void onSwiped(int position) {
        mData.remove(position);
        notifyItemRemoved(position);
    }

    @Override
    public int getItemCount() {
        return mData.size();
    }

ok  运行!

dome地址

gethub

阅读更多
个人分类: android 技术迷
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭