仿腾讯新闻频道定制界面效果

转载请注明出处
http://blog.csdn.net/oddshou/article/details/73467589

更新:
仿腾讯新闻频道定制界面效果2

这个效果一直想做,最近项目无事决定着手实现

先看原效果图
腾讯新闻效果图

那么我们的目标就是实现这样一个效果。目前分析大致有件事情要做:
1、添加或者移除频道动画(添加或移除都需要跨越中间栏目分类)
2、拖拽频道动画
先来分析拖拽动画,这个看似复杂,其实并不难。长按之后布局不变,底部位置出现一个占位空白频道。同时,我们需要调整位置的频道变成抓取状态。移动时,底部布局动态变化直至放下抓取(松手)所选频道移动到占位位置。这个过程可以分成两个部分
底部运动:那么移动的效果实际就是根据鼠标(暂时这么描述)的位置决定占位符(底部占位控件)的下一个位置,并移动到那个位置
顶部运动(抓取控件的运动)根据手势移动,并提供位置坐标

接下来分析添加或者移除频道动画
移除上边(已选频道)这里不需要做什么处理,只需要简单移除就好。同时执行移除动画(后面控件填充空位),那么下边(推荐频道这里)执行添加动画,起始位置为上边移除的位置。
添加 因为添加都是添加在末尾,所以动画也很简单。下边移除,上边添加。添加执行动画,起始位置在移除的地方。
当然以上两块的动画还需要注意动画的执行顺序。

下面开始第一步控制生成布局
图片:
代码

public class GridLayoutAnimation extends Activity {
    LinearLayout rootLayout;
    static final String [] CHANNELS_CHOOSED = {"要闻", "视频","广东","娱乐","体育",
            "要闻2", "视频2","广东2","娱乐2","体育2",
            "要闻3", "视频3","广东3","娱乐3","体育3",
            "要闻4", "视频4","广东4","娱乐4","体育4",

    };

    static final String [] CHANNELS_UNCHOOSED = {"宠物", "纪录片","文化","动漫","股票",
            "宠物2", "纪录片2","文化2","动漫2","股票2",
            "宠物3", "纪录片3","文化3","动漫3","股票3",
            "宠物4", "纪录片4","文化4","动漫4","股票4",

    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_container);
        rootLayout = (LinearLayout) findViewById(R.id.container);
        createPage();
    }

    protected void createPage(){
        //1.titile 已选频道
        TextView chooseTitle = new TextView(this);
        chooseTitle.setWidth(200);
        chooseTitle.setHeight(100);
        chooseTitle.setText("已选频道");

        rootLayout.addView(chooseTitle, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT));
        //2.buttons 已选频道
        GridLayout gridLayoutChoosed = new GridLayout(this);

        gridLayoutChoosed.setColumnCount(4);
        gridLayoutChoosed.setLayoutTransition(new LayoutTransition());
        for (String title: CHANNELS_CHOOSED
             ) {
            Button btn = new Button(this);
            btn.setText(title);
            btn.setWidth(180);
            gridLayoutChoosed.addView(btn);
        }
        rootLayout.addView(gridLayoutChoosed);
        //3.title 推荐频道
        TextView unChoosedTitle = new TextView(this);
        unChoosedTitle.setWidth(200);
        unChoosedTitle.setHeight(100);
        unChoosedTitle.setText("未选频道");

        rootLayout.addView(unChoosedTitle, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT));

        //4.buttons 推荐频道
        GridLayout gridLayoutUnChoosed = new GridLayout(this);
        gridLayoutUnChoosed.setColumnCount(4);
        gridLayoutUnChoosed.setLayoutTransition(new LayoutTransition());
        for (String title: CHANNELS_UNCHOOSED
                ) {
            Button btn = new Button(this);
            btn.setWidth(180);
            btn.setText(title);
            gridLayoutUnChoosed.addView(btn);
        }
        rootLayout.addView(gridLayoutUnChoosed);


    }

