• Android 仿今日头条频道管理(上)(GridView之间Item的移动和拖拽)


    前言

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


    它是2个gridview组成、2个gridview之间的Item是能够相互更换的、并且我的频道的Item是能够拖拽进行排序。

    细致观察、今日头条有些细节做的的非常好,当一个gridview1的item移动到还有一个gridview2时、gridview1的item不会马上消失、而是有一个没有内容的背景框、等item移动gridview2操作完成才会消失、并且gridview2在gridview1的Item到达之前也有一个没有内容的背景框,等到达后覆盖。

    给用户一个非常强的交互体验,非常赞。并且在item拖拽移动排序时、拖拽的item会变大变色、效果非常赞,体验极好。感兴趣的话能够下一个今日头条的client看看。当看到这么赞的交互体验。我就想看看是怎么实现的,这篇博客先讲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<String> mUserList = new ArrayList<>();
        private List<String> 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<String> channelList;
        private TextView item_text;
        /** 是否可见 在移动动画完成之前不可见,动画完成后可见*/
        boolean isVisible = true;
        /** 要删除的position */
        public int remove_position = -1;
        /** 是否是用户频道 */
        private boolean isUser = false;
    
        public OtherAdapter(Context context, List<String> 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<String> 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<String> 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"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
        android:layout_height="match_parent" tools:context=".MainActivity">
        <ScrollView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            >
    
            <LinearLayout
                android:id="@+id/subscribe_main_layout"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical"
                android:paddingBottom="14.0dip" >
    
                <LinearLayout
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="10.0dip"
                    android:layout_marginTop="14.0dip"
                    android:gravity="bottom"
                    android:orientation="horizontal" >
    
    
                    <TextView
                        android:id="@+id/my_category_tip_text"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:textSize="13sp"
                        android:text="我的频道"
                        />
                </LinearLayout>
    
                <View
                    android:id="@+id/seperate_line"
                    android:layout_width="match_parent"
                    android:layout_marginTop="10dp"
                    android:layout_height="0.5dp"
                    android:layout_marginBottom="14.0dip"
                    android:background="@color/subscribe_item_drag_stroke" />
    
                <com.test.drag.view.MyGridView
                    android:id="@+id/userGridView"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="14dip"
                    android:layout_marginRight="14dip"
                    android:gravity="center"
                    android:horizontalSpacing="14dip"
                    android:listSelector="@android:color/transparent"
                    android:numColumns="4"
                    android:scrollbars="vertical"
                    android:stretchMode="columnWidth"
                    android:verticalSpacing="14.0px" />
    
                <View
                    android:id="@+id/seperate_line2"
                    android:layout_marginTop="10dp"
                    android:layout_width="match_parent"
                    android:layout_height="0.5dp"
                    android:background="@color/subscribe_item_drag_stroke"/>
    
                <TextView
                    android:id="@+id/more_category_text"
                    android:layout_marginBottom="14.0dip"
                    android:layout_width="wrap_content"
                    android:layout_marginTop="10dp"
                    android:layout_height="wrap_content"
                    android:textSize="13sp"
                    android:layout_marginLeft="10.0dip"
                    android:text="很多其它频道" />
    
                <com.test.drag.view.MyGridView
                    android:id="@+id/otherGridView"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginLeft="14dip"
                    android:layout_marginRight="14dip"
                    android:gravity="center"
                    android:horizontalSpacing="14dip"
                    android:listSelector="@android:color/transparent"
                    android:numColumns="4"
                    android:scrollbars="vertical"
                    android:stretchMode="columnWidth"
                    android:verticalSpacing="14.0px" />
            </LinearLayout>
        </ScrollView>
    
    </RelativeLayout>
    

    实现的效果例如以下:



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


    源代码下载







  • 相关阅读:
    jQueryUI的widget的Hello World
    jquery.fileupload源码解读笔记
    起始路由改成分区(Areas)的RouteConfig.cs配置方法
    C++/CLI
    WM_COPYDATA 进程间通信
    C# 托管内存与非托管内存之间的转换
    迟延(Lazy)加载导出部件(Export Part)与元数据(Metadata)
    Bitmap(Type, String) 图片路径
    C# GetManifestResourceStream获取资源为null
    C#可扩展编程之MEF学习笔记(二):MEF的导出(Export)和导入(Import)
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/7262489.html
Copyright © 2020-2023  润新知