A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 小鲁哥哥 于 2017-6-17 14:37 编辑

【济南中心】Android课程同步笔记智慧北京:Day06(上)


科大讯飞-语音合成
注册用户进行登录

创建应用

下载云服务SDK

添加依赖库

配置权限
[XML] 纯文本查看 复制代码
<!--连接网络权限,用于执行云端语音能力 -->
<uses-permission android:name="android.permission.INTERNET"/>
<!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!--读取网络信息状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--获取当前wifi状态 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!--允许程序改变网络连接状态 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<!--读取手机信息权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!--读取联系人权限,上传联系人需要用到此权限 -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<!--外存储写权限,构建语法需要用到此权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!--外存储读权限,构建语法需要用到此权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!--配置权限,用来记录应用配置信息 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<!--手机定位信息,用来为语义等功能提供定位,提供更精准的服务-->
<!--定位信息是敏感信息,可通过Setting.setLocationEnable(false)关闭定位请求 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

<!--摄相头权限,拍照需要用到 -->
<uses-permission android:name="android.permission.CAMERA" />

初始化云服务
[Java] 纯文本查看 复制代码
public class MainActivity extends AppCompatActivity {

    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //初始化
        // 将“12345678”替换成您申请的 APPID,申请地址:[url=http://www.xfyun.cn]http://www.xfyun.cn[/url]
        // 请勿在“=”与 appid 之间添加任务空字符或者转义符
        SpeechUtility.createUtility(this, SpeechConstant.APPID +"=57f75ccc");
    }

将文字合成语音
[Java] 纯文本查看 复制代码
        //把文字转换成语言
public void say(View view){
    //1.创建 SpeechSynthesizer 对象, 第二个参数:本地合成时传 InitListener
    SpeechSynthesizer mTts= SpeechSynthesizer.createSynthesizer(this, null);
    //2.合成参数设置,详见《MSC Reference Manual》SpeechSynthesizer 类
    //设置发音人(更多在线发音人,用户可参见 附录13.2
    mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan"); //设置发音人 mTts.setParameter(SpeechConstant.SPEED, "50");//设置语速 mTts.setParameter(SpeechConstant.VOLUME, "80");//设置音量,范围 0~100
    mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); //设置云端
    //设置合成音频保存位置(可自定义保存位置),保存在“./sdcard/iflytek.pcm” //保存在 SD 卡需要在 AndroidManifest.xml 添加写 SD 卡权限
    //仅支持保存为 pcm 和 wav 格式,如果不需要保存合成音频,注释该行代码
    mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, "./sdcard/iflytek.pcm");
    //3.开始合成
    mTts.startSpeaking("黑马程序员,让世界聆听我们的声音", mSynListener);
}

//合成监听器
private SynthesizerListener mSynListener = new SynthesizerListener(){
    //会话结束回调接口,没有错误时,error为null
    public void onCompleted(SpeechError error) {}
    //缓冲进度回调
    //percent为缓冲进度0~100,beginPos为缓冲音频在文本中开始位置,endPos表示缓冲音频在文本中结束位置,info为附加信息。
    public void onBufferProgress(int percent, int beginPos, int endPos, String info) {}
    //开始播放
    public void onSpeakBegin() {}
    //暂停播放
    public void onSpeakPaused() {}
    //播放进度回调
    //percent为播放进度0~100,beginPos为播放音频在文本中开始位置,endPos表示播放音频在文本中结束位置.
    public void onSpeakProgress(int percent, int beginPos, int endPos) {}
    //恢复播放回调接口
    public void onSpeakResumed() {}
    //会话事件回调接口
    public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {}
};