到目前还只是简单的搭建工作,还没有实现什么功能。不过前端工作就是这样,开到界面写起代码来就会越来越幸福有离成功越来越近的感觉。
相信代码应该能看懂,createPage() 添加一些需要的控件。
接下来实现添加和移除的动画。
第一天实现的效果,流畅度远没有达到预期

用上图的效果对比腾讯新闻的话,流畅度不够。还有一个很重要的转移动画没有完成,拖拽也没有完成。
完成这一步的话,需要的工作也讲下:上下两块用的是gridLayout,通过setLayoutTransition 方法设置基本动画效果,包括移除,添加,以及其他item的换行效果。
算了代码就不贴了,后续完成后一并贴上。
对比发现使用setLayoutTransition 动画过程中还可以继续操作,而腾讯新闻却不可以,表示他用的是纯动画而系统这种方式不是。
试过关闭这个动画,速度很快。想了一下,后面的移动动画和拖拽都是要自己实现的,干脆还是自己实现吧。

第二天项目停滞,之前考虑用TranslationLayout 没能解决问题,不过意外发现了一些东西,这里一并记录一下
https://stackoverflow.com/questions/20973089/android-add-view-with-expand-animation-without-blinking
https://github.com/andkulikov/Transitions-Everywhere
以上两个链接一个是系统自动实现动画效果的api,要求api 19我这里就先不考虑了。另一个是第三方库,api要求不高,这里暂时不用了,日后有需要再研究。关键字TransitionManager.beginDelayedTransition
Transitions-Everywhere

第三天:第一个大的效果已经完成
这里写图片描述

这里说明一下:差距还在于按钮点击效果上,通过手机拍摄慢动作可以发现点击过程中有短暂的白块,认为应该是btn点击背景色导致,这里暂时不去处理。到目前的代码也贴一下不是很多。

public class GridLayoutAnimation extends Activity implements View.OnLongClickListener, View.OnClickListener {
    private static final String TAG = "GridLayoutAnimation";
    LinearLayout rootLayout;
    static final String[] CHANNELS_CHOOSED = {"要闻", "视频", "广东", "娱乐", "体育",
            "要闻2", "视频2", "广东2", "娱乐2", "体育2",
            "要闻3", "视频3", "广东3", "娱乐3", "体育3",
            "要闻4", "视频4", "广东4", "娱乐4", "体育4",

    };

