自定义dialog的频道选择器

这里写图片描述
效果图如上

我们一步一步把它撸出来
首先不考虑是dialog,搞个自定义的viewgroup来实现主要功能
先来看看这个viewgrop的xml布局,很简单,两个textview,两个gridlayout
注意这个属性 android:animateLayoutChanges=”true”,这个是为gridlayout设置内容变化时的动画.

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_new_channl"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="viewpager.villa.com.viewpagertransformer.NewChannlActivity">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="已选频道:"/>
    <!-- 设置gridlayout改变时有动画-->
    <GridLayout
        android:id="@+id/selected_channel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:animateLayoutChanges="true"
        android:columnCount="4"></GridLayout>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="未选频道:"/>

    <GridLayout
        android:animateLayoutChanges="true"
        android:id="@+id/unSelected_channel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:columnCount="4"></GridLayout>

</LinearLayout>

这里写图片描述

package viewpager.villa.com.viewpagertransformer;

import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.Gravity;
import android.view.View;
import android.widget.GridLayout;
import android.widget.TextView;

public class NewChannlActivity2 extends AppCompatActivity {
    private String[] mSelectedChannels = {"北京", "中国", "国际", "体育", "育人", "生活", "旅游", "军事", "汽车"};

    private String[] mUnSeletedChannels = {"时尚", "娱乐", "呵呵", "嘿嘿", "羞羞", "巴拿马"};
    private GridLayout mSelectedChannel;
    private GridLayout mUnSelectedChannel;
    private int itemMargin;

    private static final int NOT_AT_GRID = -1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_new_channl);
        initView();
        initSelectedChannel();
        initUnSelectedChannel();
    }


    /**
     * 初始化没有选中的item
     */
    private void initUnSelectedChannel() {
        for (int i = 0; i < mUnSeletedChannels.length; i++) {
            TextView item = getTextView(mUnSeletedChannels[i]);
            item.setOnClickListener(mUnSelectedOnClickListener);
            mUnSelectedChannel.addView(item, 0);
        }
    }

    private View.OnClickListener mUnSelectedOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mUnSelectedChannel.removeView(v);
            TextView mTextView = (TextView) v;
            TextView textView = getTextView(mTextView.getText().toString());
            addSelectedItem(textView);

        }
    };

    /**
     * 初始化选中的item
     */
    private void initSelectedChannel() {
        for (int i = 0; i < mSelectedChannels.length; i++) {
            TextView item = getTextView(mSelectedChannels[i]);
            addSelectedItem(item);

        }
    }

    private void addSelectedItem(TextView item) {
        //为创建的每一个item设置长按点击事件

        item.setOnClickListener(mSelectedOnclickListener);
        mSelectedChannel.addView(item);
    }

    private View.OnClickListener mSelectedOnclickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mSelectedChannel.removeView(v);
            TextView mTextView = (TextView) v;
            addUnselectedItem(mTextView);
        }
    };

    private void addUnselectedItem(TextView mTextView) {
        TextView textView = getTextView(mTextView.getText().toString());
        textView.setOnClickListener(mUnSelectedOnClickListener);
        mUnSelectedChannel.addView(textView);
    }

    /**
     * 初始化view
     */
    private void initView() {
        mSelectedChannel = (GridLayout) findViewById(R.id.selected_channel);
        mUnSelectedChannel = (GridLayout) findViewById(R.id.unSelected_channel);
        //获取dimen值
        itemMargin = getResources().getDimensionPixelOffset(R.dimen.item_margin);
    }


    /**
     * 获取一个item的方法
     *
     * @param msg
     * @return
     */
    @NonNull
    private TextView getTextView(String msg) {
        TextView item = new TextView(this);
        GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams();
        int widthPixels = getResources().getDisplayMetrics().widthPixels;
        //这里不能直接去获取gridlayout的宽,因为这个方法在oncreate方法有调用,view还没有绘制完成,所以直接去获取屏幕的宽度像素
        layoutParams.width = widthPixels / 4 - 2 * itemMargin;
        layoutParams.height = ActionBar.LayoutParams.WRAP_CONTENT;
        layoutParams.setMargins(itemMargin, itemMargin, itemMargin, itemMargin);
        item.setLayoutParams(layoutParams);
        //设置每个item的gravity,中心,
        item.setGravity(Gravity.CENTER);
        item.setBackgroundResource(R.drawable.item_back_selector);
        item.setTextColor(getResources().getColorStateList(R.color.item_text_selector));
        item.setText(msg);
        return item;
    }


}