科大讯飞-语言识别
语言识别:
将连续语音快速识别为文字的过程,科大讯飞语音听写能识别通用常见的语句、词汇, 而且不限制说法。
功能实现:
[Java] 纯文本查看 复制代码
   //把语言转换成文字
    public void listen(View view){
        //1.创建SpeechRecognizer对象,第二个参数:本地识别时传InitListener
        SpeechRecognizer mIat= SpeechRecognizer.createRecognizer(this, null);
        //2.设置听写参数,详见《MSC Reference Manual》SpeechConstant类
        mIat.setParameter(SpeechConstant.DOMAIN, "iat"); mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn"); mIat.setParameter(SpeechConstant.ACCENT, "mandarin ");
        //3.开始听写
        mIat.startListening(mRecoListener);
    }
    //听写监听器
    private RecognizerListener mRecoListener = new RecognizerListener(){
        //听写结果回调接口(返回Json格式结果,用户可参见附录13.1);
        //一般情况下会通过onResults接口多次返回结果,完整的识别内容是多次结果的累加;
        //关于解析Json的代码可参见Demo中JsonParser类; //isLast等于true时会话结束。

        StringBuilder sb = new StringBuilder();
        public void onResult(RecognizerResult results, boolean isLast) {
//            Log.d(TAG, "result:" + results.getResultString ());
            VoiceInfo info = new Gson().fromJson(results.getResultString(), VoiceInfo.class);
            if(isLast){
                String content = info.ws.get(0).cw.get(0).w;
                sb.append(content);
                Log.d(TAG, "result:" + sb.toString());
            }else{
                //拼接内容
                List<VoiceInfo.WS> ws = info.ws;
                for (VoiceInfo.WS w:ws){
                    String content = w.cw.get(0).w;
                    sb.append(content);
                }
            }
        }
        //会话发生错误回调接口
        public void onError(SpeechError error) {
            //打印错误码描述
            Log.d(TAG, "error:" + error.getPlainDescription(true)); }
        //开始录音
        public void onBeginOfSpeech() {}
        //volume音量值0~30,data音频数据
        public void onVolumeChanged(int volume, byte[] data){}
        //结束录音
        public void onEndOfSpeech() {}
        //扩展用接口
        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {}
    };

将转换为文字封装成java数据模型
[Java] 纯文本查看 复制代码
public class VoiceInfo {
    public int bg;
    public int ed;
    public boolean ls;
    public int sn;
    public List<WS> ws;

    public class WS{
        public int bg;
        public List<CW> cw;
    }

    public class CW{
        public String sc;
        public String w;
    }
}

在听写监听器中转换java模型,并拼接一句完整的文字
[Java] 纯文本查看 复制代码
//听写监听器
    private RecognizerListener mRecoListener = new RecognizerListener(){
        //听写结果回调接口(返回Json格式结果,用户可参见附录13.1);
        //一般情况下会通过onResults接口多次返回结果,完整的识别内容是多次结果的累加;
        //关于解析Json的代码可参见Demo中JsonParser类; //isLast等于true时会话结束。

        StringBuilder sb = new StringBuilder();
        public void onResult(RecognizerResult results, boolean isLast) {
//            Log.d(TAG, "result:" + results.getResultString ());
            VoiceInfo info = new Gson().fromJson(results.getResultString(), VoiceInfo.class);
            if(isLast){
                String content = info.ws.get(0).cw.get(0).w;
                sb.append(content);
                Log.d(TAG, "result:" + sb.toString());
            }else{
                //拼接内容
                List<VoiceInfo.WS> ws = info.ws;
                for (VoiceInfo.WS w:ws){
                    String content = w.cw.get(0).w;
                    sb.append(content);
                }
            }
        }
        //会话发生错误回调接口
        public void onError(SpeechError error) {
            //打印错误码描述
            Log.d(TAG, "error:" + error.getPlainDescription(true)); }
        //开始录音
        public void onBeginOfSpeech() {}
        //volume音量值0~30,data音频数据
        public void onVolumeChanged(int volume, byte[] data){}
        //结束录音
        public void onEndOfSpeech() {}
        //扩展用接口
        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {}
    };

科大讯飞-带对话框的语言识别
资源导入

带有对话框的功能实现
[Java] 纯文本查看 复制代码
public void dialogListen(View view){
    //1.创建RecognizerDialog对象
    RecognizerDialog mDialog = new RecognizerDialog(this, mInitListener);
    //2.设置accent、language等参数
    mDialog.setParameter(SpeechConstant.LANGUAGE, "zh_cn"); mDialog.setParameter(SpeechConstant.ACCENT, "mandarin");
    //若要将UI控件用于语义理解,必须添加以下参数设置,设置之后onResult回调返回将是语义理解
    //结果
    // mDialog.setParameter("asr_sch", "1");
    // mDialog.setParameter("nlp_version", "2.0");

    //3.设置回调接口
    mDialog.setListener(mRecognizerDialogListener);
    //4.显示dialog,接收语音输入
    mDialog.show();
}

