文章目录

  • 一、游戏逻辑
  • 二、数据管理
    • 1.增加
    • 2.删除
    • 3.查询
  • 三、绘图模块
    • 1. 自定义画笔
    • 2.自定义颜色选择器
    • 3.自定义画板
  • 三、 跨端通信
  • 四、游戏界面逻辑
  • 五、简单的Dialog
    • 1.AlertDialog
    • 2.ConfirmDialog
    • 3.PromptDialog
    • 4.SelectDialog
  • 六、效果
  • 七、源码
  • 八、参考

一、游戏逻辑

游戏分为单双人模式

  • 单人模式: 自画自猜,只需要一个设备即可
  • 双人模式: 需要两台设备,主设备根据关键字进行绘图,从设备根据主设备的绘图描述猜关键字。从设备猜对则从设备获胜,否则主设备获胜。

游戏流程图如下

二、数据管理

参考官方教程Data Ability基本概念简单创建一个Data用于管理关键字,用户可以增加、删除关键字。在进行游戏前可以选择数据库中的关键字进行游戏。

1.增加

    /*** 插入一条数据** @param value*/private int insert(String value) {ValuesBucket valuesBucket = new ValuesBucket();valuesBucket.putString(Constants.DB_COLUMN_KEY, value);try {return databaseHelper.insert(Uri.parse(Constants.BASE_URI + Constants.DATA_PATH), valuesBucket);} catch (DataAbilityRemoteException | IllegalStateException exception) {LogUtils.error("insert: dataRemote exception|illegalStateException"+exception.getMessage());}return -1;}

2.删除

/*** 删除一条数据* @param value* @return*/private int delete(String value){DataAbilityPredicates predicates = new DataAbilityPredicates();predicates.equalTo(Constants.DB_COLUMN_KEY,value);try {return databaseHelper.delete(Uri.parse(Constants.BASE_URI + Constants.DATA_PATH), predicates);} catch (DataAbilityRemoteException | IllegalStateException exception) {LogUtils.error("delete: dataRemote exception|illegalStateException"+exception.getMessage());}return 0;}

3.查询

/*** 模糊查询** @param key* @return*/private List<String> fuzzyQuery(String key) {String[] columns = new String[]{Constants.DB_COLUMN_KEY};List<String> result = new ArrayList<>();DataAbilityPredicates predicates = new DataAbilityPredicates();predicates.contains(Constants.DB_COLUMN_KEY,key);try {ResultSet resultSet = databaseHelper.query(Uri.parse(Constants.BASE_URI + Constants.DATA_PATH), columns,predicates);if (!resultSet.goToFirstRow())return null;int index=resultSet.getColumnIndexForName(Constants.DB_COLUMN_KEY);do {String tmp = resultSet.getString(index);result.add(tmp);} while (resultSet.goToNextRow());resultSet.close();} catch (DataAbilityRemoteException | IllegalStateException exception) {LogUtils.error( "fuzzyQuery: dataRemote exception|illegalStateException"+exception.getMessage());}return result;}

三、绘图模块

参考官方自定义组件文档说明自定义组件和自定义view-(你画我猜)画板

1. 自定义画笔

用户可以选择画笔的粗细。
部分代码如下

public void onDraw(Component component, Canvas canvas) {mPaint.setColor(new Color(mPaintColor));HiLog.info(HI_LOG_LABEL, getClass().getSimpleName()+" --- onDraw");for (int i = 0; i < rectList.size(); i++){Rect rect = rectList.get(i);float radius = widthArray[i];switch (mCurrentState){case PEN:mChoosePaint.setColor(Color.WHITE);if (mCurrentIndex == i){canvas.drawCircle(rect.getCenterX(), rect.getCenterY(), radius + 10, mChoosePaint);}canvas.drawCircle(rect.getCenterX(), rect.getCenterY(), radius, mPaint);break;case ERASER:mChoosePaint.setColor(Color.BLACK);if (mCurrentIndex == i){canvas.drawCircle(rect.getCenterX(), rect.getCenterY(), radius + 10, mChoosePaint);}canvas.drawCircle(rect.getCenterX(), rect.getCenterY(), radius, mWhitePaint);break;}}}