接下来我们来处理长按时,拖拽的效果
首先我们实现点击时添加或者删除的效果
这里要注意为从selectedLayout到unSelectedLayout的添加textview,需要设置点击事件,同样unSelectedLayout到selectedLayout也需要设置长按点击事件和点击事件
并且采用的一个矩形数组来存储位置
mRects[i] = new Rect(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());把每个矩形item的位置存到矩形数组中,
孩子实现拖拽的代码就一行
v.startDrag(null, new View.DragShadowBuilder(v), null, 0);

package viewpager.villa.com.newchannel;

import android.content.Context;
import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.support.v7.app.ActionBar;
import android.util.AttributeSet;
import android.view.DragEvent;
import android.view.Gravity;
import android.view.View;
import android.widget.GridLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

/**
 * Created by Administrator on 2016/10/13 0013.
 */
public class NewsChannelView extends RelativeLayout {
    private static final String TAG = "ViewChannelView";
    private String[] mSelectedChannels = {"北京", "中国", "国际", "体育", "育人", "生活", "旅游", "军事", "汽车"};

    private String[] mUnSeletedChannels = {"时尚", "娱乐", "呵呵", "嘿嘿", "羞羞", "巴拿马"};
    private GridLayout mSelectedChannel;
    private GridLayout mUnSelectedChannel;
    private int itemMargin;
    private Rect[] mRects;
    private static final int NOT_AT_GRID = -1;
    public NewsChannelView(Context context, AttributeSet attrs) {
        super(context, attrs);
        View.inflate(getContext(),R.layout.activity_new_channl,this);
        init();
    }

    public NewsChannelView(Context context) {
        this(context,null);

    }

    private void init() {
        initView();
        initSelectedChannel();
        initUnSelectedChannel();
        setEvent();
    }
    private void initRects() {
        mRects = new Rect[mSelectedChannel.getChildCount()];
        for (int i = 0; i < mSelectedChannel.getChildCount(); i++) {
            View child = mSelectedChannel.getChildAt(i);
            mRects[i] = new Rect(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
        }
    }

    //为选中的gridlayout设置拖拽的监听
    private void setEvent() {
        mSelectedChannel.setOnDragListener(mOnDragListener);
    }

    private View.OnDragListener mOnDragListener = new View.OnDragListener() {
        @Override
        public boolean onDrag(View v, DragEvent event) {
            switch (event.getAction()) {
                //拖拽结束
                case DragEvent.ACTION_DRAG_ENDED:
                    mDragView.setSelected(false);
                    break;
                //进入父容器的范围
                case DragEvent.ACTION_DRAG_ENTERED:
                    break;
                //不再父容器范围内时调用
                case DragEvent.ACTION_DRAG_EXITED:
                    break;
                //拖拽位置改变过程中调用
                case DragEvent.ACTION_DRAG_LOCATION:
                    //实时的获取在gridlyout中的拖拽进入的孩子
                    int index = getChildIndex(event.getX(), event.getY());
                    //获取当前的需要移动到的目标孩子
                    View mTagart = mSelectedChannel.getChildAt(index);
                    //如果移动到了grid孩子中,就移除这个孩子
                    if (index != NOT_AT_GRID && mTagart != mDragView) {
                        //移动掉这个孩子
                        mSelectedChannel.removeView(mDragView);
                        //再把这个还在添加到移动到的位置,但是这里有个问题是移动到了自身的位置,所以前面需要加个判断
                        mSelectedChannel.addView(mDragView, index);
                    }
                    break;
                //拖拽开始,初始化矩形数组,以便判断孩子是不是在gridlayout范围内
                case DragEvent.ACTION_DRAG_STARTED:
                    initRects();
                    break;
                //拖拽终止
                case DragEvent.ACTION_DROP:
                    break;

            }
            return true;
        }
    };

    /**
     * 初始化没有选中的item
     */
    private void initUnSelectedChannel() {
        for (int i = 0; i < mUnSeletedChannels.length; i++) {
            TextView item = getTextView(mUnSeletedChannels[i]);
            item.setOnClickListener(mUnSelectedOnClickListener);
            mUnSelectedChannel.addView(item, 0);
        }
    }

    private View.OnClickListener mUnSelectedOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mUnSelectedChannel.removeView(v);
            TextView mTextView = (TextView) v;
            TextView textView = getTextView(mTextView.getText().toString());
            addSelectedItem(textView);

        }
    };

    /**
     * 初始化选中的item
     */
    private void initSelectedChannel() {
        for (int i = 0; i < mSelectedChannels.length; i++) {
            TextView item = getTextView(mSelectedChannels[i]);
            addSelectedItem(item);

        }
    }

    private void addSelectedItem(TextView item) {
        //为创建的每一个item设置长按点击事件
        item.setOnLongClickListener(mOnLongClickListener);
        item.setOnClickListener(mSelectedOnclickListener);
        mSelectedChannel.addView(item);
    }

    private View.OnClickListener mSelectedOnclickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mSelectedChannel.removeView(v);
            TextView mTextView = (TextView) v;
            addUnselectedItem(mTextView);
        }
    };

    private void addUnselectedItem(TextView mTextView) {
        TextView textView = getTextView(mTextView.getText().toString());
        textView.setOnClickListener(mUnSelectedOnClickListener);
        mUnSelectedChannel.addView(textView);
    }

    /**
     * 初始化view
     */
    private void initView() {
        mSelectedChannel = (GridLayout) findViewById(R.id.selected_channel);
        mUnSelectedChannel = (GridLayout) findViewById(R.id.unSelected_channel);
        //获取dimen值
        itemMargin = getResources().getDimensionPixelOffset(R.dimen.item_margin);
    }


    private View mDragView;
    private View.OnLongClickListener mOnLongClickListener = new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {

            /**
             *  * @param data A {@link android.content.ClipData} object pointing to the data to be
             * transferred by the drag and drop operation.
             * shadowBuilder,拖拽时的阴影
             * myLocalState, This Object is put into every DragEvent object sent by the system during the
             * current drag.
             * 最后一个标志位,我们不需要标志位,设为0
             */
            v.startDrag(null, new View.DragShadowBuilder(v), null, 0);
            mDragView = v;
            mDragView.setSelected(true);
            return true;//表示我要消费这个事件
        }
    };

    /**
     * 获取一个item的方法
     *
     * @param msg
     * @return
     */
    @NonNull
    private TextView getTextView(String msg) {
        TextView item = new TextView(getContext());
        GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams();
        int widthPixels = getResources().getDisplayMetrics().widthPixels;
        //这里不能直接去获取gridlayout的宽,因为这个方法在oncreate方法有调用,view还没有绘制完成,所以直接去获取屏幕的宽度像素
        layoutParams.width = widthPixels / 4 - 2 * itemMargin;
        layoutParams.height = ActionBar.LayoutParams.WRAP_CONTENT;
        layoutParams.setMargins(itemMargin, itemMargin, itemMargin, itemMargin);
        item.setLayoutParams(layoutParams);
        //设置每个item的gravity,中心,
        item.setGravity(Gravity.CENTER);
        item.setBackgroundResource(R.drawable.item_back_selector);
        item.setTextColor(getResources().getColorStateList(R.color.item_text_selector));
        item.setText(msg);
        return item;
    }

    public int getChildIndex(float x, float y) {
        for (int i = 0; i < mRects.length; i++) {
            if (mRects[i].contains((int) x, (int) y)) {
                return i;
            }
        }
        return NOT_AT_GRID;
    }
}