添加听写监听
[Java] 纯文本查看 复制代码
  private InitListener mInitListener = new InitListener() {
        @Override
        public void onInit(int i) {

        }
    };

    private RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() {
        StringBuilder sb = new StringBuilder();
        public void onResult(RecognizerResult results, boolean isLast) {
//            Log.d(TAG, "result:" + results.getResultString ());
            VoiceInfo info = new Gson().fromJson(results.getResultString(), VoiceInfo.class);
            if(isLast){
                String content = info.ws.get(0).cw.get(0).w;
                sb.append(content);
                Log.d(TAG, "result:" + sb.toString());
            }else{
                //拼接内容
                List<VoiceInfo.WS> ws = info.ws;
                for (VoiceInfo.WS w:ws){
                    String content = w.cw.get(0).w;
                    sb.append(content);
                }
            }
        }

        @Override
        public void onError(SpeechError speechError) {

        }
    }

zxing二维码扫描
二维码的概念:
用某种特定的几何图形按一定规律在平面(二维方向上)分布的黑白相间的图形记录数据符号信息。
二维码功能:
信息获取(名片、地图、WIFI密码、资料)
网站跳转(跳转到微博、手机网站、网站)
广告推送(用户扫码,直接浏览商家推送的视频、音频广告)
手机支付(扫描商品二维码,通过银行或第三方支付提供的手机端通道完成支付)
二维码特点:
高密度编码,信息容量大:500多个汉字
容错能力强,具有纠错功能:这使得二维条码因穿孔、污损等引起局部损坏时,照样可以正确得到识读,损毁面积达50%仍可恢复信息
编码范围广:该条码可以把图片、声音、文字、签字、指纹等可以数字化的信息进行编码
扫描二维码功能实现:
由于二维码使用算法,进行保密度编码。如果作为一个开发者来说,实现识别二维码功能,相对来说比较困难。因此,google公司,开源了一套识别二维码的项目。Zxinggithub中搜索zxing,然后主页中,下载对应的案例。继承到工程中。
添加依赖库:

扫描结果处理:

二维码扫描流程
  • 初始化相机,设置一些相机参数;
  • 绑定SurfaceView,在SurfaceView上显示预览图像;
  • 获取相机的一帧图像;
  • 对图像进行一定的预处理,只保留亮度信息,成为灰度图像;
  • 对灰度图像进行二维码解析,解析成功进入下一步,不成功回到第③步;
  • 返回解析结果并退出。
二维码扫描流程图


可以移动的GridView

下载项目并继承到项目中

可拖动的核心类

按下拖动显示对应的专栏的item

移动处理,专栏之间交换位置




停止拖动,松手情况下,显示拖动的item


GridLayout的使用
将GridLayout引入到布局中
[XML] 纯文本查看 复制代码
<!--android:columnCount="4" 列数
android:animateLayoutChanges="true" 开启动画
-->
<GridLayout
    android:id="@+id/gridLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:columnCount="4"
    android:animateLayoutChanges="true"></GridLayout>

注意:这里面中有两属性:android:columnCount="4" 列数android:animateLayoutChanges="true" 开启动画
初始化GridLayout,并添加条目
[Java] 纯文本查看 复制代码
//初始化GridLayout对象
gridLayout = (GridLayout) findViewById(R.id.gridLayout);

添加条目

public void addItem(View view){
    //添加条目
    TextView tv = new TextView(this);
    //设置布局参数
    GridLayout.LayoutParams params = new GridLayout.LayoutParams();
    params.height = GridLayout.LayoutParams.WRAP_CONTENT;
    params.width = getResources().getDisplayMetrics().widthPixels/4 - margin*2;
    //设置外边距
    params.setMargins(margin,margin,margin,margin);
    tv.setLayoutParams(params);
    //设置内边距
    tv.setPadding(0,margin,0,margin);
    tv.setGravity(Gravity.CENTER);
    tv.setText(index+"");
    //设置背景资源
    tv.setBackgroundResource(R.drawable.item_bg);
    index++;
    gridLayout.addView(tv,0);
    //给条目设置长按点击事件
    tv.setOnLongClickListener(onLongClickListener);
}

创建每个item的背景颜色
默认背景图片item_bg_normal.xml
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <corners android:radius="5dp"/>
    <stroke android:color="#000" android:width="1dp"/>
</shape>

