Android基础系列 - 手势自定义,识别手势

Posted SingleShu888

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android基础系列 - 手势自定义,识别手势相关的知识,希望对你有一定的参考价值。

之前把谷歌提供的android手势相关的官方文档和网上一些手势分析的文档,也写了一个简单的示例。

那么今天继续深入学习手势相关的API,增加手势提供了API,GestureLibrary和GestureOverlayView。
GestureLibrary中有几个常用的方法。

  • GestureLibraries .fromFile(Context con,String filepath); 获取GestureLibrary的主要途径。filepath是手势缓存的文件地址。

  • addGesture(String name,Gesture gesture);添加一个手势,name是该手势的名称。

  • save();调用保存的方法。

GestureOverlayView是手势相关API中直接与用户打交道的。它的一些常用方法。

  • setGestureStrokeType(GestureOverlayView.GESTURE_STROKE_TYPE_MULTIPLE);设置手势可多笔画绘制,默认情况为单笔画绘制 。

  • setGestureColor(Color.RED); 设置手势的颜色(红色) 。

  • setUncertainGestureColor(Color.RED);设置还没未能形成手势绘制是的颜色(红色) 。

  • setGestureStrokeWidth(10);设置手势宽度10。

  • setFadeOffset(500);手势绘制完成后淡出屏幕的时间间隔,即绘制完手指离开屏幕后相隔多长时间手势从屏幕上消失,可以理解为手势绘制完成手指离开屏幕后到调用onGesturePerformed的时间间隔,默认值为420毫秒,这里设置为0.5秒 。

  • addOnGesturePerformedListener(OnGesturePerformedListener listener);设置手势绘制监听回调。

    OnGesturePerformedListener 是手势已经形成回调的API。大致的使用方法以及意义了解之后就写一个简单的实例。

MainActivity,很多逻辑都写了注释。

package com.example.administrator.myapplication;

import android.content.DialogInterface;
import android.content.Intent;
import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity 

    EditText editText;
    GestureOverlayView overlayView;
    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        editText = (EditText) findViewById(R.id.editText);
        overlayView = (GestureOverlayView) findViewById(R.id.gesture);
        button = (Button) findViewById(R.id.btn);

        //设置手势颜色
        overlayView.setGestureColor(Color.RED);
        //设置手势宽度
        overlayView.setGestureStrokeWidth(10);
        //获得手势的缓存
        final GestureLibrary gestureLibrary = GestureLibraries.fromFile("/mnt/sdcard/mygestures");
        //添加手势监听
        overlayView.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() 
            @Override
            public void onGesturePerformed(GestureOverlayView gestureOverlayView, final Gesture gesture) 
                //加载提示界面
                View save = getLayoutInflater().inflate(R.layout.save,null);
                //获得提示界面的手势图片控件
                ImageView imageView = (ImageView) save.findViewById(R.id.image);

                final EditText editText = (EditText) save.findViewById(R.id.editText);
                //将手势图片转码生成bitmap
                Bitmap bitmap = gesture.toBitmap(128,128,10,0xffff0000);
                imageView.setImageBitmap(bitmap);
                //提示设置
                new AlertDialog.Builder(MainActivity.this)
                        .setView(save)
                        .setPositiveButton("保存", new DialogInterface.OnClickListener() 
                            @Override
                            public void onClick(DialogInterface dialogInterface, int i) 
                                //点击
                                addGesture(gestureLibrary,editText,gesture);
                            
                        ).setNegativeButton("取消",null).show();
            
        );


        button.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                startActivity(new Intent(MainActivity.this,GestureActivity.class));
            
        );
    

    private void addGesture(GestureLibrary gestureLibrary, EditText editText, Gesture gesture) 
        //添加手势
        gestureLibrary.addGesture(editText.getText().toString(),gesture);
        //判断是否保存成功
        if (gestureLibrary.save())
            Toast.makeText(MainActivity.this, "保存成功!", Toast.LENGTH_SHORT).show();
        else 
            Toast.makeText(MainActivity.this, "保存失败!", Toast.LENGTH_SHORT).show();
        
        //调用保存
        gestureLibrary.save();
    


我的主界面布局。

