前言

经常逛今日头条、发现它的频道管理功能做的特别赞,交互体验非常好、如图:


它是2个gridview组成、2个gridview之间的Item是可以相互更换的、而且我的频道的Item是可以拖拽进行排序。仔细观察、今日头条有些细节做的的非常好,当一个gridview1的item移动到另一个gridview2时、gridview1的item不会立即消失、而是有一个没有内容的背景框、等item移动gridview2操作完毕才会消失、并且gridview2在gridview1的Item到达之前也有一个没有内容的背景框,等到达后覆盖。给用户一个很强的交互体验,很赞。而且在item拖拽移动排序时、拖拽的item会变大变色、效果很赞,体验极好。感兴趣的话可以下一个今日头条的客户端看看。当看到这么赞的交互体验,我就想看看是怎么实现的,这篇博客先讲2个Gridview之间item的移动,下一篇在带来gridview的拖拽排序。

实现思路

要实现2个gridview之间的Item相互移动:

1、首先我们获取我们点击的位置、处于gridview哪个位置

2、获取位置后、我们就能拿到这个Item的View,我们获取item绘制缓存的Bitmap对象。

3、将Bitmap设置的一个Imageview上,然后将这个ImageView放到一个容器中去进行移动操作,这样可能有人有疑问,为什么不直接把item放到容器中去呢,是因为item已经有自己的父容器gridview,所以我们new一个Imageview来代替item

4、然后我们将imageview移动到另一个gridview的最后一个位置。

5、最后刷新2个gridview的视图、就能实现我们所见的效果。

实现代码

主程序代码:

