Android自定义Viewgroup切换View带有吸附效果

来源:互联网 发布:网络延长器多少钱 编辑:程序博客网 时间:2024/05/22 13:29

转载请标明出处: 【http://blog.csdn.net/hlglinglong/article/details/42687043】

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 onLoadingComplete(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 onErrorResponse(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 onErrorResponse(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 onErrorResponse(VolleyError error) {                        LogHelper.d(TAG, "DeleteFavorite Error!");                    }                });    }}





最后的效果还不错,感兴趣的可以研究研究。
demo 下载地址 http://download.csdn.net/detail/hlglinglong/8359097  android studio开发的,eclipse导入估计有问题,简单看下代码吧

本文参考文章:
鸿洋大神博客的
http://blog.csdn.net/lmj623565791/article/details/38140505
http://blog.csdn.net/lmj623565791/article/details/38339817

如果对你有帮助的话点个赞留个言呗~
0 0
原创粉丝点击