2.自定义颜色选择器

用户通过点击对应的颜色来选择画笔的颜色,通过滑动来查看更多颜色


public void onDraw(Component component, Canvas canvas) {Rect rect;Rect chooseRect;switch (mCurrentState){//橡皮擦模式不突出选中颜色case ERASER:for (int i = 0; i < rectList.size(); i++){mPaint.setColor(new Color(colors[i]));rect = rectList.get(i);rect = new Rect(rect.left-getScrollValue(AXIS_X), rect.top , rect.right-getScrollValue(AXIS_X), rect.bottom );canvas.drawRect(rect, mPaint);}break;case PEN:for (int i = 0; i < rectList.size(); i++){mPaint.setColor(new Color(colors[i]));rect = rectList.get(i);//把选中的颜色突出显示if (currentIndex == i){chooseRect = new Rect(rect.left-getScrollValue(AXIS_X), rect.bottom - 10, rect.right-getScrollValue(AXIS_X), rect.bottom);rect = new Rect(rect.left-getScrollValue(AXIS_X), rect.top - 30, rect.right-getScrollValue(AXIS_X), rect.bottom - 30);canvas.drawRect(chooseRect, mPaint);canvas.drawRect(rect, mPaint);}else{rect = new Rect(rect.left-getScrollValue(AXIS_X), rect.top , rect.right-getScrollValue(AXIS_X), rect.bottom );canvas.drawRect(rect, mPaint);}}break;}}/*** 根据点击区域判断选中的颜色* @param component* @param touchEvent* @return*/@Overridepublic boolean onTouchEvent(Component component, TouchEvent touchEvent) {MmiPoint mmiPoint =touchEvent.getPointerPosition(touchEvent.getIndex());;switch (touchEvent.getAction()){case TouchEvent.PRIMARY_POINT_DOWN:HiLog.info(HI_LOG_LABEL,"TouchEvent.PRIMARY_POINT_DOWN");startX = mmiPoint.getX();startY = mmiPoint.getY();break;case TouchEvent.POINT_MOVE:HiLog.info(HI_LOG_LABEL,"TouchEvent.POINT_MOVE");dx = mmiPoint.getX() - startX;dy = mmiPoint.getY() - startY;HiLog.info(HI_LOG_LABEL," --- dx "+dx+", dy "+dy);if (Math.abs(dx) -  Math.abs(dy) >0){if (getScrollValue(AXIS_X) + (-dx) < 0 || getScrollValue(AXIS_X) + (-dx) > getWidth()){return true;}this.scrollBy((int) -dx, 0);HiLog.info(HI_LOG_LABEL,"TouchEvent.Scroll"+getScrollValue(AXIS_X));startX = mmiPoint.getX();startY = mmiPoint.getY();}invalidate();break;case TouchEvent.PRIMARY_POINT_UP:HiLog.info(HI_LOG_LABEL,getClass().getSimpleName()+"TouchEvent.PRIMARY_POINT_UP");if (Math.abs(dx) <= 10 && Math.abs(dy) <= 10){for (int i = 0; i < rectList.size(); i++){if (rectList.get(i).contains((int) startX+getScrollValue(AXIS_X)  , (int) startY+getScrollValue(AXIS_Y) ,(int)startX+getScrollValue(AXIS_X),(int)startY+getScrollValue(AXIS_Y))){HiLog.info(HI_LOG_LABEL,getClass().getSimpleName()+" --- check rect "+i);Rect rect;rectList.clear();for (int j = 0; j < colors.length; j++){int centerX = 20 * j + radius * 2 * j + radius;int centerY = height/2;rect = new Rect(centerX - radius, centerY - radius, centerX + radius, centerY + radius);rectList.add(rect);}currentIndex = i;onStateChangedListener.onPen();strokeWidthChooseView.setmPaintColor(colors[i]);invalidate();}}}startX = 0;startY = 0;dx = 0;dy = 0;break;}return true;}

3.自定义画板

用户根据画笔的粗细和颜色在画板上面滑动来进行绘图
部分代码

 public void onDraw(Component component, Canvas canvas) {HiLog.info(HI_LOG_LABEL, getClass().getSimpleName()+" --- onDraw");if (cacheBitmap!=null){PixelMapHolder pixelMapHolder=new PixelMapHolder(cacheBitmap);canvas.drawPixelMapHolder(pixelMapHolder,0,0,backPaint);}}/*** 按下开始画线,抬起结束画线,把画线结果保存* @param component* @param touchEvent* @return*/@Overridepublic boolean onTouchEvent(Component component, TouchEvent touchEvent) {if(!canDraw){return true;}MmiPoint point = touchEvent.getPointerPosition(touchEvent.getIndex());float x = point.getX();float y = point.getY();//HiLog.info(HI_LOG_LABEL,getClass().getSimpleName()+" --- point ("+x+","+y+")");switch (touchEvent.getAction()) {case TouchEvent.PRIMARY_POINT_DOWN:// HiLog.info(HI_LOG_LABEL,getClass().getSimpleName()+" --- TouchEvent.PRIMARY_POINT_DOWN ");TouchDown(x, y);break;case TouchEvent.POINT_MOVE://HiLog.info(HI_LOG_LABEL,getClass().getSimpleName()+" --- TouchEvent.POINT_MOVE ");TouchMove(x, y);break;case TouchEvent.PRIMARY_POINT_UP://HiLog.info(HI_LOG_LABEL,getClass().getSimpleName()+" --- TouchEvent.PRIMARY_POINT_UP ");TouchUp();break;}//HiLog.info(HI_LOG_LABEL, getClass().getSimpleName()+" --- path size " +paths.size());return true;}private void TouchUp() {Path path = new Path(mPath);paths.push(path);mPath.reset();if (mCurrentState == State.PEN) {states.push(0);Color color = drawPaint.getColor();colors.push(color);widths.push(drawPaint.getStrokeWidth());} else {states.push(1);Color color = eraserPaint.getColor();colors.push(color);widths.push(eraserPaint.getStrokeWidth());}if (canDraw && callback!=null)callback.sendDrawData(points,colors.lastElement().getValue(),mCurrentState,widths.lastElement());}private void TouchMove(float x, float y) {float dx = Math.abs(x - lastX);float dy = Math.abs(y - lastY);mPath.quadTo(lastX, lastY, (x + lastX) / 2, (y + lastY) / 2);lastX = x;lastY = y;points.add(new Point(x, y));drawPath();invalidate();}private void TouchDown(float x, float y) {if (mPath==null)mPath=new Path();points.clear();points.add(new Point(x,y));mPath.moveTo(x, y);lastX = x;lastY = y;drawPath();}

三、 跨端通信

分布式游戏需要在主设备每完成一次绘图动作后把数据传输给从设备进行显示。分布式操作可以参考前面鸿蒙HarmonyOS学习笔记之Service Ability实现跨端通信
由于传输的数据只能是简单的数据类型,故不能把整个画布传输过去,只能把每一条线的点坐标集合传输过去,从设备再根据点坐标进行绘制显示。
部分代码如下

 /*** 发送绘制线的点坐标信息和画笔信息* @param points* @param colors* @param states* @param widths*/public void sendDrawData(List<Point> points, int colors, DrawView.State states, float widths){LogUtils.info(getClass().getSimpleName()+" points "+points);LogUtils.info(getClass().getSimpleName()+" colors "+colors);LogUtils.info(getClass().getSimpleName()+" states "+states);LogUtils.info(getClass().getSimpleName()+" widths "+widths);//把消息封装到MessageParcelMessageParcel data= MessageParcel.obtain();float pointX[]=new float[points.size()];float pointY[]=new float[points.size()];for (int i = 0; i < points.size(); i++) {pointX[i]=points.get(i).getPointX();pointY[i]=points.get(i).getPointY();}data.writeFloatArray(pointX);data.writeFloatArray(pointY);data.writeInt(colors);data.writeInt(states== DrawView.State.PEN?0:1);data.writeFloat(widths);MessageParcel reply =MessageParcel.obtain();MessageOption option =new MessageOption(MessageOption.TF_SYNC);try {//通过RemoteObject实例发送消息remote.sendRequest(Constants.SEND_DRAW_DATA,data,reply,option);//获取消息传递结果int ec=reply.readInt();if(ec!= Constants.ERR_OK){throw new RemoteException();}} catch (RemoteException e) {HiLog.error(LABEL_LOG,"RemoteException: %{public}s",e.getMessage());}}

四、游戏界面逻辑

主、从设备通过消息代码进行简单通信,根据不同的消息代码做出对应的回应。

/*** 接受并处理收到的跨端信息** @param message 消息*/private void handleMessage(int message) {LogUtils.info(getClass().getSimpleName() + " --- handleMessage " + message);//切换到主线程getUITaskDispatcher().asyncDispatch(() -> {switch (message){case Constants.BACK_COM:playerQuit();break;case Constants.FINISH_COM:finish();break;case Constants.REVOKE_COM:drawView.revoke();break;case Constants.CLEAR_COM:drawView.clear();break;case Constants.GUESS_RIGHT:gameOver(true);break;case Constants.GUESS_ERROR:gameOver(false);break;case Constants.TIME_OUT:timeOut();break;default:break;}});}

主设备的画板实现了个传输绘图数据的接口,每次进行绘制操作都把数据发送给从设备

    /*** 把新画的path数据传送给远程端**/private void sendDrawData(List<Point> points,int color,DrawView.State state,float width) {LogUtils.info(getClass().getSimpleName() + " sendPixelMap");if (mRemoteProxy == null) {ToastUtils.show(getContext(), "无跨端连接代理");} else {mRemoteProxy.sendDrawData(points, color, state, width);}}

从设备根据接受到的数据进行还原达到展示主设备上面的绘图信息效果

/*** 远程端处理主机端发送来的path数据** @param points path经过point集合* @param colors 画笔颜色* @param states paint or eraser* @param widths 画笔宽度*/private void handleDrawData(List<Point> points, int colors, DrawView.State states, float widths) {//切换到主线程getUITaskDispatcher().asyncDispatch(() -> {LogUtils.info(getClass().getSimpleName()+" points "+points);drawView.setDrawPaintColor(new Color(colors));drawView.setCurrentState(states);if(states== DrawView.State.PEN){drawView.setDrawPaintStrokeWidth(widths);}else {drawView.setEraserPaintStrokeWidth(widths);}drawView.drawPoints(points);});}

五、简单的Dialog

游戏中需要使用到确认对话框、选择对话框、输入对话框、提示对话框。通过继承CommonDialog来实现自定义的Dialog

1.AlertDialog

package com.tang.draw.dialog;
import com.tang.draw.ResourceTable;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.Text;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.text.RichText;
import ohos.agp.text.richstyles.ImageRichStyle;
import ohos.agp.text.richstyles.RangedRichStyle;
import ohos.agp.text.richstyles.UnderlineRichStyle;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.CommonDialog;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.media.image.ImageSource;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Rect;
import ohos.media.image.common.Size;import java.io.IOException;import static ohos.agp.components.ComponentContainer.LayoutConfig.MATCH_CONTENT;/*********文件名: AlertDialog*创建者: 醉意丶千层梦*创建时间:2022/2/16 16:16*描述: AlertDialog********/
public class AlertDialog extends CommonDialog {private Context mContext;private Text titleText, contentText;private Button okBtn;private DialogClickListener dialogClickListener;public AlertDialog(Context context) {super(context);this.mContext = context;initComponents();initClickedListener();}private void initClickedListener() {okBtn.setClickedListener(component -> {hide();if (dialogClickListener != null) {dialogClickListener.onOKClick();}});}private void initComponents() {Component component = LayoutScatter.getInstance(mContext).parse(ResourceTable.Layout_dialog_alert, null, true);contentText = component.findComponentById(ResourceTable.Id_text_content);titleText = component.findComponentById(ResourceTable.Id_text_title);okBtn = component.findComponentById(ResourceTable.Id_btn_ok);//设置对话框的布局setContentCustomComponent(component);//居中setAlignment(LayoutAlignment.CENTER);setCornerRadius(50);//设置高度为自适应,宽度为屏幕的0.8setSize(mContext.getResourceManager().getDeviceCapability().width* mContext.getResourceManager().getDeviceCapability().screenDensity/ 160*4/5, MATCH_CONTENT);}public void setDialogClickListener(DialogClickListener dialogClickListener){this.dialogClickListener=dialogClickListener;}public void setmContentText(String text,boolean isWinner){if (ohos.system.version.SystemVersion.getApiVersion()==7){RichText richText=new RichText(text);UnderlineRichStyle underlineRichStyle = new UnderlineRichStyle(Color.BLUE);richText.setRichStyle(underlineRichStyle,0,text.length(), RangedRichStyle.Flag.EXCLUDE);ImageRichStyle imageRichStyle=getImageRichStyle(isWinner);if (imageRichStyle!=null){richText.setRichStyle(imageRichStyle,text.length()-1,text.length(),RangedRichStyle.Flag.EXCLUDE);}contentText.setRichText(richText);}else {contentText.setText(text);}}public void setmContentText(String text){contentText.setText(text);}private ImageRichStyle getImageRichStyle(boolean isWinner){ImageRichStyle imageRichStyle = null;ImageSource imageSource;try {if (isWinner){imageSource = ImageSource.create(mContext.getResourceManager().getResource(ResourceTable.Media_icon_victory),null);}else {imageSource = ImageSource.create(mContext.getResourceManager().getResource(ResourceTable.Media_icon_defeat),null);}ImageSource.DecodingOptions decodingOpts = new ImageSource.DecodingOptions();decodingOpts.desiredSize = new Size(contentText.getHeight()-10, contentText.getHeight()-10);decodingOpts.desiredRegion = new Rect(0, 0, 0, 0);decodingOpts.desiredPixelFormat = PixelFormat.ARGB_8888;PixelMapElement pixelMapElement =new PixelMapElement(imageSource.createPixelmap(decodingOpts));imageRichStyle=new ImageRichStyle(pixelMapElement);} catch (IOException e) {e.printStackTrace();} catch (NotExistException e) {e.printStackTrace();}return imageRichStyle;}public interface DialogClickListener {void onOKClick();}
}

2.ConfirmDialog

package com.tang.draw.dialog;import com.tang.draw.ResourceTable;
import com.tang.draw.utils.LogUtils;
import com.tang.draw.view.StrokeWidthChooseView;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.Text;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.utils.TextAlignment;
import ohos.agp.window.dialog.CommonDialog;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;import static ohos.agp.components.ComponentContainer.LayoutConfig.MATCH_CONTENT;/*********文件名: ConfirmDialog*创建者: 醉意丶千层梦*创建时间:2022/2/7 17:24*描述: ConfirmDialog********/
public class ConfirmDialog extends CommonDialog implements Component.ClickedListener {private Context context;private Text  detailText;private Button okBtn,cancelBtn;private OnDialogClickListener dialogClickListener;public ConfirmDialog(Context context) {super(context);this.context=context;//居中setAlignment(LayoutAlignment.CENTER);//设置高度为自适应,宽度为屏幕的0.8setSize(context.getResourceManager().getDeviceCapability().width* context.getResourceManager().getDeviceCapability().screenDensity/ 160*4/5, MATCH_CONTENT);//设置是否启用触摸对话框外区域关闭对话框的功能setAutoClosable(false);initComponents();LogUtils.info(getClass().getSimpleName()+" --- create dialog");}@Overridepublic void onClick(Component component) {if (component==okBtn){LogUtils.info(getClass().getSimpleName()+" --- ok click");//关闭dialoghide();if(dialogClickListener != null){dialogClickListener.onOKClick();}}else if(component==cancelBtn){LogUtils.info(getClass().getSimpleName()+" --- cancel click");//关闭dialoghide();if(dialogClickListener != null){dialogClickListener.onCancelClick();}}}/***按钮接口*/public interface OnDialogClickListener{void onOKClick();void onCancelClick();}/*** 初始化组件以及设置对应按钮监听事件*/private void initComponents(){//设置布局xmlComponent component= LayoutScatter.getInstance(context).parse(ResourceTable.Layout_dialog_confirm,null,true);detailText=component.findComponentById(ResourceTable.Id_text_detail);okBtn=component.findComponentById(ResourceTable.Id_btn_ok);cancelBtn=component.findComponentById(ResourceTable.Id_btn_cancel);//设置监听okBtn.setClickedListener(this::onClick);cancelBtn.setClickedListener(this::onClick);super.setContentCustomComponent(component);}public void setOnDialogClickListener(OnDialogClickListener clickListener){dialogClickListener = clickListener;}/*** 设置提示内容** @param text*/public void setDetailText(String text){if (detailText!=null){detailText.setText(text);}}
}

3.PromptDialog

package com.tang.draw.dialog;import com.tang.draw.ResourceTable;
import com.tang.draw.utils.LogUtils;
import ohos.agp.components.*;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.text.RichText;
import ohos.agp.text.richstyles.ImageRichStyle;
import ohos.agp.text.richstyles.RangedRichStyle;
import ohos.agp.text.richstyles.UnderlineRichStyle;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.CommonDialog;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.media.image.ImageSource;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Rect;
import ohos.media.image.common.Size;import java.io.IOException;import static ohos.agp.components.ComponentContainer.LayoutConfig.MATCH_CONTENT;/*********文件名: PromptDialog*创建者: 醉意丶千层梦*创建时间:2022/2/9 22:36*描述: PromptDialog********/
public class PromptDialog extends CommonDialog {private Context mContext;private Text titleText,errorText;private TextField input;private Button okBtn,cancelBtn;private DialogClickListener dialogClickListener;public PromptDialog(Context context) {super(context);this.mContext =context;initComponents();initClickedListener();}private void initClickedListener() {okBtn.setClickedListener(this::onClick);cancelBtn.setClickedListener(this::onClick);}public void onClick(Component component) {if (component==okBtn){LogUtils.info(getClass().getSimpleName()+" --- ok click");//关闭dialogif(input.getText().length()>8){setError(true,"最大长度8");}else{if(dialogClickListener != null){dialogClickListener.onOKClick(input.getText());input.setText("");}}}else if(component==cancelBtn){LogUtils.info(getClass().getSimpleName()+" --- cancel click");//关闭dialoghide();if(dialogClickListener != null){dialogClickListener.onCancelClick();}}}private void initComponents(){Component component= LayoutScatter.getInstance(mContext).parse(ResourceTable.Layout_dialog_prompt,null,true);okBtn=component.findComponentById(ResourceTable.Id_btn_ok);cancelBtn=component.findComponentById(ResourceTable.Id_btn_cancel);input=component.findComponentById(ResourceTable.Id_field_input);titleText=component.findComponentById(ResourceTable.Id_text_title);errorText=component.findComponentById(ResourceTable.Id_error_tip_text);okBtn.setEnabled(false);input.addTextObserver(new Text.TextObserver() {@Overridepublic void onTextUpdated(String s, int i, int i1, int i2) {if(s==null || s.isEmpty()){okBtn.setEnabled(false);}else {okBtn.setEnabled(true);}}});input.setFocusChangedListener(new Component.FocusChangedListener() {@Overridepublic void onFocusChange(Component component, boolean hasFocus) {if(hasFocus){setError(false,"");}}});super.setContentCustomComponent(component);//居中setAlignment(LayoutAlignment.CENTER);setCornerRadius(50);//设置高度为自适应,宽度为屏幕的0.8setSize(mContext.getResourceManager().getDeviceCapability().width* mContext.getResourceManager().getDeviceCapability().screenDensity/ 160*4/5, MATCH_CONTENT);}/***按钮接口*/public interface DialogClickListener{void onOKClick(String inputData);void onCancelClick();}public void setOnDialogClickListener(DialogClickListener clickListener){dialogClickListener = clickListener;}public void setError(boolean isError,String message){if(isError){errorText.setVisibility(Component.VISIBLE);errorText.setText(message);ShapeElement errorElement = new ShapeElement(this.mContext, ResourceTable.Graphic_background_text_field_error);input.setBackground(errorElement);input.clearFocus();}else{errorText.setVisibility(Component.INVISIBLE);ShapeElement errorElement = new ShapeElement(this.mContext, ResourceTable.Graphic_background_field_input);input.setBackground(errorElement);}}
}

4.SelectDialog

package com.tang.draw.dialog;import com.tang.draw.ResourceTable;
import com.tang.draw.provide.DeviceItemProvider;
import com.tang.draw.provide.SelectItemProvider;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.dialog.CommonDialog;
import ohos.app.Context;
import ohos.distributedschedule.interwork.DeviceInfo;import java.util.ArrayList;
import java.util.List;import static ohos.agp.components.ComponentContainer.LayoutConfig.MATCH_CONTENT;
import static ohos.agp.components.ComponentContainer.LayoutConfig.MATCH_PARENT;/*********文件名: SelectDialog*创建者: 醉意丶千层梦*创建时间:2022/2/15 14:17*描述: SelectDialog********/
public class SelectDialog extends CommonDialog {//圆角矩形的圆角半径private static final int RADIO_SIZE =10;//支持分布式协同的设备列表private  String[] mDataList ;//设备选择回调监听private final ItemSelectListener mItemSelectListener;//当前上下文对象private final Context mContext;public SelectDialog(Context context, String[] dataList,ItemSelectListener itemSelectListener) {super(context);this.mItemSelectListener = itemSelectListener;this.mContext = context;this.mDataList =dataList;}@Overridepublic void onCreate(){super.onCreate();//初始化界面布局Component rootView = LayoutScatter.getInstance(mContext).parse(ResourceTable.Layout_dialog_select,null,false);//初始化pickerPicker picker=rootView.findComponentById(ResourceTable.Id_picker);//初始化按钮Button cancelBtn= rootView.findComponentById(ResourceTable.Id_btn_cancel);Button okBtn=rootView.findComponentById(ResourceTable.Id_btn_ok);if (mDataList==null || mDataList.length==0){String item[]={"没有数据"};picker.setDisplayedData(item);picker.setValue(0);picker.setEnabled(false);okBtn.setClickedListener(component -> {destroy();});}else{ShapeElement shape = new ShapeElement();shape.setShape(ShapeElement.RECTANGLE);shape.setRgbColor(RgbColor.fromArgbInt(0xCFCFCF));picker.setDisplayedLinesElements(shape, shape);picker.setDisplayedData(mDataList);okBtn.setClickedListener(component -> {mItemSelectListener.onItemSelected(mDataList[picker.getValue()]);destroy();});}//设置点击监听cancelBtn.setClickedListener(component -> {destroy();});//设置对话框尺寸setSize(MATCH_PARENT,MATCH_CONTENT);//设置对话框位置setAlignment(LayoutAlignment.CENTER);//设置对话框的圆角背景setCornerRadius(RADIO_SIZE);//设置对话框背景为透明setTransparent(true);//设置对话框的布局setContentCustomComponent(rootView);}public interface ItemSelectListener{void onItemSelected(String item);}
}

六、效果

数据管理
长按数据可以选择删除

游戏
选择关键字和游戏时间发起跨端连接

选择画笔颜色、粗细,撤销操作

橡皮擦功能和作答

退出游戏

七、源码

github:https://github.com/TangtangSix/DrawAndGuess
gitee:https://gitee.com/tangtangsix/DrawAndGuess

八、参考

自定义view-(你画我猜)画板

基于HarmonyOS分布式小游戏之你画我猜相关推荐

  1. 基于JAVA网页小游戏交流论坛计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVA网页小游戏交流论坛计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA网页小游戏交流论坛计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构:B/S架构 开 ...

  2. matlab模拟小游戏,基于MATLAB的小游戏(puzzle)

    更新: 没有素材或者.mat文件看着博客也比较难实现,下面是完整的游戏文件 链接:https://pan.baidu.com/s/1CH_vFQQ_m2rIXde-VtkPWg 提取码:uo2x 游戏 ...

  3. 基于MATLAB的小游戏(puzzle)

    更新: 没有素材或者.mat文件看着博客也比较难实现,下面是完整的游戏文件 链接:https://pan.baidu.com/s/1CH_vFQQ_m2rIXde-VtkPWg 提取码:uo2x 游戏 ...

  4. 基于Python的小游戏

    先记一下流水账,昨天一天没课,写了高数和一篇考研真题的阅读,阅读竟然一个都没错,自己都不敢相信.今天上午三四节课竟然有课(课表上明明啥都没有),差点一不小心就翘了两节课的. 今天下午主要是用Pytho ...

  5. 基于javascript扫雷小游戏,以前上学经常玩

    引言: 扫雷是系统自带的经典小游戏,以前上学那会上机的时候就经常玩这个,趁着五一假期的最后一天,用canvas编写了这个小游戏,看着还行,不知道会不会有什么我没发现的bug,难度目前是设置成简易的,如 ...

  6. 【项目】游戏开发期末大作业 之 基于Java的小游戏 “大鱼吃小鱼“ (代码素材齐全)

    1.EatFish游戏开发过程 1.游戏窗口创建 2.添加背景图片 3.启动封面 4.启动页面的点击事件 5.游戏开始的背景添加 6.双缓存解决闪屏问题 7.敌方鱼类的生成 8.我方鱼的生成 9.我方 ...

  7. 基于HTML5canvars的小游戏,利用HTML5实现Canvas激流勇进小游戏代码

    特效描述:利用HTML5实现 Canvas 激流勇进 小游戏代码.利用HTML5实现Canvas激流勇进小游戏代码 代码结构 1. 引入JS 2. HTML代码 进入游戏 游戏玩法:使用左键.右键和上 ...

  8. 基于HTML5canvars的小游戏,HTML5之canvas简单射箭小游戏

    最近折腾一个自己个人主页,无奈履历太渣,能放在首页的东西不多,于是想给自己的个人主页上添加一个小游戏.遂参考了各种教程,使用HTML5的canvas元素做了一个相当原始的东西出来,效果如图~ QQ截图 ...

  9. 【微信小程序】你画我猜Merged

    你画我猜 代码在github: https://github.com/ETRick/MiniProgram-Draw 设计知识点比较全面,可做微信小程序教程: - canvas绘制 - 自定义组件 - ...

最新文章

  1. java网络编程的通信原理_11 - 网络编程之设备间通信原理
  2. Web前端性能优化——编写高效的JavaScript
  3. CentOS YUM / RPM Error Signature Key ID BAD
  4. mysql 创建带参数的存储过程_在MySQL中创建带有IN和OUT参数的存储过程的方法
  5. 百度糯米android面试题,【百度百度糯米队列百度编程基础数据安全面试题】面试问题:编程:使用C实… - 看准网...
  6. 【教程】批量号码归属地查询可以导出excel表格,手机号码归属地批量查询软件免费版
  7. 微信扫一扫扫描二维码带参
  8. 3D优化之ShadowGun系列二:浓烟,使用面片模拟粒子效果
  9. lol无法连接服务器win10系统,win10系统中lol无法连接服务器怎么办
  10. 我的世界服务器怎么无限附魔,我的世界无限附魔书指令
  11. linux系统看实际内存剩余,linux怎么看内存剩余
  12. 调用微信扫码实现扫一扫签到
  13. 基于.Net Core Web MVC的图书查询系统——第四章,添加模型并使用EF Core生成基架自动生成控制器和视图
  14. 理解悲观锁乐观锁、同步锁、读锁、写锁
  15. 腰椎间盘突出症的自我疗法
  16. C# 操作Excel单元格格式
  17. 语义分割-CityScapes数据集
  18. 世界热力地图 R语言
  19. mac下使用python安装autosub为视频生成字幕
  20. elasticsearch(二)---基本数据操作

热门文章

  1. python使用结巴分词(jieba)创建自己的词典/词库
  2. 基于PyQt5的简易计算器
  3. 大学小说男主计算机,一部小说,男女主是大学校友,男主比较高冷,一次聚会上认识,男主对女主一见钟情,然后带去出租屋里睡了...
  4. k8s学习笔记(10)--- kubernetes核心组件之controller manager详解
  5. 正则表达式中$1,$2算是什么意思
  6. 感知器算法(PLA)
  7. OA系统都能为企业带来什么
  8. OSChina 周四乱弹 —— 如果你追到我,我就和你……
  9. 2014.华为实习招聘数字芯片(转)
  10. 塔科夫为什么远程服务器返回错误,逃离塔科夫登陆错误解决教程