按下时的背景图片Item_bg_press.xml:
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <corners android:radius="5dp"/>
    <stroke android:color="#f00" android:width="1dp" android:dashGap="2dp" android:dashWidth="5dp"/>
</shape>

注意:属性dashGap:虚线的宽度               属性dashWidth:实现的宽度
创建条目的状态选择器
[XML] 纯文本查看 复制代码
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_enabled="true" android:drawable="@drawable/item_bg_normal"/>
    <item android:state_enabled="false" android:drawable="@drawable/item_bg_press"/>

</selector>

给item设置背景资源
[Java] 纯文本查看 复制代码
public void addItem(View view){
    //添加条目
    TextView tv = new TextView(this);
    //设置布局参数
    GridLayout.LayoutParams params = new GridLayout.LayoutParams();
    params.height = GridLayout.LayoutParams.WRAP_CONTENT;
    //动态计算每个item的宽度
    params.width = getResources().getDisplayMetrics().widthPixels/4 - margin*2;
    //设置外边距
    params.setMargins(margin,margin,margin,margin);
    tv.setLayoutParams(params);
    //设置内边距
    tv.setPadding(0,margin,0,margin);
    tv.setGravity(Gravity.CENTER);
    tv.setText(index+"");
    //设置背景资源
    tv.setBackgroundResource(R.drawable.item_bg);
    index++;
    gridLayout.addView(tv,0);
    //给条目设置长按点击事件
    tv.setOnLongClickListener(onLongClickListener);
}

DragEvent事件

设置GridLayout每个item长按事件,并产生浮动的阴影效果
[Java] 纯文本查看 复制代码
public void addItem(View view){
    //添加条目
    TextView tv = new TextView(this);
    //设置布局参数
    GridLayout.LayoutParams params = new GridLayout.LayoutParams();
    params.height = GridLayout.LayoutParams.WRAP_CONTENT;
    //动态计算每个item的宽度
    params.width = getResources().getDisplayMetrics().widthPixels/4 - margin*2;
    //设置外边距
    params.setMargins(margin,margin,margin,margin);
    tv.setLayoutParams(params);
    //设置内边距
    tv.setPadding(0,margin,0,margin);
    tv.setGravity(Gravity.CENTER);
    tv.setText(index+"");
    //设置背景资源
    tv.setBackgroundResource(R.drawable.item_bg);
    index++;
    gridLayout.addView(tv,0);
    //给条目设置长按点击事件
    tv.setOnLongClickListener(onLongClickListener);
}

实现长按监听
[Java] 纯文本查看 复制代码
private View.OnLongClickListener onLongClickListener = new View.OnLongClickListener() {
    @Override
    public boolean onLongClick(View v) {
        dragView = v;
        //产生浮动的阴影效果
        //①传递数据  ② 产生阴影的    ③ 传递数据  ④ 状态
        v.startDrag(null,new View.DragShadowBuilder(v),null,0);
        return true;//处理长按事件
    }
};

给GridLayout设置可拖动的事件
[Java] 纯文本查看 复制代码
//初始化GridLayout对象
gridLayout = (GridLayout) findViewById(R.id.gridLayout);
//设置拖拽的监听
gridLayout.setOnDragListener(onDragListener);

实现GridLayout的拖动监听

封装拖动事件类型
[Java] 纯文本查看 复制代码
static SparseArray<String> dragEventType = new SparseArray<String>();
static{
    dragEventType.put(DragEvent.ACTION_DRAG_STARTED, "STARTED");
    dragEventType.put(DragEvent.ACTION_DRAG_ENDED, "ENDED");
    dragEventType.put(DragEvent.ACTION_DRAG_ENTERED, "ENTERED");
    dragEventType.put(DragEvent.ACTION_DRAG_EXITED, "EXITED");
    dragEventType.put(DragEvent.ACTION_DRAG_LOCATION, "LOCATION");
    dragEventType.put(DragEvent.ACTION_DROP, "DROP");
}

通过静态方法获取当前拖动的事件类型
[Java] 纯文本查看 复制代码
/*
DragEvent.ACTION_DRAG_STARTED 手指按下
DragEvent.ACTION_DRAG_ENTERED  手指按下|从GridLayout外部进入
DragEvent.ACTION_DRAG_LOCATION 在Gridlayout的区间内移动
DragEvent.ACTION_DRAG_EXITED   离开GridLayout的区间
DragEvent.ACTION_DROP      松手
DragEvent.ACTION_DRAG_ENDED  松手

 */
