怎么用手机做一个网站,index网站制作,桂林公司做网站,互联网营销工具工作之余#xff0c;自己想着利用空闲时间做一些小工具出来#xff0c;今天分享的是一个简单的画板工具#xff0c;支持轨迹绘制、更换笔迹颜色等功能#xff0c;并且可以把成品保存到系统相册。支持Android 13
先看一下效果#xff0c;吐槽一下csdn的视频上传#xff0…工作之余自己想着利用空闲时间做一些小工具出来今天分享的是一个简单的画板工具支持轨迹绘制、更换笔迹颜色等功能并且可以把成品保存到系统相册。支持Android 13
先看一下效果吐槽一下csdn的视频上传质量压缩的比较厉害然后比例也发生变化了反正是大家凑合看吧文末会放源码我的所有demo的源码都是不需要积分的 Android画板小工具测试视频 我主要放一下关键代码吧 1.自定义画板SignatureView
public class SignatureView extends View {private Context context;private Paint paint;private Bitmap bitmap;private Canvas canvas;private Path path;public SignatureView(Context context, AttributeSet attrs) {super(context, attrs);this.context context;paint new Paint();paint.setColor(Color.BLACK);paint.setStrokeWidth(10);paint.setStyle(Paint.Style.STROKE);// 获取屏幕尺寸DisplayMetrics displayMetrics getResources().getDisplayMetrics();int screenWidth displayMetrics.widthPixels;int screenHeight displayMetrics.heightPixels;bitmap Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888);canvas new Canvas(bitmap);canvas.drawColor(Color.WHITE);path new Path();}Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawBitmap(bitmap, 0, 0, paint);}Overridepublic boolean onTouchEvent(MotionEvent event) {float x event.getX();float y event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:path.reset();path.moveTo(x, y);break;case MotionEvent.ACTION_MOVE:path.lineTo(x, y);canvas.drawPath(path, paint);break;case MotionEvent.ACTION_UP:break;default:return false;}invalidate();return true;}public void setColor(int newColor) {paint.setColor(newColor);}public void clear() {canvas.drawColor(Color.WHITE);invalidate();}public Bitmap getSignatureBitmap() {return bitmap;}public int dpToPx(float dp) {float density context.getResources().getDisplayMetrics().density;return Math.round(dp * density);}}2.布局文件
?xml version1.0 encodingutf-8?
LinearLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:orientationverticaltools:context.MainActivitycom.swy.signdemo.SignatureViewandroid:idid/signatureViewandroid:layout_widthmatch_parentandroid:layout_height0dpandroid:layout_weight1android:background#ffffff /Viewandroid:layout_widthmatch_parentandroid:layout_height1dpandroid:background#dcdcdc /LinearLayoutandroid:layout_widthwrap_contentandroid:layout_height50dpandroid:layout_gravitybottom|endandroid:layout_margin10dpandroid:orientationhorizontalTextViewandroid:layout_widthwrap_contentandroid:layout_heightwrap_contentandroid:text当前颜色 /FrameLayoutandroid:layout_width32dpandroid:layout_height32dpandroid:layout_gravitycenter_verticalandroid:background#000Viewandroid:idid/view_colorandroid:layout_width40dpandroid:layout_height40dpandroid:layout_gravitycenterandroid:backgroundcolor/black //FrameLayoutButtonandroid:idid/pickColorandroid:layout_widthwrap_contentandroid:layout_heightmatch_parentandroid:layout_marginLeft20dpandroid:text更换颜色 /Buttonandroid:idid/clearButtonandroid:layout_widthwrap_contentandroid:layout_heightmatch_parentandroid:layout_marginLeft10dpandroid:text清空 /Buttonandroid:idid/saveButtonandroid:layout_widthwrap_contentandroid:layout_heightmatch_parentandroid:layout_marginLeft10dpandroid:text保存 //LinearLayout/LinearLayout3.选择颜色的弹窗
public class PickColorWindow extends PopupWindow {private WindowPickColorBinding binding;private CommonAdapterColorData commonAdapter;private ListColorData colors new ArrayList();private ColorData colorDataSelected null;public PickColorWindow(Activity context, ColorData color, PickColorCallBack callBack) {super(context);binding WindowPickColorBinding.inflate(context.getLayoutInflater());setWidth(WindowManager.LayoutParams.MATCH_PARENT);setHeight(WindowManager.LayoutParams.MATCH_PARENT);setContentView(binding.getRoot());initColors();binding.viewColor.setBackgroundColor(Color.parseColor(color.getColorValue()));binding.btnCancel.setOnClickListener(v - {dismiss();});binding.btnConfirm.setOnClickListener(v - {callBack.onPick(colorDataSelected);dismiss();});binding.recycler.setLayoutManager(new GridLayoutManager(context, 4));commonAdapter new CommonAdapterColorData(context,R.layout.item_color, colors) {Overridepublic void convert(CommonViewHolder holder, ColorData bean, int position) {holder.setBackgroundColor(R.id.view_color, Color.parseColor(bean.getColorValue()));holder.setOnClickListener(R.id.view_color, v - {colorDataSelected bean;binding.viewColor.setBackgroundColor(Color.parseColor(colorDataSelected.getColorValue()));});}Overridepublic void footConvert(CommonViewHolder holder, int size) {}};binding.recycler.setAdapter(commonAdapter);}private void initColors() {colors.clear();colors.add(new ColorData(#000000));colors.add(new ColorData(#e6194B));colors.add(new ColorData(#3cb44b));colors.add(new ColorData(#ffe119));colors.add(new ColorData(#4363d8));colors.add(new ColorData(#f58231));colors.add(new ColorData(#42d4f4));colors.add(new ColorData(#f032e6));colors.add(new ColorData(#fabed4));colors.add(new ColorData(#469990));colors.add(new ColorData(#dcbeff));colors.add(new ColorData(#9A6324));colors.add(new ColorData(#fffac8));colors.add(new ColorData(#800000));colors.add(new ColorData(#aaffc3));colors.add(new ColorData(#a9a9a9));}public interface PickColorCallBack {void onPick(ColorData colorData);}
}
4.主界面
public class MainActivity extends AppCompatActivity {private ActivityMainBinding binding;private AlertDialog dialog;private static final int REQUEST_EXTERNAL_STORAGE 1;private static String[] PERMISSIONS_STORAGE {Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE};private boolean havePermission false;private PickColorWindow pickColorWindow;private ColorData currentColor new ColorData(#000000);Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding ActivityMainBinding.inflate(getLayoutInflater());Window window getWindow();window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);window.setStatusBarColor(Color.TRANSPARENT); // 设置状态栏颜色为透明window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);setContentView(binding.getRoot());binding.pickColor.setOnClickListener(v - {showColorPickerDialog();});binding.clearButton.setOnClickListener(v - {binding.signatureView.clear();});binding.saveButton.setOnClickListener(v - {if (havePermission) {saveBitmap(binding.signatureView.getSignatureBitmap());} else {checkPermission();}});}private void saveBitmap(Bitmap bitmap) {// 获取外部存储目录String folderName Environment.DIRECTORY_PICTURES;File file new File(Environment.getExternalStoragePublicDirectory(folderName), signature.png);try {if (file.exists()) {file.delete();}// 创建目录如果不存在file.getParentFile().mkdirs();// 尝试创建文件if (file.createNewFile()) {OutputStream os new FileOutputStream(file);bitmap.compress(Bitmap.CompressFormat.PNG, 100, os); // 保存为PNG格式os.close();// 发送广播通知相册刷新sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));Toast.makeText(MainActivity.this, 保存成功, Toast.LENGTH_SHORT).show();}} catch (IOException e) {e.printStackTrace();}}private void showColorPickerDialog() {if (pickColorWindow ! null) {pickColorWindow.dismiss();pickColorWindow null;}pickColorWindow new PickColorWindow(this, currentColor, (ColorData color) - {currentColor color;binding.signatureView.setColor(Color.parseColor(currentColor.getColorValue()));binding.viewColor.setBackgroundColor(Color.parseColor(currentColor.getColorValue()));});pickColorWindow.showAsDropDown(binding.getRoot());}private void checkPermission() {//检查权限NEED_PERMISSION是否被授权 PackageManager.PERMISSION_GRANTED表示同意授权if (Build.VERSION.SDK_INT 30) {if (!Environment.isExternalStorageManager()) {if (dialog ! null) {dialog.dismiss();dialog null;}dialog new AlertDialog.Builder(this).setTitle(提示)//设置标题.setMessage(请开启文件访问权限否则无法正常使用本应用).setNegativeButton(取消, (dialog, i) - dialog.dismiss()).setPositiveButton(确定, (dialog, which) - {dialog.dismiss();Intent intent new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);startActivity(intent);}).create();dialog.show();} else {havePermission true;saveBitmap(binding.signatureView.getSignatureBitmap());Log.i(swyLog, Android 11以上当前已有权限);}} else {if (Build.VERSION.SDK_INT Build.VERSION_CODES.M) {if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) ! PackageManager.PERMISSION_GRANTED) {//申请权限if (dialog ! null) {dialog.dismiss();dialog null;}dialog new AlertDialog.Builder(this).setTitle(提示)//设置标题.setMessage(请开启文件访问权限否则无法正常使用本应用).setPositiveButton(确定, (dialog, which) - {dialog.dismiss();ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);}).create();dialog.show();} else {havePermission true;saveBitmap(binding.signatureView.getSignatureBitmap());Log.i(swyLog, Android 6.0以上11以下当前已有权限);}} else {havePermission true;saveBitmap(binding.signatureView.getSignatureBitmap());Log.i(swyLog, Android 6.0以下已获取权限);}}}Overridepublic void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {super.onRequestPermissionsResult(requestCode, permissions, grantResults);switch (requestCode) {case REQUEST_EXTERNAL_STORAGE: {if (grantResults.length 0 grantResults[0] PackageManager.PERMISSION_GRANTED) {havePermission true;saveBitmap(binding.signatureView.getSignatureBitmap());Toast.makeText(this, 授权成功, Toast.LENGTH_SHORT).show();} else {havePermission false;Toast.makeText(this, 授权被拒绝, Toast.LENGTH_SHORT).show();}return;}}}}
这个demo的功能还是相对比较简单的然后没有什么好讲的只不过这个demo中有涉及到Android 的运行时权限申请兼容Android13的可以重点关注一下其他的都是UI层的东西基本上把代码复制过去就可以用了真的有什么问题了评论区留言
demo源码