    static final String[] CHANNELS_UNCHOOSED = {"宠物", "纪录片", "文化", "动漫", "股票",
            "宠物2", "纪录片2", "文化2", "动漫2", "股票2",
            "宠物3", "纪录片3", "文化3", "动漫3", "股票3",
            "宠物4", "纪录片4", "文化4", "动漫4", "股票4",

    };
    private GridLayout gridLayoutUnChoosed;
    private GridLayout gridLayoutChoosed;
    private ArrayList<BtnData> groupDataChoosed;
    private ArrayList<BtnData> groupDataUnChoosed;
    private LayoutTransition mTransitionerTop;
    private LayoutTransition mTransitionerBottom;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_container);
        rootLayout = (LinearLayout) findViewById(R.id.container);
        createPage();
    }

    protected void createPage() {
        //尝试过设置同一个LayoutTransition,发现会有错乱,大概是因为
        //动画是两块的,同步执行会有问题。
        mTransitionerTop = new LayoutTransition();
        mTransitionerBottom = new LayoutTransition();
        setupCustomAnimations();

        //1.titile 已选频道
        TextView chooseTitle = new TextView(this);
        chooseTitle.setWidth(200);
        chooseTitle.setHeight(100);
        chooseTitle.setText("已选频道");

        rootLayout.addView(chooseTitle, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT));
        //2.buttons 已选频道
        gridLayoutChoosed = new GridLayout(this);

        gridLayoutChoosed.setColumnCount(4);
        gridLayoutChoosed.setLayoutTransition(mTransitionerTop);
        groupDataChoosed = new ArrayList<BtnData>();
        createBtns(CHANNELS_CHOOSED, gridLayoutChoosed, groupDataChoosed);
        rootLayout.addView(gridLayoutChoosed);
        //3.title 推荐频道
        TextView unChoosedTitle = new TextView(this);
        unChoosedTitle.setWidth(200);
        unChoosedTitle.setHeight(100);
        unChoosedTitle.setText("未选频道");

        rootLayout.addView(unChoosedTitle, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT));

        //4.buttons 推荐频道
        gridLayoutUnChoosed = new GridLayout(this);
        gridLayoutUnChoosed.setColumnCount(4);
        gridLayoutUnChoosed.setLayoutTransition(mTransitionerBottom);
        groupDataUnChoosed = new ArrayList<BtnData>();
        createBtns(CHANNELS_UNCHOOSED, gridLayoutUnChoosed, groupDataUnChoosed);
        rootLayout.addView(gridLayoutUnChoosed);

    }

    private LayoutTransition.TransitionListener mTransitionListner = new LayoutTransition.TransitionListener() {
        int[] locationSrc = new int[2];

        @Override
        public void startTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {
            if (transitionType == LayoutTransition.DISAPPEARING) {
                view.getLocationInWindow(locationSrc);
            } else if (transitionType == LayoutTransition.APPEARING) {
                int[] locationDst = new int[2];
                if (transition == mTransitionerTop) {
                    //由下到上
                    getLocation(locationDst);
                } else if (transition == mTransitionerBottom) {
                    //由上到下
                    View dstView = gridLayoutUnChoosed.getChildAt(0);
                    dstView.getLocationInWindow(locationDst); //这里获取得到0,0,改用其他方式获取
                }else {
                    return;
                }

                PropertyValuesHolder pvhTransX =
                        PropertyValuesHolder.ofFloat("translationX", locationSrc[0] - locationDst[0], 0f);
                PropertyValuesHolder pvhTransY =
                        PropertyValuesHolder.ofFloat("translationY", locationSrc[1] - locationDst[1], 0f);
                final ObjectAnimator animIn = ObjectAnimator.ofPropertyValuesHolder(
                        this, pvhTransX, pvhTransY).
                        setDuration(transition.getDuration(LayoutTransition.APPEARING));
                transition.setAnimator(LayoutTransition.APPEARING, animIn);
            }
        }

        @Override
        public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {

        }

        private void getLocation(int[] location) {
            //1.计算新增控件行列
            int childCount = gridLayoutChoosed.getChildCount();
            int columnCount = gridLayoutChoosed.getColumnCount();
            int row = (int)Math.ceil(( childCount + 1.0 )/columnCount + 0.5);
            int column = (childCount + 1) % columnCount;
            if (column > 1) {
                View columnBefor = gridLayoutChoosed.getChildAt(childCount - 1);
                columnBefor.getLocationInWindow(location);
                location[0] += columnBefor.getWidth();  //这里理论上还需要加上一些margin left,right
            }else {
                //这里认为已选频道大于1
                View columnAbove = gridLayoutChoosed.getChildAt(childCount - columnCount);
                columnAbove.getLocationInWindow(location);
                location[1] += columnAbove.getHeight(); //同样这里也是不准确的
            }

        }
    };

    private void setupCustomAnimations() {
        //把延时去掉,速度瞬间提升
//        mTransitionerTop.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
//        mTransitionerTop.setStartDelay(LayoutTransition.APPEARING, 0);
        mTransitionerTop.addTransitionListener(mTransitionListner);
        mTransitionerTop.setAnimator(LayoutTransition.DISAPPEARING, null);
        mTransitionerTop.setAnimator(LayoutTransition.APPEARING, null);
        mTransitionerTop.setInterpolator(LayoutTransition.APPEARING, new LinearInterpolator());
        mTransitionerTop.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
        mTransitionerTop.setStartDelay(LayoutTransition.APPEARING, 0);

//        mTransitionerBottom.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
//        mTransitionerBottom.setStartDelay(LayoutTransition.APPEARING, 0);
        mTransitionerBottom.addTransitionListener(mTransitionListner);
        mTransitionerBottom.setAnimator(LayoutTransition.DISAPPEARING, null);
        mTransitionerBottom.setAnimator(LayoutTransition.APPEARING, null);
        mTransitionerBottom.setInterpolator(LayoutTransition.APPEARING, new LinearInterpolator());
        mTransitionerBottom.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
        mTransitionerBottom.setStartDelay(LayoutTransition.APPEARING, 0);

    }

    protected void createBtns(String[] titles, ViewGroup rootView, ArrayList<BtnData> groupList) {
        for (int i = 0; i < titles.length; i++) {
            Button btn = new Button(this);
            btn.setOnLongClickListener(this);
            btn.setOnClickListener(this);
            btn.setWidth(180);
            btn.setText(titles[i]);
            BtnData btnData = new BtnData(i, titles[i], titles == CHANNELS_CHOOSED);

            btn.setTag(btnData);
            groupList.add(btnData);
            rootView.addView(btn);
        }
    }


    @Override
    public boolean onLongClick(View v) {
        return false;
    }

    @Override
    public void onClick(View v) {
        //已选频道点击移动到未选频道
        //未选频道点击移动到已选频道
        BtnData tag = (BtnData) v.getTag();
        if (tag.choosed) {
            gridLayoutChoosed.removeView(v);
            //这里如果不添加新的btn 会有问题,原因似乎是原btn有一些坐标属性
            //导致添加到新的父控件计算位置有误
            Button btn = getButton(tag);
            gridLayoutUnChoosed.addView(btn, 0);

            tag.choosed = false;
            if (groupDataChoosed.contains(tag)) {
                groupDataChoosed.remove(tag);
            }
            if (!groupDataUnChoosed.contains(tag)) {
                groupDataUnChoosed.add(tag);
            }
        } else {
            gridLayoutUnChoosed.removeView(v);
            Button btn = getButton(tag);
            gridLayoutChoosed.addView(btn);
            tag.choosed = true;
            if (!groupDataChoosed.contains(tag)) {
                groupDataChoosed.add(tag);
            }
            if (groupDataUnChoosed.contains(tag)) {
                groupDataUnChoosed.remove(tag);
            }
        }
    }

    @NonNull
    private Button getButton(BtnData tag) {
        Button btn = new Button(this);

        btn.setOnLongClickListener(this);
        btn.setOnClickListener(this);
        btn.setWidth(180);
        btn.setText(tag.title);
        btn.setTag(tag);
        return btn;
    }

    public class BtnData {
        int id;
        String title;
        boolean choosed;

        public BtnData(int id, String title, boolean choosed) {
            this.id = id;
            this.title = title;
            this.choosed = choosed;
        }
    }
}