<?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="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.administrator.myapplication.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="绘制自己的手势" />

    <android.gesture.GestureOverlayView
        android:id="@+id/gesture"
        android:layout_centerInParent="true"
        android:layout_width="200dp"
        android:layout_height="220dp"
        android:gestureStrokeType="multiple">
    </android.gesture.GestureOverlayView>
    <LinearLayout
        android:layout_marginTop="20dp"
        android:layout_centerInParent="true"
        android:orientation="vertical"
        android:layout_width="200dp"
        android:layout_height="220dp">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <ImageView
                android:id="@+id/num0"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="40dp"
                android:src="@drawable/circle"/>
            <ImageView
                android:id="@+id/num1"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="40dp"
                android:src="@drawable/circle"/>
            <ImageView
                android:id="@+id/num2"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="40dp"
                android:src="@drawable/circle"/>
        </LinearLayout>
        <LinearLayout
            android:layout_marginTop="40dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <ImageView
                android:id="@+id/num3"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="40dp"
                android:src="@drawable/circle"/>
            <ImageView
                android:id="@+id/num4"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="40dp"
                android:src="@drawable/circle"/>
            <ImageView
                android:id="@+id/num5"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="40dp"
                android:src="@drawable/circle"/>
        </LinearLayout>
        <LinearLayout
            android:layout_marginTop="40dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <ImageView
                android:id="@+id/num6"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="40dp"
                android:src="@drawable/circle"/>
            <ImageView
                android:id="@+id/num7"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="40dp"
                android:src="@drawable/circle"/>
            <ImageView
                android:id="@+id/num8"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="40dp"
                android:src="@drawable/circle"/>
        </LinearLayout>
    </LinearLayout>
    <Button
        android:id="@+id/btn"
        android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="识别手势库"
        android:layout_alignParentBottom="true"/>
</RelativeLayout>

save.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">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="输入名称:"/>
        <EditText
            android:id="@+id/editText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    <ImageView
        android:id="@+id/image"
        android:layout_gravity="center_horizontal"
        android:layout_width="128dp"
        android:layout_height="128dp"
        android:layout_marginTop="10dp"/>
</LinearLayout>

手势从手势库加载,并进行识别。

package com.example.administrator.myapplication;

import android.gesture.Gesture;
import android.gesture.GestureLibraries;
import android.gesture.GestureLibrary;
import android.gesture.GestureOverlayView;
import android.gesture.Prediction;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.Toast;

import java.util.ArrayList;

public class GestureActivity extends AppCompatActivity 

    GestureOverlayView gesture_test;
    GestureLibrary gestureLibrary;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gesture);
        gesture_test = (GestureOverlayView) findViewById(R.id.gesture_test);
        gestureLibrary = GestureLibraries.fromFile("/mnt/sdcard/mygestures");

        if (gestureLibrary.load())
            Toast.makeText(this, "文件手势加载成功。", Toast.LENGTH_SHORT).show();
        else 
            Toast.makeText(this, "文件手势加载失败。", Toast.LENGTH_SHORT).show();
        

        gesture_test.addOnGesturePerformedListener(new GestureOverlayView.OnGesturePerformedListener() 
            @Override
            public void onGesturePerformed(GestureOverlayView gestureOverlayView, Gesture gesture) 
                ArrayList<Prediction> predictions = gestureLibrary.recognize(gesture);
                ArrayList<String> result = new ArrayList<String>();

                Log.i("tag00","数据库一共多少个手势:"+predictions.size());

                for (Prediction prediction:predictions) 
                    Log.i("tag00","手势:"+prediction.name +",相似度:"+prediction.score);
//                    if (prediction.score > 2.0)
                        result.add("与手势【" + prediction.name + "】相似度为" + prediction.score);
//                    
                

                if (result.size() > 0)
                    ArrayAdapter adapter = new ArrayAdapter(GestureActivity.this,android.R.layout.simple_dropdown_item_1line,result.toArray());
                    new AlertDialog.Builder(GestureActivity.this).setAdapter(adapter,null).setPositiveButton("确定",null).show();
                else 
                    Toast.makeText(GestureActivity.this, "无法找到能匹配的手势!", Toast.LENGTH_SHORT).show();
                

            
        );

    

识别界面非常简单。

<?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_gesture"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.administrator.myapplication.GestureActivity">


    <android.gesture.GestureOverlayView
        android:id="@+id/gesture_test"
        android:layout_width="match_parent"
        android:layout_height="match_parent"></android.gesture.GestureOverlayView>
</RelativeLayout>

记得添加权限:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>

由于这个是手势相关的,模拟器不太好运行,真机做一个gif也比较麻烦。以上代码我已经测试没有问题。可以直接使用。这些就是手势的简单自定义和识别。

以上是关于Android基础系列 - 手势自定义,识别手势的主要内容,如果未能解决你的问题,请参考以下文章

Android应用开发基础篇(13)-----GestureDetector(手势识别)

自定义 UIControl 和手势识别器

自定义长按手势识别器

在视图上自定义多个手势

可以使用自定义 UIViewController 但没有自定义 UIView 类来实现手势识别吗?

是否可以自定义触发 UIScrollView 滚动的滑动手势识别?