package com.test.drag;import android.graphics.Bitmap;import android.os.Bundle;import android.os.Handler;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.view.ViewGroup;import android.view.animation.Animation;import android.view.animation.AnimationSet;import android.view.animation.TranslateAnimation;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.GridView;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.TextView;import com.test.drag.view.MyGridView;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity implements OnItemClickListener {    private MyGridView mUserGv, mOtherGv;    private List mUserList = new ArrayList<>();    private List mOtherList = new ArrayList<>();    private OtherAdapter mUserAdapter, mOtherAdapter;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();    }    public void initView() {        mUserGv = (MyGridView) findViewById(R.id.userGridView);        mOtherGv = (MyGridView) findViewById(R.id.otherGridView);        mUserList.add("推荐");        mUserList.add("热点");        mUserList.add("上海");        mUserList.add("时尚");        mUserList.add("科技");        mUserList.add("体育");        mUserList.add("军事");        mUserList.add("财经");        mUserList.add("网络");        mOtherList.add("汽车");        mOtherList.add("房产");        mOtherList.add("社会");        mOtherList.add("情感");        mOtherList.add("女人");        mOtherList.add("旅游");        mOtherList.add("健康");        mOtherList.add("美女");        mOtherList.add("游戏");        mOtherList.add("数码");        mOtherList.add("娱乐");        mOtherList.add("探索");        mUserAdapter = new OtherAdapter(this, mUserList,true);        mOtherAdapter = new OtherAdapter(this, mOtherList,false);        mUserGv.setAdapter(mUserAdapter);        mOtherGv.setAdapter(mOtherAdapter);        mUserGv.setOnItemClickListener(this);        mOtherGv.setOnItemClickListener(this);    }    /**     *获取点击的Item的对应View,     *因为点击的Item已经有了自己归属的父容器MyGridView,所有我们要是有一个ImageView来代替Item移动     * @param view     * @return     */    private ImageView getView(View view) {        view.destroyDrawingCache();        view.setDrawingCacheEnabled(true);        Bitmap cache = Bitmap.createBitmap(view.getDrawingCache());        view.setDrawingCacheEnabled(false);        ImageView iv = new ImageView(this);        iv.setImageBitmap(cache);        return iv;    }    /**     * 获取移动的VIEW,放入对应ViewGroup布局容器     * @param viewGroup     * @param view     * @param initLocation     * @return     */    private View getMoveView(ViewGroup viewGroup, View view, int[] initLocation) {        int x = initLocation[0];        int y = initLocation[1];        viewGroup.addView(view);        LinearLayout.LayoutParams mLayoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);        mLayoutParams.leftMargin = x;        mLayoutParams.topMargin = y;        view.setLayoutParams(mLayoutParams);        return view;    }    /**     * 创建移动的ITEM对应的ViewGroup布局容器     * 用于存放我们移动的View     */    private ViewGroup getMoveViewGroup() {        //window中最顶层的view        ViewGroup moveViewGroup = (ViewGroup) getWindow().getDecorView();        LinearLayout moveLinearLayout = new LinearLayout(this);        moveLinearLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));        moveViewGroup.addView(moveLinearLayout);        return moveLinearLayout;    }    /**     * 点击ITEM移动动画     *     * @param moveView     * @param startLocation     * @param endLocation     * @param moveChannel     * @param clickGridView     */    private void MoveAnim(View moveView, int[] startLocation, int[] endLocation, final String moveChannel,                          final GridView clickGridView, final boolean isUser) {        int[] initLocation = new int[2];        //获取传递过来的VIEW的坐标        moveView.getLocationInWindow(initLocation);        //得到要移动的VIEW,并放入对应的容器中        final ViewGroup moveViewGroup = getMoveViewGroup();        final View mMoveView = getMoveView(moveViewGroup, moveView, initLocation);        //创建移动动画        TranslateAnimation moveAnimation = new TranslateAnimation(                startLocation[0], endLocation[0], startLocation[1],                endLocation[1]);        moveAnimation.setDuration(300L);//动画时间        //动画配置        AnimationSet moveAnimationSet = new AnimationSet(true);        moveAnimationSet.setFillAfter(false);//动画效果执行完毕后,View对象不保留在终止的位置        moveAnimationSet.addAnimation(moveAnimation);        mMoveView.startAnimation(moveAnimationSet);        moveAnimationSet.setAnimationListener(new Animation.AnimationListener() {            @Override            public void onAnimationStart(Animation animation) {            }            @Override            public void onAnimationRepeat(Animation animation) {            }            @Override            public void onAnimationEnd(Animation animation) {                moveViewGroup.removeView(mMoveView);                // 判断点击的是DragGrid还是OtherGridView                if (isUser) {                    mOtherAdapter.setVisible(true);                    mOtherAdapter.notifyDataSetChanged();                    mUserAdapter.remove();                } else {                    mUserAdapter.setVisible(true);                    mUserAdapter.notifyDataSetChanged();                    mOtherAdapter.remove();                }            }        });    }    @Override    public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {        switch (parent.getId()) {            case R.id.userGridView:                //position为 0,1 的不可以进行任何操作                if (position != 0 && position != 1) {                    final ImageView moveImageView = getView(view);                    if (moveImageView != null) {                        TextView newTextView = (TextView) view.findViewById(R.id.text_item);                        final int[] startLocation = new int[2];                        newTextView.getLocationInWindow(startLocation);                        final String channel = ((OtherAdapter) parent.getAdapter()).getItem(position);//获取点击的频道内容                        mOtherAdapter.setVisible(false);                        //添加到最后一个                        mOtherAdapter.addItem(channel);                        new Handler().postDelayed(new Runnable() {                            public void run() {                                try {                                    int[] endLocation = new int[2];                                    //获取终点的坐标                                    mOtherGv.getChildAt(mOtherGv.getLastVisiblePosition()).getLocationInWindow(endLocation);                                    MoveAnim(moveImageView, startLocation, endLocation, channel, mUserGv, true);                                    mUserAdapter.setRemove(position);                                } catch (Exception localException) {                                }                            }                        }, 50L);                    }                }                break;            case R.id.otherGridView:                final ImageView moveImageView = getView(view);                if (moveImageView != null) {                    TextView newTextView = (TextView) view.findViewById(R.id.text_item);                    final int[] startLocation = new int[2];                    newTextView.getLocationInWindow(startLocation);                    final String channel = ((OtherAdapter) parent.getAdapter()).getItem(position);                    mUserAdapter.setVisible(false);                    //添加到最后一个                    mUserAdapter.addItem(channel);                    new Handler().postDelayed(new Runnable() {                        public void run() {                            try {                                int[] endLocation = new int[2];                                //获取终点的坐标                                mUserGv.getChildAt(mUserGv.getLastVisiblePosition()).getLocationInWindow(endLocation);                                MoveAnim(moveImageView, startLocation, endLocation, channel, mOtherGv,false);                                mOtherAdapter.setRemove(position);                            } catch (Exception localException) {                            }                        }                    }, 50L);                }                break;            default:                break;        }    }}

适配器代码:

package com.test.drag;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.TextView;import java.util.List;/** * Created by fuweiwei on 2016/1/8. */public class OtherAdapter extends BaseAdapter {    private Context context;    public List channelList;    private TextView item_text;    /** 是否可见 在移动动画完毕之前不可见,动画完毕后可见*/    boolean isVisible = true;    /** 要删除的position */    public int remove_position = -1;    /** 是否是用户频道 */    private boolean isUser = false;    public OtherAdapter(Context context, List channelList ,boolean isUser) {        this.context = context;        this.channelList = channelList;        this.isUser = isUser;    }    @Override    public int getCount() {        return channelList == null ? 0 : channelList.size();    }    @Override    public String getItem(int position) {        if (channelList != null && channelList.size() != 0) {            return channelList.get(position);        }        return null;    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        View view = LayoutInflater.from(context).inflate(R.layout.adapter_mygridview_item, null);        item_text = (TextView) view.findViewById(R.id.text_item);        String channel = getItem(position);        item_text.setText(channel);        if(isUser){            if ((position == 0) || (position == 1)){                item_text.setEnabled(false);            }        }        if (!isVisible && (position == -1 + channelList.size())){            item_text.setText("");            item_text.setSelected(true);            item_text.setEnabled(true);        }        if(remove_position == position){            item_text.setText("");        }        return view;    }    /** 获取频道列表 */    public List getChannnelLst() {        return channelList;    }    /** 添加频道列表 */    public void addItem(String channel) {        channelList.add(channel);        notifyDataSetChanged();    }    /** 设置删除的position */    public void setRemove(int position) {        remove_position = position;        notifyDataSetChanged();        // notifyDataSetChanged();    }    /** 删除频道列表 */    public void remove() {        channelList.remove(remove_position);        remove_position = -1;        notifyDataSetChanged();    }    /** 设置频道列表 */    public void setListDate(List list) {        channelList = list;    }    /** 获取是否可见 */    public boolean isVisible() {        return isVisible;    }    /** 设置是否可见 */    public void setVisible(boolean visible) {        isVisible = visible;    }}


至于之前说的很赞的交互体验是怎么实现的:

1、在点击gridview1的item时(也就是Imageview移动动画开始时),我们将所点击的内容置为空,

2、在gridview1点击的同时我们在gridview2的最后面加一个我们刚点击的item,但内容显示也是空

3、当imageview移动动画结束后,我们将gridview1所点击的item移除、重新刷新界面,而gridview2我们只要设置最后一个内容显示、刷新视图。

这样就能实现今天头条一样超赞的交互体验。

其它代码:

package com.test.drag.view;import android.content.Context;import android.util.AttributeSet;import android.widget.GridView;/** * Created by fuweiwei on 2016/1/8. */public class MyGridView extends GridView {    public MyGridView(Context paramContext, AttributeSet paramAttributeSet) {        super(paramContext, paramAttributeSet);    }    @Override    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,                MeasureSpec.AT_MOST);        super.onMeasure(widthMeasureSpec, expandSpec);    }}

布局:

<?xml version="1.0" encoding="utf-8"?>                                                                                                                            

实现的效果如下:



是不是效果一模一样,很喜欢这样交互体验,这里只介绍了gridview之间item的移动,至于gridview的Item的拖拽比较复杂、会在下一篇博客记录。


源码下载







更多相关文章

  1. 一次偶然机遇找到一个不错的关于Android实现加载gif动画的实例,写
  2. Android(安卓)OpenGLES2.0(十三)——流畅的播放逐帧动画
  3. 我的工具太少了之Android无限轮播图片,最后一张过度动画很重要
  4. Android(安卓)使用动画效果后的控件位置处理 类似系统通知栏下拉
  5. Android(安卓)PowerImageView实现,可以播放动画的强大ImageView
  6. Android里的动画(补间动画,帧动画,属性动画)
  7. [置顶] 关于代码家(干货集中营)共享知识点汇总系列——Android
  8. Android共享动画兼容实现
  9. Android(安卓)动画之ScaleAnimation应用详解

随机推荐

  1. 2.运行我的第一个Android程序,学习四大组
  2. 如何让android的service一直在后台运行
  3. Android开发之语音识别
  4. 禁用GPU硬件加速方法
  5. android 使用xmpp smack openfire实现即
  6. android之基于Echart的图表
  7. Android中铃声总结【安卓源码解析一】
  8. Android手动清除APP中Data目录下的文件
  9. Android(安卓)8.0源码编译问题记录
  10. Android(安卓)彩色上下文菜单 Context