接下来需要实现拖拽的效果
兴高采烈发现view.startDragAndDrop 却不能用,api level 24,我只能另寻他处了。
备注一些吧,感觉很强大。
http://www.jcodecraeer.com/a/anzhuokaifa/developer/2013/0311/1003.html

第三天基本把第二个效果做完了,先上图
这里写图片描述
效果基本上完成了,还有一个释放回弹和占位效果。做这个效果三天了,要达到比较完美的效果仍然需要下一些功夫,就当是个思路吧。
补充说明一下,依然使用了startDrag。
最后代码

package com.oddshou.testall.animation;

import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.app.Activity;
import android.content.ClipData;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.DragEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.GridLayout;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.oddshou.testall.Logger;
import com.oddshou.testall.R;

import java.util.ArrayList;

/**
 * Created by oddshou on 2017/6/19.
 */

public class GridLayoutAnimation extends Activity implements View.OnLongClickListener,
        View.OnClickListener, View.OnDragListener {
    private static final String TAG = "GridLayoutAnimation";
    LinearLayout rootLayout;
    static final String[] CHANNELS_CHOOSED = {"要闻", "视频", "广东", "娱乐", "体育",
            "要闻2", "视频2", "广东2", "娱乐2", "体育2",
            "要闻3", "视频3", "广东3", "娱乐3", "体育3",
            "要闻4", "视频4", "广东4", "娱乐4", "体育4",

    };

    static final String[] CHANNELS_UNCHOOSED = {"宠物", "纪录片", "文化", "动漫", "股票",
            "宠物2", "纪录片2", "文化2", "动漫2", "股票2",
            "宠物3", "纪录片3", "文化3", "动漫3", "股票3",
            "宠物4", "纪录片4", "文化4", "动漫4", "股票4",

    };
    private GridLayout gridLayoutUnChoosed;
    private GridLayout gridLayoutChoosed;
    private ArrayList<BtnData> groupDataChoosed;
    private ArrayList<BtnData> groupDataUnChoosed;
    private LayoutTransition mTransitionerTop;
    private LayoutTransition mTransitionerBottom;
    //内部调换位置
    private boolean choosedChange;
    private int choosedChangeId;
    private View moveView;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_container);
        rootLayout = (LinearLayout) findViewById(R.id.container);
        createPage();
    }

    protected void createPage() {
        //尝试过设置同一个LayoutTransition,发现会有错乱,大概是因为
        //动画是两块的,同步执行会有问题。
        mTransitionerTop = new LayoutTransition();
        mTransitionerBottom = new LayoutTransition();
        setupCustomAnimations();

        //1.titile 已选频道
        TextView chooseTitle = new TextView(this);
        chooseTitle.setWidth(200);
        chooseTitle.setHeight(100);
        chooseTitle.setText("已选频道");

        rootLayout.addView(chooseTitle, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT));
        //2.buttons 已选频道
        gridLayoutChoosed = new GridLayout(this);

        gridLayoutChoosed.setColumnCount(4);
        gridLayoutChoosed.setLayoutTransition(mTransitionerTop);
        groupDataChoosed = new ArrayList<BtnData>();
        createBtns(CHANNELS_CHOOSED, gridLayoutChoosed, groupDataChoosed);
        rootLayout.addView(gridLayoutChoosed);
        //3.title 推荐频道
        TextView unChoosedTitle = new TextView(this);
        unChoosedTitle.setWidth(200);
        unChoosedTitle.setHeight(100);
        unChoosedTitle.setText("未选频道");

        rootLayout.addView(unChoosedTitle, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT));

        //4.buttons 推荐频道
        gridLayoutUnChoosed = new GridLayout(this);
        gridLayoutUnChoosed.setColumnCount(4);
        gridLayoutUnChoosed.setLayoutTransition(mTransitionerBottom);
        groupDataUnChoosed = new ArrayList<BtnData>();
        createBtns(CHANNELS_UNCHOOSED, gridLayoutUnChoosed, groupDataUnChoosed);
        rootLayout.addView(gridLayoutUnChoosed);

    }

    private LayoutTransition.TransitionListener mTransitionListner = new LayoutTransition.TransitionListener() {
        int[] locationSrc = new int[2];

        @Override
        public void startTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {
            if (transitionType == LayoutTransition.DISAPPEARING) {
                view.getLocationInWindow(locationSrc);
            } else if (transitionType == LayoutTransition.APPEARING) {
                //点击.由上到下 终点为下面第一个。
                //由下到上,终点为上面最后一个。
                int[] locationDst = new int[2];
                if (!choosedChange) {

                    if (transition == mTransitionerTop) {
                        //由下到上
                        getLocation(locationDst);
                    } else if (transition == mTransitionerBottom) {
                        //由上到下
                        View dstView = gridLayoutUnChoosed.getChildAt(0);
                        dstView.getLocationInWindow(locationDst); //这里获取得到0,0,改用其他方式获取
                    }else {
                        return;
                    }
                }else {
                    View dstView = gridLayoutChoosed.getChildAt(choosedChangeId);
                    dstView.getLocationInWindow(locationDst); //这里获取得到0,0,改用其他方式获取
                    choosedChange = false;
                }


                PropertyValuesHolder pvhTransX =
                        PropertyValuesHolder.ofFloat("translationX", locationSrc[0] - locationDst[0], 0f);
                PropertyValuesHolder pvhTransY =
                        PropertyValuesHolder.ofFloat("translationY", locationSrc[1] - locationDst[1], 0f);
                final ObjectAnimator animIn = ObjectAnimator.ofPropertyValuesHolder(
                        this, pvhTransX, pvhTransY).
                        setDuration(transition.getDuration(LayoutTransition.APPEARING));
                transition.setAnimator(LayoutTransition.APPEARING, animIn);
            }
        }

        @Override
        public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {

        }

        private void getLocation(int[] location) {
            //1.计算新增控件行列
            int childCount = gridLayoutChoosed.getChildCount();
            int columnCount = gridLayoutChoosed.getColumnCount();
            int row = (int)Math.ceil(( childCount + 1.0 )/columnCount + 0.5);
            int column = (childCount + 1) % columnCount;
            if (column > 1) {
                View columnBefor = gridLayoutChoosed.getChildAt(childCount - 1);
                columnBefor.getLocationInWindow(location);
                location[0] += columnBefor.getWidth();  //这里理论上还需要加上一些margin left,right
            }else {
                //这里认为已选频道大于1
                View columnAbove = gridLayoutChoosed.getChildAt(childCount - columnCount);
                columnAbove.getLocationInWindow(location);
                location[1] += columnAbove.getHeight(); //同样这里也是不准确的
            }

        }
    };

    private void setupCustomAnimations() {
        //把延时去掉,速度瞬间提升
//        mTransitionerTop.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
//        mTransitionerTop.setStartDelay(LayoutTransition.APPEARING, 0);
        mTransitionerTop.addTransitionListener(mTransitionListner);
        mTransitionerTop.setAnimator(LayoutTransition.DISAPPEARING, null);
        mTransitionerTop.setAnimator(LayoutTransition.APPEARING, null);
        mTransitionerTop.setInterpolator(LayoutTransition.APPEARING, new LinearInterpolator());
        mTransitionerTop.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
        mTransitionerTop.setStartDelay(LayoutTransition.APPEARING, 0);

//        mTransitionerBottom.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
//        mTransitionerBottom.setStartDelay(LayoutTransition.APPEARING, 0);
        mTransitionerBottom.addTransitionListener(mTransitionListner);
        mTransitionerBottom.setAnimator(LayoutTransition.DISAPPEARING, null);
        mTransitionerBottom.setAnimator(LayoutTransition.APPEARING, null);
        mTransitionerBottom.setInterpolator(LayoutTransition.APPEARING, new LinearInterpolator());
        mTransitionerBottom.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
        mTransitionerBottom.setStartDelay(LayoutTransition.APPEARING, 0);

    }

    protected void createBtns(String[] titles, ViewGroup rootView, ArrayList<BtnData> groupList) {
        for (int i = 0; i < titles.length; i++) {
            Button btn = new Button(this);
            btn.setOnLongClickListener(this);
            btn.setOnClickListener(this);
            btn.setOnDragListener(this);
            btn.setWidth(180);
            btn.setText(titles[i]);
            BtnData btnData = new BtnData(i, titles[i], titles == CHANNELS_CHOOSED);

            btn.setTag(btnData);
            groupList.add(btnData);
            rootView.addView(btn);
        }
    }


    @Override
    public boolean onLongClick(View v) {
//        v.startDragAndDrop()  api level 24,好吧算我输
        ClipData dragData = ClipData.newPlainText("clipdata", "clipString");
//        View.DragShadowBuilder dragShadowBuilder = new View.DragShadowBuilder(v);
        View.DragShadowBuilder dragShadowBuilder = new MyShadow(v);


        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            v.startDragAndDrop(dragData, dragShadowBuilder, null, 0);
        }else {
            v.startDrag(dragData, dragShadowBuilder, null, 0);
        }