public static String getDragEventAction(DragEvent de){
    return dragEventType.get(de.getAction());
}

GridLayout条目拖拽交换
长按记录拖动的条目

监听拖动事件:
按下时:
将拖动的item设置为不可用
初始化每个item的矩形区域
移动时:
判断拖动的item是否在下方item的矩形区域中
       如果存在,进行交互,反之不做交互
抬起时:
       将拖动的item设置为可用
[Java] 纯文本查看 复制代码
private View.OnDragListener onDragListener = new View.OnDragListener() {
    @Override
    public boolean onDrag(View v, DragEvent event) {
        //Log.i(TAG,getDragEventAction(event));
        switch (event.getAction()){
            case DragEvent.ACTION_DRAG_STARTED://按下
                dragView.setEnabled(false);
                initRects();
                break;
            case DragEvent.ACTION_DRAG_LOCATION://移动
                //获取要交换条目的下标
                int exchangeItemPosition = getExchangeItemPosition(event);
                if(exchangeItemPosition > -1 && dragView != gridLayout.getChildAt(exchangeItemPosition)){
                    //移除
                    gridLayout.removeView(dragView);
                    //添加
                    gridLayout.addView(dragView,exchangeItemPosition);
                }
                break;
            case DragEvent.ACTION_DRAG_ENDED://弹起
                dragView.setEnabled(true);
                break;
        }
        return true;//拖拽事件成功的处理
    }
};

初始化每个条目的矩形区域
[Java] 纯文本查看 复制代码
//初始化条目的矩形区域
private void initRects() {
    rects = new ArrayList<>();
    for (int i = 0; i < gridLayout.getChildCount(); i++) {
        View view = gridLayout.getChildAt(i);
        //创建矩形
        Rect rect = new Rect(view.getLeft(),view.getTop(),view.getRight(),view.getBottom());
        rects.add(rect);
    }
}

获取要交换的条目下标
[Java] 纯文本查看 复制代码
//获取要交换条目的下标
private int getExchangeItemPosition(DragEvent event) {
    for (int i = 0; i < rects.size(); i++) {
        Rect rect = rects.get(i);
        if(rect.contains((int)event.getX(),(int)event.getY())){
            return i;
        }
    }
    return -1;
}

自定义DragGridLayout
继承GridLayout,重写构造方法
[Java] 纯文本查看 复制代码
public DragGridLayout(Context context) {
        this(context,null);
    }

    public DragGridLayout(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public DragGridLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

//        android:columnCount="4"
//        android:animateLayoutChanges="true"
        //设置列数
        setColumnCount(columnCount);
        //开启动画
        setLayoutTransition(new LayoutTransition());
    }

初始化GridLayout的显示列数和开启动画
[Java] 纯文本查看 复制代码
 public DragGridLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

//        android:columnCount="4"
//        android:animateLayoutChanges="true"
        //设置列数
        setColumnCount(columnCount);
        //开启动画
        setLayoutTransition(new LayoutTransition());
    }

为外界提供是否可以拖动监听方法
[Java] 纯文本查看 复制代码
public void setHasCanDrag(boolean hasCanDrag) {
    this.hasCanDrag = hasCanDrag;
    if(hasCanDrag){
        setOnDragListener(onDragListener);
    }else{
        setOnDragListener(null);
    }
}

为外界提供设置条目的方法

[Java] 纯文本查看 复制代码
//从外部设置条目的内容
public void setItems(List<String> items) {
    this.items = items;
    createItems(items);
}
//创建所有的条目
private void createItems(List<String> items) {
    //创建条目
    for (String item : items) {
        addItem(item);
    }
}

添加条目
[Java] 纯文本查看 复制代码
public void addItem(String content){
    //添加条目
    TextView tv = new TextView(getContext());
    //设置布局参数
    GridLayout.LayoutParams params = new GridLayout.LayoutParams();
    params.height = GridLayout.LayoutParams.WRAP_CONTENT;
    params.width = getResources().getDisplayMetrics().widthPixels/4 - margin*2;
    //设置外边距
    params.setMargins(margin,margin,margin,margin);
    tv.setLayoutParams(params);
    //设置内边距
    tv.setPadding(0,margin,0,margin);
    tv.setGravity(Gravity.CENTER);
    tv.setText(content);
    //设置背景资源
    tv.setBackgroundResource(R.drawable.item_bg);
    addView(tv,0);

    if(hasCanDrag){
        //给条目设置长按点击事件
        tv.setOnLongClickListener(onLongClickListener);
    }else{
        //给条目设置长按点击事件
        tv.setOnLongClickListener(null);
    }
    //设置条目的点击事件
    tv.setOnClickListener(onClickListener);
}