这里写图片描述

最后我们来创建自己的dialog
布局

<?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:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingBottom="50dp"
    tools:context="viewpager.villa.com.newchannel.MainActivity">

    <viewpager.villa.com.newchannel.NewsChannelView
        android:id="@+id/ncv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"></viewpager.villa.com.newchannel.NewsChannelView>
</RelativeLayout>

代码

package viewpager.villa.com.newchannel;

import android.app.Dialog;
import android.content.Context;
import android.view.Gravity;
import android.view.WindowManager;

/**
 * Created by Administrator on 2016/10/13 0013.
 */
public class NewsChannalDialog extends Dialog {
    private static final String TAG = "NewsChannalDialog";

    public NewsChannalDialog(Context context) {
        this(context,-1);
    }

    public NewsChannalDialog(Context context, int themeResId) {
        super(context, R.style.DialogTheme);
        init();
    }

    private void init() {
        setContentView(R.layout.new_channel_dialog);
        WindowManager.LayoutParams attributes = getWindow().getAttributes();
        attributes.width =WindowManager.LayoutParams.MATCH_PARENT;
        attributes.height =WindowManager.LayoutParams.WRAP_CONTENT;
        attributes.gravity = Gravity.TOP;
        setCanceledOnTouchOutside(true);
        getWindow().setAttributes(attributes);
    }
}

style,这里引用了两个平移动画,很简单

<style name="DialogTheme" >
    <item name="android:windowAnimationStyle">@style/DialogWindowAnimationStyle</item>
</style>
<style name="DialogWindowAnimationStyle" >
    <item name="android:windowEnterAnimation">@anim/dialog_enter</item>
    <item name="android:windowExitAnimation">@anim/dialog_exit</item>
</style>

最后大功告成…

Demo连接(https://github.com/mouxuefei/NewsChannelDialog.git)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值