首页 > 代码库 > Android自定义Viewgroup切换View带有吸附效果
Android自定义Viewgroup切换View带有吸附效果
1.概述
先上效果图
大概就是这个效果,先说说实现思路
1.首先我们要拿到图片的url(网络)或id、路径(本地),将View与数据进行绑定,写我们自己的Adapter
2.自定义Viewgroup将要显示的view进行布局,以及处理触摸事件进行逻辑处理
3.写切换回调
2.实现
1)自定义Adapter
这里我下载的网络图片,同样可以将图片放到res下设置ImageView的内容
public class DragPageViewAdapter { private static final String TAG = "DragPageViewAdapter"; private List<WxCollocationRandomList> mDatas; private Context mContext; private LayoutInflater inflater; /** * 宽和高 */ int width; int height; public DragPageViewAdapter(Context mContext) { this.mContext = mContext; inflater = LayoutInflater.from(mContext); width = (int) (0.8*DragViewActivity.mScreenWidth);<span style="font-family: Arial, Helvetica, sans-serif;">//宽是屏幕宽度的0.8</span> height = (int) (0.8*DragViewActivity.mScreenWidth); } public int getCount(){ return mDatas==null?0:mDatas.size(); } public int getItemId(int position){ return position; } public Object getItem(int position){ return mDatas==null?null:mDatas.get(position); } public View getView(int position, View convertView, ViewGroup parent){ LogHelper.d(TAG, "position :" + position); final ImageView imageView = new ImageView(mContext); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(width,height); params.addRule(Gravity.CENTER); imageView.setLayoutParams(params); imageView.setBackgroundDrawable(mContext.getResources().getDrawable(R.drawable.gray_border)); ViewHelper.setAlpha(imageView,1.0f); String url = mDatas.get(position).getPictureUrl(); if (!Utils.stringIsNull(url)){ url = url.substring(0, url.lastIndexOf(".")) + "--300x300.png"; // UILHelper.loadImageUrl(url, imageView,0); UILHelper.loadImageUrl(url, new SimpleImageLoadingListener(){ @Override public void onl oadingComplete(String imageUri, View view, Bitmap loadedImage) { imageView.setImageBitmap(loadedImage); } }); } convertView = imageView; convertView.setTag(mDatas.get(position)); // viewHolder.mImageView.setImageResource((Integer) mDatas.get(position)); return convertView; } public void setData(List data){ mDatas = data; } private class ViewHolder{ ImageView mImageView; } }
通过此Adapter将所需要的图片匆网络下载下来,当我们需要的时候ImageView自己去请求下载。并将数据通过setTag的方法与ImageView进行绑定
2)自定义Viewgroup
直接上代码,我们要做的事情
a.onMeasure方法测量子自己及子view
b.onLayout方法给子view进行布局
c.onTouchEvent处理触摸事件,up的时候判断是否切换下一个view,如果不是的话通过属性动画将view的状态恢复
d.绑定切换的回调
e.切换后把当前的View从viewgruop中remove掉,add一个需要加载的view,同时给当前view赋值为切换的view,保证viewgroup中不多于指定的子view个数,保证不OOM
public class DragPageView extends ViewGroup{ private static final String TAG = "DragPageView"; /** * 适配器 */ private DragPageViewAdapter mAdapter; /** * view的个数 */ private int ONE_SCREEN_COUNT = 2; /** * 屏幕的宽和高 */ private int mScrenWidth; private int mScreenHeight; /** * 子元素的宽 高 */ private int mChildWidth; private int mChildHeight; /** * 当前最后一张图片的index */ private int mLastIndex; /** * 当前第一张图片的下标 */ private int mFirstIndex; /** * 当前显示View */ private View mFirstView; /** * 之前触摸的x y */ private int mDownX; private int mDownY; /** * 当前触摸的x y */ private int mCurX; private int mCurY; public static int mDirection = -1; public static final int DIRECTION_LEFT_TO_RIGHT = 1; public static final int DIRECTION_RIGHT_TO_LEFT = 2; /** * 保存View与位置的键值对 */ private Map<Integer,View> mViewMap = new HashMap<Integer, View>(); /** * 最大旋转角度 */ private int ROTATE_DEGREE = 30; private int CHILD_OFFSET = 10; /** * 保存回调接口 */ private OnImageSavedListener mOnImageSavedListener; public void setOnImageSavedListener(OnImageSavedListener mOnImageSavedListener) { this.mOnImageSavedListener = mOnImageSavedListener; } public DragPageView(Context context) { this(context, null); } public DragPageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public DragPageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //获得屏幕宽和高 WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics metrics = new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(metrics); mScrenWidth = metrics.widthPixels; mScreenHeight = metrics.heightPixels; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { /** * 获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式 */ int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); // 计算出所有的childView的宽和高 measureChildren(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(mScrenWidth, sizeHeight); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { for (int i = 0; i < getChildCount(); i++){ View child = getChildAt(i); mChildWidth = child.getMeasuredWidth(); mChildHeight = child.getMeasuredHeight(); int left = getWidth()/2-mChildWidth/2; int top = getHeight()/2- mChildHeight*2/3; int right = left + mChildWidth; int bottom = top + mChildHeight; if (i == 0) child.layout(left+CHILD_OFFSET, top+CHILD_OFFSET, right+CHILD_OFFSET, bottom+CHILD_OFFSET); else child.layout(left, top, right, bottom); } } public void initDatas(DragPageViewAdapter mAdapter){ this.mAdapter = mAdapter; initView(); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void initView() { removeAllViews(); for (int i = 0; i < ONE_SCREEN_COUNT; i++){ View view = mAdapter.getView(i, null, this); mViewMap.put(i,view); } //mViewMap中存放的view倒叙添加到ViewGroup,因为ViewGroup index = 0在最底层 for (int j= ONE_SCREEN_COUNT -1; j>=0;j--){ addView(mViewMap.get(j)); if (j == 0){ mFirstView = mViewMap.get(j); } } mLastIndex = ONE_SCREEN_COUNT -1; mFirstIndex = mLastIndex - ONE_SCREEN_COUNT-1; } @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override public boolean onTouchEvent(MotionEvent event) { int focusX = (int) event.getX(); int focusY = (int) event.getY(); switch (event.getAction()){ case MotionEvent.ACTION_DOWN: mDownX = mCurX = focusX; mDownY = mCurY = focusY; break; case MotionEvent.ACTION_MOVE: final int deltaX = focusX - mCurX; final int deltaY = focusY-mCurY ; if (Math.abs(deltaX) > 5 || Math.abs(deltaY)>5){ if (focusX > mDownX){ mDirection = DIRECTION_LEFT_TO_RIGHT; }else { mDirection = DIRECTION_RIGHT_TO_LEFT; } handlerScroll(deltaX, deltaY); // mFirstView.setPivotX((float) (mFirstView.getMeasuredWidth()*0.5)); // mFirstView.setPivotY(mFirstView.getMeasuredHeight()); mFirstView.setRotation(ROTATE_DEGREE*(focusX-mDownX)/mChildWidth); } mCurX = focusX; mCurY = focusY; break; case MotionEvent.ACTION_UP: LogHelper.d(TAG, "mPreX : " + mDownX + " mPreY " + mDownY + " mCurX : " + mCurX + " mCurY : " + mCurY); if (Math.abs(mCurX- mDownX)> mChildWidth/2 && mLastIndex < mAdapter.getCount()){ loadNextImage(); }else { resetView(); } break; } return true; } private void resetView() { PropertyValuesHolder oaX= PropertyValuesHolder.ofFloat("translationX", 0); PropertyValuesHolder oaY = PropertyValuesHolder.ofFloat("translationY",0); PropertyValuesHolder rotate = PropertyValuesHolder.ofFloat("rotation",0); ObjectAnimator.ofPropertyValuesHolder(mFirstView, oaX, oaY, rotate).start(); } public void loadNextImage() { ObjectAnimator oaX = null; ObjectAnimator oaRotate = null; if (mLastIndex == mAdapter.getCount()) return; if (mDirection == DIRECTION_LEFT_TO_RIGHT){ oaX = new ObjectAnimator().ofFloat(mFirstView, "translationX",800); oaRotate = new ObjectAnimator().ofFloat(mFirstView, "rotation",ROTATE_DEGREE); //通知回调已保存的view if (mOnImageSavedListener != null){ mOnImageSavedListener.onImageSaved(mFirstView); } }else { oaX = new ObjectAnimator().ofFloat(mFirstView, "translationX", -800); oaRotate = new ObjectAnimator().ofFloat(mFirstView, "rotation", -ROTATE_DEGREE); if (mOnImageSavedListener != null){ mOnImageSavedListener.onImageDelete(mFirstView); } } oaX.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { //动画结束后load下一张图片 mViewMap.remove(mFirstIndex); //删除view removeAllViews(); //获取下一张图片 if ((mLastIndex+1)>= mAdapter.getCount()){ addView(mViewMap.get(mLastIndex)); }else { View view = mAdapter.getView(++mLastIndex, null, DragPageView.this); mViewMap.put(mLastIndex, view); addView(mViewMap.get(mLastIndex)); addView(mViewMap.get(mLastIndex-1)); mFirstView = mViewMap.get(mLastIndex-1); } } }); //开启动画 oaRotate.start(); oaX.start(); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) private void handlerScroll(float distanceX, float distanceY) { int newLeft = (int) (mFirstView.getLeft()+distanceX); int newTop = (int) (mFirstView.getTop()+distanceY); float[] deltaVector = {distanceX, distanceY}; mFirstView.getMatrix().mapVectors(deltaVector); mFirstView.setTranslationX(mFirstView.getTranslationX() + deltaVector[0]); mFirstView.setTranslationY(mFirstView.getTranslationY() + deltaVector[1]); } public interface OnImageSavedListener{ public void onImageSaved(View view); public void onImageDelete(View view); } }
3)Activity
负责的事情
a.请求数据初始化Adapter及ViewGroup
b.切换回调的响应
c.点击按键切换的事件处理
public class DragViewActivity extends BaseActivity{ private static final String TAG = "DragViewActivity"; private DragPageViewAdapter adapter; private DragPageView mDragView; private int pageIndex = 1; private int pageSize = 21; private int total; /** * userId */ private String userId; //网路请求的数据 private List<WxCollocationRandomList> lists; //保存的view的信息 private List<WxCollocationRandomList> mSavedView; private WxCollocationRandomList mViewInfo; /** * 屏幕宽和高 */ public static int mScreenWidth; public static int mScreenHeight; private TextView mSkip; private TextView mSave; private TextView mDone; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.dragview_act); WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); DisplayMetrics displayMetrics = new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(displayMetrics); mScreenWidth = displayMetrics.widthPixels; mScreenHeight = displayMetrics.heightPixels; userId = SettingsManager.getSettingsManager(this).getUserId(); initView(); httpGetImageInfo(pageIndex); } private void httpGetImageInfo(final int pageIndex) { JSONObject object = new JSONObject(); try { object.put("pageIndex", pageIndex); object.put("pageSize", pageSize); } catch (JSONException e) { e.printStackTrace(); } if (pageIndex == 1) { showProgress(getResources().getString(R.string.app_data_loading)); } HttpsRequestUtil.doHttpsVolleyPost(this, SOAServices.COLLOCATION_SERVICE, SOAMethods.RANDOM_COLLOCATION, HttpsRequestUtil.GET, object, new Response.Listener<String>(){ @Override public void onResponse(String response) { if (pageIndex ==1){ closeProgress(); } transformData(response); } }, new Response.ErrorListener(){ @Override public void one rrorResponse(VolleyError error) { closeProgress(); } }); } /** * 请求的数据,进行初始化adapter及Viewgroup的初始化 * @param response */ private void transformData(String response) { Gson gson = new Gson(); WxCollocationRandomFilter wxCollocationRandomFilter= gson.fromJson(response, WxCollocationRandomFilter.class); total = wxCollocationRandomFilter.getTotal(); if (total == 0)return; lists = wxCollocationRandomFilter.getCollocationRandomLists(); adapter.setData(lists); mDragView.initDatas(adapter); } private void initView() { mDragView = (DragPageView) findViewById(R.id.dragView); adapter = new DragPageViewAdapter(this); mDragView.setOnImageSavedListener(new DragPageView.OnImageSavedListener() { @Override public void onImageSaved(View view) { mViewInfo = (WxCollocationRandomList) view.getTag(); httpSaveFavorite(mViewInfo); } @Override public void onImageDelete(View view) { mViewInfo = (WxCollocationRandomList) view.getTag(); httpDeleteFavorite(mViewInfo); } }); mSkip = (TextView) findViewById(R.id.skip); mSave = (TextView) findViewById(R.id.save); mDone = (TextView) findViewById(R.id.done); mSkip.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mDragView.mDirection = mDragView.DIRECTION_RIGHT_TO_LEFT; mDragView.loadNextImage(); } }); mSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mDragView.mDirection = mDragView.DIRECTION_LEFT_TO_RIGHT; mDragView.loadNextImage(); } }); mDone.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { DragViewActivity.this.finish(); } }); } /** * 喜欢 * @param mViewInfo 搭配信息 sourcE_TYPE 1 商品 2 搭配 */ private void httpSaveFavorite(WxCollocationRandomList mViewInfo) { JSONObject jsonObject = new JSONObject(); try { jsonObject.put("sourcE_ID", mViewInfo.getId()); jsonObject.put("userId",userId); jsonObject.put("creatE_USER", mViewInfo.getCreateUser()); jsonObject.put("sourcE_TYPE", 2); } catch (JSONException e) { e.printStackTrace(); } HttpsRequestUtil.doHttpsVolleyPost(DragViewActivity.this, SOAServices.ORDER_SERVICE, SOAMethods.FAVORITE_ADD, HttpsRequestUtil.POST, jsonObject, new Response.Listener<String>() { @Override public void onResponse(String response) { LogHelper.d(TAG, "SaveFavorite Success!"); } }, new Response.ErrorListener() { @Override public void one rrorResponse(VolleyError error) { LogHelper.d(TAG, "SaveFavorite Error!"); } }); } /** * 删除喜欢 * @param mViewInfo 搭配信息 sourcE_TYPE 1 商品 2 搭配 */ private void httpDeleteFavorite(WxCollocationRandomList mViewInfo) { JSONObject jsonObject = new JSONObject(); try { jsonObject.put("sourcE_ID", mViewInfo.getId()); jsonObject.put("userId",userId); jsonObject.put("creatE_USER", mViewInfo.getCreateUser()); jsonObject.put("sourcE_TYPE", 2); } catch (JSONException e) { e.printStackTrace(); } HttpsRequestUtil.doHttpsVolleyPost(DragViewActivity.this, SOAServices.ORDER_SERVICE, SOAMethods.FAVORITE_DELETE, HttpsRequestUtil.POST, jsonObject, new Response.Listener<String>() { @Override public void onResponse(String response) { LogHelper.d(TAG, "DeleteFavorite Success!"); } }, new Response.ErrorListener() { @Override public void one rrorResponse(VolleyError error) { LogHelper.d(TAG, "DeleteFavorite Error!"); } }); } }
最后的效果还不错,感兴趣的可以研究研究。
demo 下载地址 http://download.csdn.net/detail/hlglinglong/8359097
本文参考文章:
鸿洋大神博客的
http://blog.csdn.net/lmj623565791/article/details/38140505
http://blog.csdn.net/lmj623565791/article/details/38339817
Android自定义Viewgroup切换View带有吸附效果
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。