给GridLayout控件中拖动事件,实现拖动交互功能
[Java] 纯文本查看 复制代码
private View.OnDragListener onDragListener = new View.OnDragListener() {
    @Override
    public boolean onDrag(View v, DragEvent event) {
        //Log.i(TAG,getDragEventAction(event));
        switch (event.getAction()){
            case DragEvent.ACTION_DRAG_STARTED://按下
                dragView.setEnabled(false);
                initRects();
                break;
            case DragEvent.ACTION_DRAG_LOCATION://移动
                //获取要交换条目的下标
                int exchangeItemPosition = getExchangeItemPosition(event);
                if(exchangeItemPosition > -1 && dragView != getChildAt(exchangeItemPosition)){
                    //移除
                   removeView(dragView);
                    //添加
                    addView(dragView,exchangeItemPosition);
                }
                break;
            case DragEvent.ACTION_DRAG_ENDED://弹起
                dragView.setEnabled(true);
                break;
        }
        return true;//拖拽事件成功的处理
    }
};

为外界提供每个条目的点击事件监听接口
[Java] 纯文本查看 复制代码
//接口
public interface OnDragItemClickListener{
    public void onDragItemClick(TextView tv);
}

private OnDragItemClickListener onDragItemClickListener;

public void setOnDragItemClickListener(OnDragItemClickListener onDragItemClickListener) {
    this.onDragItemClickListener = onDragItemClickListener;
}

在添加条目时,设置点击事件
[Java] 纯文本查看 复制代码
//设置条目的点击事件
tv.setOnClickListener(onClickListener);

初始化两个自定义GridLayout控件
[Java] 纯文本查看 复制代码
final DragGridLayout dragGridLayout = (DragGridLayout) findViewById(R.id.dragGridLayout);
dragGridLayout.setHasCanDrag(true);
List<String> items = new ArrayList<>();
items.add("北京");
items.add("上海");
items.add("深圳");
items.add("广州");
items.add("武汉");
items.add("济南");
items.add("重庆");
items.add("长沙");
items.add("大连");
items.add("南京");
items.add("石家庄");
dragGridLayout.setItems(items);

final DragGridLayout dragGridLayout2 = (DragGridLayout) findViewById(R.id.dragGridLayout2);
List<String> items2 = new ArrayList<>();
items2.add("日本");
items2.add("东京");
items2.add("韩国");
items2.add("新加坡");
items2.add("纽约");
items2.add("常德");
items2.add("广西");
items2.add("哈尔滨");
items2.add("南昌");
items2.add("无锡");
items2.add("海南");
dragGridLayout2.setItems(items2);
dragGridLayout2.setHasCanDrag(false);

分别点击两个控件中item进行相互交换
[Java] 纯文本查看 复制代码
//设置条目点击监听
dragGridLayout.setOnDragItemClickListener(new DragGridLayout.OnDragItemClickListener() {
    @Override
    public void onDragItemClick(TextView tv) {
        //移除点击的条目,把条目添加到下面的Gridlayout
        dragGridLayout.removeView(tv);//移除是需要时间,不能直接添加
        dragGridLayout2.addItem(tv.getText().toString());
    }
});

dragGridLayout2.setOnDragItemClickListener(new DragGridLayout.OnDragItemClickListener() {
    @Override
    public void onDragItemClick(TextView tv) {
        //移除点击的条目,把条目添加到上面的Gridlayout
        dragGridLayout2.removeView(tv);//移除是需要时间,不能直接添加
        dragGridLayout.addItem(tv.getText().toString());
    }
});

注意:在添加时,调用
dragGridLayout的addItem方法,进行添加处理
dragGridLayout2.removeView(tv);//移除是需要时间,不能直接添加
dragGridLayout.addItem(tv.getText().toString());





2 个回复

倒序浏览
可以的 很强势
回复 使用道具 举报
多谢分享
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马