//        v.setEnabled(false);
        moveView = v;




        return false;
    }

    @Override
    public boolean onDrag(View v, DragEvent event) {


        switch (event.getAction()) {
            case DragEvent.ACTION_DRAG_STARTED:
                //开始拖动,所有监听控件都会收到
                return !(v == moveView);
            case DragEvent.ACTION_DRAG_ENTERED:
                Logger.i(TAG, "onDrag: " + event.getAction() + " " + ((BtnData)v.getTag()).title , "oddshou");
                //进入目标区域,执行变换
                BtnData tag = (BtnData) v.getTag();
                if (tag.choosed) {
                    int k = -1; //终点
                    int j = -1; //起点
                    for (int i = 0; i < gridLayoutChoosed.getChildCount(); i++) {
                        View child = gridLayoutChoosed.getChildAt(i);
                        if (child == v) {
                            k = i;
                        }
                        if (child == moveView) {
                            j = i;
                        }
                        if (k >= 0 && j >= 0) {
                            break;
                        }
                    }
                    choosedChange = true;
                    choosedChangeId =  k > j ? k-1 : k;
                    //如果起点小于终点,计算终点坐标时减1,大于终点不减
                    gridLayoutChoosed.removeView(moveView);
                    moveView.setLayoutParams(new GridLayout.LayoutParams());
                    gridLayoutChoosed.addView(moveView, k);
                }
                return false;
            case DragEvent.ACTION_DRAG_LOCATION:
                Logger.i(TAG, "onDrag: " + event.getAction(), "oddshou");
                return true;
            case DragEvent.ACTION_DRAG_EXITED:
                //移除目标区域
                Logger.i(TAG, "onDrag: " + event.getAction() + " " + ((BtnData)v.getTag()).title, "oddshou");
                return true;
            case DragEvent.ACTION_DROP:
                Logger.i(TAG, "onDrag: " + event.getAction() + " " + ((BtnData)v.getTag()).title, "oddshou");
                //目标区域放下
                BtnData tag2 = (BtnData) v.getTag();
                if (tag2.choosed) {
                    //还原到终点位置
                }else {
                    //进入下方第一个位置

                }

                return true;
            case DragEvent.ACTION_DRAG_ENDED:
//                if (moveView == v) {
//                    moveView.setEnabled(true);
//                }
                return true;
        }

        return false;
    }

    @Override
    public void onClick(View v) {
        //已选频道点击移动到未选频道
        //未选频道点击移动到已选频道
        BtnData tag = (BtnData) v.getTag();
        if (tag.choosed) {
            gridLayoutChoosed.removeView(v);
            //这里如果不添加新的btn 会有问题,原因似乎是原btn有一些坐标属性
            //导致添加到新的父控件计算位置有误
            v.setLayoutParams(new GridLayout.LayoutParams());
            gridLayoutUnChoosed.addView(v, 0);

            tag.choosed = false;
            if (groupDataChoosed.contains(tag)) {
                groupDataChoosed.remove(tag);
            }
            if (!groupDataUnChoosed.contains(tag)) {
                groupDataUnChoosed.add(tag);
            }
        } else {
            gridLayoutUnChoosed.removeView(v);
            v.setLayoutParams(new GridLayout.LayoutParams());
            gridLayoutChoosed.addView(v);
            tag.choosed = true;
            if (!groupDataChoosed.contains(tag)) {
                groupDataChoosed.add(tag);
            }
            if (groupDataUnChoosed.contains(tag)) {
                groupDataUnChoosed.remove(tag);
            }
        }
    }

    @NonNull
    private Button getButton(BtnData tag) {
        Button btn = new Button(this);

        btn.setOnLongClickListener(this);
        btn.setOnClickListener(this);
        btn.setWidth(180);
        btn.setText(tag.title);
        btn.setTag(tag);
        return btn;
    }

    public class BtnData {
        int id;
        String title;
        boolean choosed;

        public BtnData(int id, String title, boolean choosed) {
            this.id = id;
            this.title = title;
            this.choosed = choosed;
        }
    }

    /**
     * 要达到完成的效果还需要仔细斟酌shader效果,
     * 目前我遇到的问题就是始终有透明度,
     */
    public class MyShadow extends View.DragShadowBuilder {
        private View viewSrc;

        public MyShadow(View view) {
            super(view);
            this.viewSrc = view;
        }

        @Override
        public void onDrawShadow(Canvas canvas) {
            canvas.drawColor(Color.RED);
//            super.onDrawShadow(canvas);
            viewSrc.draw(canvas);
        }
    }
}

xml代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/container"
    android:background="@android:color/white"
    android:clipChildren="false">


</LinearLayout>

好了,先就这样。有需要再完善。希望上传的一些图片能正常播放
2017.6.21
oddshou

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值