业务介绍
vivo手写笔SDK提供了在vivo Pad上使用手写笔进行笔形选择、笔形绘制擦除,笔迹预测等能力,主要包含画笔工具栏和画布两个组成部分,通过SDK的简单集成,即可为应用提供多种书写绘制能力。
功能介绍
1.画笔工具栏
画笔工具栏包含以下内容
画笔工具:铅笔,钢笔,水彩笔,马克笔四种画笔工具,5档粗细调节,同时可通过调色盘进行颜色修改
橡皮工具:包含像素橡皮擦和对象橡皮擦两种橡皮擦类型
套索工具:包含框选,移动,复制,剪切,粘贴,删除的功能
另外还提供了撤销、重做及仅手写笔涂鸦开关功能
2.画布
画布提供了一块区域,用于笔迹的绘制和擦除,同时集成了笔迹预测功能
3.笔迹预测
笔迹预测功能通过笔迹的报点,对笔迹绘制的位置进行预测,减少了笔迹绘制的延迟,优化了书写体验
接入指南
一、SDK接入
开发环境
Android Studio 3.4及以上版本
Gradle 版本 3.4及以上
minSdkVersion 28
targetSdkVersion 30
compileSdkVersion 30
接入流程
vivo手写笔SDK目前仅支持在vivo Pad上使用,开发者需要在本地集成aar以及声明SDK所需权限,即可开始接入SDK进行应用开发,接入步骤如下:
1.首先在本地lib添加penengine.aar文件。
2.在build.gradle文件中添加对应依赖
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
implementation(name:'penengine', ext:'aar')
}
3.在AndroidManifest.xml文件中添加SDK所需权限,添加之后便可开始使用SDK进行开发了
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
4.在proguard-rules.pro文件中配置混淆
-keeppackagenames com.vivo.penengine.impl
-keep class com.vivo.penengine.impl.**.*
二、简单应用介绍
下面介绍sdk最基础的使用方式,在应用页面添加画布和画笔工APP自动生成平台具栏,添加之后便可使用画笔选择,笔迹绘制和擦除等功能,步骤如下
1.在应用页面对应的layout文件添加VivoCanvasViewImpl
layout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
android:orientation="vertical"
tools:context=".MainActivity">
<com.vivo.penengine.impl.VivoCanvasViewImpl
android:id="@+id/canvasView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="100dp"
网页转app工具手机版 android:layout_marginBottom="100dp"
/>
</FrameLayout>
2.初始化VivoCanvasViewImpl和VivoToolPickerImpl,并将两者进行绑定
MainActivity
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private VivoCanvasViewImpl mCanvasView;
private VivoToolPickerImpl mToolPicker;
private boolean mIsEngineAvailable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mIsEngineAvailable = PenEngineManager.isEngineAvailable(this);
if (mIsEngineAvailable) {
return;
}
setContentView(R.layout.activity_main);
mCanvasView = findViewById(R.id.canvasView);
mToolPicker = new VivoToolPickerImpl(this);
mToolPicker.bindCanvasView(mCanvasView);
mToolPicker.show();
}
@Override
protected void onResume() {
super.onResume();
if (!mIsEngineAvailable) {
return;
}
if (mToolPicker != null){
mToolPicker.onResume();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (!mIsEngineAvailable) {
return;
}
if (mToolPicker != null) {
mToolPicker.onDestroy();
}
if (mCanvasView != null) {
mCanvasView.release();
}
}
}
功能介绍
一、画布回调和笔形选择
1.可通过注册回调监听接口来获取画布事件,包括涂鸦内容修改和笔形切换。
回调接口中
onStepChanged 在每完成一笔绘制之后进行回调,其中StepType表示该笔绘制的类型,分为 NEW(新增笔迹) UNDO (撤销),REDO(重做),CLEAR(清空撤销重做栈)
onSetPen 接口会在笔形切换之后进行回调,可用该接口监听笔形的变化
onPathLoaded 接口在画布初始化笔迹加载完成后进行回调
mCanvasView.registerOnCanvasListener(new VivoCanvasViewImpl.OnCanvasListener() {
@Override
public void onStepChanged(StepType stepType) {
}
@Override
public void onSetPen(Pen pen) {
}
@Override
public void onPathLoaded() {
}
});
2.默认工具栏提供的笔形类型包括 钢笔、铅笔、水彩笔、马克笔、橡皮、套索,可在初始化toolPicker后通过禁用来实现自定义的笔形组合
Set<PenType> penTypes = new HashSet<>();
penTypes.add(PenType.PENCIL);
mToolPicker.disablePens(penTypes);
3.可在初始化时通过setPen接口设置默认笔形,依次设置笔形类型,透明度(0 ~ 100),颜色,粗细等级(0 ~ 4)
mToolPicker.setPen(Pen.WATERCOLOR_PEN, 60, Color.BLACK, SizeLevel.LEVEL_0);
二、笔迹预测
笔迹预测功能,即通过当前的轨迹,预测出下一个可能的触摸点,用于减少画笔轨迹绘制的延迟。
逻辑如下:
1.通过获取轨迹的点集
2.将点集传入算法中,通过算法计算得到预测点的数据
3.算法返回结果即为根据轨迹点集所得的预测点
以下使用简单demo进行展示,使用一笔完整的绘制轨迹经过的点作为点集,计算出预测点
1.在onTouchEvent中,使用requestUnbufferedDispatch() 方法获取无缓冲的MotionEventsl流
2.对每个ACTION_MOVE和ACTION_UP的报点,获取对应的历史点,得到完整的轨迹点集
3.将点集送入算法引擎中,获取对应的预测点,此后可对此预测点进行渲染
4.view销毁时,需要释放算法引擎
public boolean onTouchEvent(MotionEvent event) {
// step 1: Request unbuffered dispatch of the given stream of MotionEvents to this View.
requestUnbufferedDispatch(event);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mTouchPointDataList.add(ConvertUtil.convertMotionEventToTouchPoint(event));
......
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
handleActionMove(event);
} else if (event.getAction() == MotionEvent.ACTION_UP) {
handleActionMove(event);
......
}
invalidate();
return true;
}
private void handleActionMove(MotionEvent event) {
// step 2: Get the history point set of the current motion event.
for (int i = 0; i < event.getHistorySize() - 1; i++) {
MotionEvent historyEvent = MotionEvent.obtain(event.getDownTime(),
event.getHistoricalEventTime(i), event.getAction(),
event.getHistoricalX(i), event.getHistoricalY(i), 0);
mTouchPointDataList.add(ConvertUtil.convertMotionEventToTouchPoint(historyEvent));
}
mTouchPointDataList.add(ConvertUtil.convertMotionEventToTouchPoint(event));
// step 3: Use algorithm to calculate prediction point.
if (mVivoAlgorithmManager == null) {
mVivoAlgorithmManager = new VivoAlgorithmManagerImpl(getContext());
}
if (mVivoAlgorithmManager.isFeatureEnable()) {
mEstimatePoint = mVivoAlgorithmManager.computeEstimatePoint(mTouchPointDataList);
}
......
}
public void release() {
// step 4: Release algorithm engine.
if (mVivoAlgorithmManager != null) {
mVivoAlgorithmManager.release();
}
......
}
public static TouchPointData convertMotionEventToTouchPoint(MotionEvent event) {
if (event == null) {
return null;
}
TouchPointData touchPoint = new TouchPointData(event.getX(), event.getY());
touchPoint.setOrientation(event.getOrientation());
touchPoint.setPressure(event.getPressure());
touchPoint.setTime(event.getEventTime());
return touchPoint;
}
三、手写笔按键切换
手写笔按键切换功能,需要在按住按键落笔时切换笔形为橡皮擦,抬笔后切换笔形为原来的笔形
处理逻辑如下:
收到ACTION_DOWN事件后进行判断,事件的buttonState是否为BUTTON_STYLUS_PRIMARY,若是则代表按键事件触发,此时判断当前是否为橡皮擦,如果不是则切换为橡皮擦,同时记录状态;
抬笔后对状态进行判断,如果笔形被切换为橡皮擦,则切换为原来笔形。
@Override
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getPointerId(event.getActionIndex()) == 0) {
if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_POINTER_DOWN) {
if (event.getButtonState() == MotionEvent.BUTTON_STYLUS_PRIMARY) {
if (mErasePen != null && mCurrentPen.getType() != Pen.PenType.POINT_ERASE && mCurrentPen.getType() != Pen.PenType.STROKE_ERASE) {
//TODO switch to eraser
mIsDownChange = true;
}
} else {
mIsDownChange = false;
}
} else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_POINTER_UP) {
if (mIsDownChange) {
//TODO switch to last pen
}
}
}
return super.onTouchEvent(event);
}
编辑:yimen,如若转载,请注明出处:https://www.yimenapp.com/kb-yimen/11633/
部分内容来自网络投稿,如有侵权联系立删