Android -- [SelfView] 自定义弹窗式颜色选择器
Android – [SelfView] 自定义弹窗式颜色选择器
PS:
1. 弹框式显示;
2. 支持透明度设置;
3. 支持拖动控件选择颜色;
4. 支持 ARGB | HEX 数值填写预览颜色并返回;
5. 输出支持Hex 和 Int 两种格式;
效果
使用方法:
//activity 内
//1. 声明
private VirgoColorBoard colorBoard;//2. 初始化
colorBoard = new VirgoColorBoard(this);//用content会报错
//监听回调:
//a. Avtivity -> implements VirgoColorBoard.ColorCallback
//b. 直接 new VirgoColorBoard.ColorCallback(){...}
colorBoard.setCallback(this);
//弹窗宽、高、透明属性设置,按需
colorBoard.setDialogAlpha(1);
colorBoard.setDialogWidth(768);
colorBoard.setDialogHeight(660);//回调口执行自定义处理@Override
public void onPick(int color) {//do something
}@Override
public void onPickStr(String hex) {//do something
}
=====================================
码源:
1. VirgoColorBoard.java(弹框式颜色画板)
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;import com.nepalese.harinetest.R;/*** @author nepalese on 2024/12/03 08:43* @usage 弹框式颜色画板*/
public class VirgoColorBoard extends Dialog {private static final String TAG = "VirgoColorBoard";private static final int MSG_UPDATE_UI = 1;private static final int MIN_VALUE = 0;private static final int MAX_VALUE = 255;private ColorCallback callback;//结果回调private VirgoSVPicker svPicker;//饱和度、亮度控制器private VirgoHPicker hPicker;//色相控制器private VirgoAPicker aPicker;//透明度控制器private View preview;//选中颜色预览private EditText etA, etR, etG, etB, etColor;private int mColor;//传入的颜色private int curAlpha;//当前透明度private int dialogWidth = -1;//默认为屏幕宽度private int dialogHeight = 720;//默认弹框高度private float dialogAlpha = 1f;//默认弹框透明度private final float[] hsv = new float[3];public VirgoColorBoard(@NonNull Context context) {super(context, R.style.VirgoColorBoard);this.init(context);}public VirgoColorBoard(@NonNull Context context, int themeResId) {super(context, themeResId);this.init(context);}private void init(Context context) {this.mColor = Color.RED;//默认this.curAlpha = MAX_VALUE;LayoutInflater mLayoutInflater = LayoutInflater.from(context);View view = mLayoutInflater.inflate(R.layout.layout_color_board, null);svPicker = view.findViewById(R.id.svPicker);hPicker = view.findViewById(R.id.hPicker);aPicker = view.findViewById(R.id.aPicker);preview = view.findViewById(R.id.colorPreview);etA = view.findViewById(R.id.etA);etR = view.findViewById(R.id.etR);etG = view.findViewById(R.id.etG);etB = view.findViewById(R.id.etB);etColor = view.findViewById(R.id.etColor);this.setContentView(view);this.setListener();}private void setLayout() {Window dialogWindow = this.getWindow();WindowManager.LayoutParams lp = dialogWindow.getAttributes();dialogWindow.setGravity(Gravity.CENTER);if (dialogWidth > 0) {lp.width = dialogWidth; // 宽度}lp.height = dialogHeight; // 高度lp.alpha = dialogAlpha; // 透明度dialogWindow.setAttributes(lp);}private void initData() {setLayout();initColor(true);}private void initColor(boolean edit) {Color.colorToHSV(mColor, hsv);curAlpha = Color.alpha(mColor);svPicker.setmH(hsv[0]);svPicker.setSV(hsv[1], hsv[2]);hPicker.setmH(hsv[0]);aPicker.setmH(hsv[0]);aPicker.setA(curAlpha);preview.setBackgroundColor(mColor);if(edit){etColor.setText(Integer.toHexString(mColor));}extraARGB(mColor);}private void setListener() {svPicker.setCallback(svCallBack);hPicker.setCallback(hCallBack);aPicker.setCallback(aCallBack);addTextListener();etColor.setOnEditorActionListener(new TextView.OnEditorActionListener() {@Overridepublic boolean onEditorAction(TextView v, int actionId, KeyEvent event) {if (actionId == EditorInfo.IME_ACTION_SEARCH || (event != null && (event.getKeyCode() == KeyEvent.KEYCODE_ENTER))) {//收起键盘((InputMethodManager) etColor.getContext().getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(etColor.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);//要执行任务(这里显示输入的内容)String input = etColor.getText().toString();if (input.length() == 6 || input.length() == 8) {for (Character c : input.toCharArray()) {if (c > 'f') {return true;}}mColor = Color.parseColor("#" + input);initColor(false);if (callback != null) {callback.onPick(mColor);callback.onPickStr("#" + input);}}return true;}return false;}});}//防止edittext settext 与 onTextChanged 发生冲突,在赋值前取消监听,之后重新监听;private void addTextListener() {etA.addTextChangedListener(watcherA);etR.addTextChangedListener(watcherR);etG.addTextChangedListener(watcherG);etB.addTextChangedListener(watcherB);}private void removeTextListener() {etA.removeTextChangedListener(watcherA);etR.removeTextChangedListener(watcherR);etG.removeTextChangedListener(watcherG);etB.removeTextChangedListener(watcherB);}//当a/r/g/b输入值大于255或小于0时,强制重置为255或0;private void resetInputVlue(EditText et, TextWatcher watcher, int value) {et.removeTextChangedListener(watcher);if (value > MAX_VALUE) {et.setText(String.valueOf(MAX_VALUE));} else {et.setText(String.valueOf(MIN_VALUE));}et.addTextChangedListener(watcher);}//手动调整r/g/b值后,更新需要更改的值private void updateWithInput() {Color.colorToHSV(mColor, hsv);svPicker.setmH(hsv[0]);svPicker.setSV(hsv[1], hsv[2]);hPicker.setmH(hsv[0]);aPicker.setmH(hsv[0]);updateSelectColor();}//更新选中的颜色private void updateSelectColor() {if (callback != null) {callback.onPick(mColor);callback.onPickStr("#" + Integer.toHexString(mColor));}preview.setBackgroundColor(mColor);etColor.setText(Integer.toHexString(mColor));}private final TextWatcher watcherA = new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {if (TextUtils.isEmpty(s)) return;int alph = Integer.parseInt(s.toString());if (alph <= MAX_VALUE && alph >= MIN_VALUE) {aPicker.setA(alph);curAlpha = alph;mColor = (alph << 24) | (mColor & 0x00ff0000) | (mColor & 0x0000ff00) | (mColor & 0x000000ff);updateSelectColor();} else {resetInputVlue(etA, this, alph);}}@Overridepublic void afterTextChanged(Editable s) {}};private final TextWatcher watcherR = new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {if (TextUtils.isEmpty(s)) return;int r = Integer.parseInt(s.toString());if (r <= MAX_VALUE && r >= MIN_VALUE) {mColor = (mColor & 0xff000000) | (r & 0x00ff0000) | (mColor & 0x0000ff00) | (mColor & 0x000000ff);updateWithInput();} else {resetInputVlue(etR, this, r);}}@Overridepublic void afterTextChanged(Editable s) {}};private final TextWatcher watcherG = new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {if (TextUtils.isEmpty(s)) return;int g = Integer.parseInt(s.toString());if (g <= MAX_VALUE && g >= MIN_VALUE) {mColor = (mColor & 0xff000000) | (mColor & 0x00ff0000) | (g & 0x0000ff00) | (mColor & 0x000000ff);updateWithInput();} else {resetInputVlue(etG, this, g);}}@Overridepublic void afterTextChanged(Editable s) {}};private final TextWatcher watcherB = new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {if (TextUtils.isEmpty(s)) return;int b = Integer.parseInt(s.toString());if (b <= MAX_VALUE && b >= MIN_VALUE) {mColor = (mColor & 0xff000000) | (mColor & 0x00ff0000) | (mColor & 0x0000ff00) | (b & 0x000000ff);updateWithInput();} else {resetInputVlue(etB, this, b);}}@Overridepublic void afterTextChanged(Editable s) {}};//饱和度、亮度回调private final VirgoSelectCy.PointCallback svCallBack = new VirgoSelectCy.PointCallback() {@Overridepublic void onUpdateSV(float s, float v) {hsv[1] = s;hsv[2] = v;mColor = Color.HSVToColor(hsv);//透明度不变mColor = (curAlpha << 24) | (mColor & 0x00ff0000) | (mColor & 0x0000ff00) | (mColor & 0x000000ff);handler.sendEmptyMessage(MSG_UPDATE_UI);}};//色相回调private final VirgoSelectRect.RectCallback hCallBack = new VirgoSelectRect.RectCallback() {@Overridepublic void onProgress(float progress) {hsv[0] = progress;svPicker.setmH(progress);aPicker.setmH(progress);mColor = Color.HSVToColor(hsv);//透明度不变mColor = (curAlpha << 24) | (mColor & 0x00ff0000) | (mColor & 0x0000ff00) | (mColor & 0x000000ff);handler.sendEmptyMessage(MSG_UPDATE_UI);}};//透明度回调private final VirgoSelectRect.RectCallback aCallBack = new VirgoSelectRect.RectCallback() {@Overridepublic void onProgress(float progress) {int alph = (int) progress;curAlpha = alph;mColor = (alph << 24) | (mColor & 0x00ff0000) | (mColor & 0x0000ff00) | (mColor & 0x000000ff);handler.sendEmptyMessage(MSG_UPDATE_UI);}};private final Handler handler = new Handler(Looper.myLooper()) {@Overridepublic void handleMessage(@NonNull Message msg) {super.handleMessage(msg);if (msg.what == MSG_UPDATE_UI) {updateUI();}}};//选择变化后相应数据改变private void updateUI() {updateSelectColor();extraARGB(mColor);}//提取某一颜色的a/r/g/b和hex值private void extraARGB(int color) {removeTextListener();int a = color >> 24 & 0xff;int r = color >> 16 & 0xff;int g = color >> 8 & 0xff;int b = color & 0xff;etA.setText(String.valueOf(a));etR.setText(String.valueOf(r));etG.setText(String.valueOf(g));etB.setText(String.valueOf(b));addTextListener();}/@Overridepublic void show() {super.show();initData();}@Overridepublic void dismiss() {super.dismiss();}//结果回调public interface ColorCallback {//intvoid onPick(@ColorInt int color);//十六进制void onPickStr(String hex);}public void setCallback(ColorCallback callback) {this.callback = callback;}/*** 颜色赋值*/public void setmColor(@ColorInt int mColor) {this.mColor = mColor;curAlpha = Color.alpha(mColor);}/*** 十六进制颜色*/public void setmColor(String color) {try {this.mColor = Color.parseColor(color);curAlpha = Color.alpha(mColor);} catch (Exception e) {//}}/*** 设置弹框宽度*/public void setDialogWidth(int dialogWidth) {this.dialogWidth = dialogWidth;}/*** 设置弹窗高度*/public void setDialogHeight(int dialogHeight) {this.dialogHeight = dialogHeight;}/*** 设置弹窗透明度*/public void setDialogAlpha(float dialogAlpha) {this.dialogAlpha = dialogAlpha;}
R.style.VirgoColorBoard (themes.xml)
<style name="VirgoColorBoard" parent="@android:style/Theme.Dialog"><item name="android:windowIsFloating">true</item><item name="android:windowBackground">@android:color/transparent</item><item name="android:windowNoTitle">true</item><item name="android:background">@color/colorTransparent</item><item name="android:backgroundDimEnabled">true</item></style>
layout_color_board.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/frame_color_board"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"><com.nepalese.harinetest.player.color.VirgoSVPickerandroid:id="@+id/svPicker"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:padding="10dp"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginBottom="10dp"android:orientation="horizontal"><Viewandroid:id="@+id/colorPreview"android:layout_width="@dimen/size_pre_view"android:layout_height="@dimen/size_pre_view"android:layout_marginEnd="10dp"android:background="@color/colorRed"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><com.nepalese.harinetest.player.color.VirgoHPickerandroid:id="@+id/hPicker"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1"/><Viewandroid:layout_width="wrap_content"android:layout_height="5dp"/><com.nepalese.harinetest.player.color.VirgoAPickerandroid:id="@+id/aPicker"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_weight="1" /></LinearLayout></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><LinearLayoutandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="@dimen/text_14"android:text="A"android:textColor="@color/colorWhite"/><EditTextandroid:id="@+id/etA"android:layout_width="match_parent"android:layout_height="@dimen/size_input_h"android:layout_margin="@dimen/margin_3"android:textSize="@dimen/text_size_12"android:background="@drawable/frame_input"android:textColor="@color/colorWhite"android:textAlignment="center"android:inputType="numberDecimal"/></LinearLayout><LinearLayoutandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="@dimen/text_14"android:text="R"android:textColor="@color/colorWhite"/><EditTextandroid:id="@+id/etR"android:layout_width="match_parent"android:layout_height="@dimen/size_input_h"android:layout_margin="@dimen/margin_3"android:textSize="@dimen/text_size_12"android:background="@drawable/frame_input"android:textColor="@color/colorWhite"android:textAlignment="center"android:inputType="numberDecimal"/></LinearLayout><LinearLayoutandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="@dimen/text_14"android:text="G"android:textColor="@color/colorWhite"/><EditTextandroid:id="@+id/etG"android:layout_width="match_parent"android:layout_height="@dimen/size_input_h"android:layout_margin="@dimen/margin_3"android:textSize="@dimen/text_size_12"android:background="@drawable/frame_input"android:textColor="@color/colorWhite"android:textAlignment="center"android:inputType="numberDecimal"/></LinearLayout><LinearLayoutandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:gravity="center"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="@dimen/text_14"android:text="B"android:textColor="@color/colorWhite"/><EditTextandroid:id="@+id/etB"android:layout_width="match_parent"android:layout_height="@dimen/size_input_h"android:layout_margin="@dimen/margin_3"android:textSize="@dimen/text_size_12"android:background="@drawable/frame_input"android:textColor="@color/colorWhite"android:textAlignment="center"android:inputType="numberDecimal"/></LinearLayout><LinearLayoutandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="2"android:gravity="center"android:orientation="vertical"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="@dimen/text_14"android:text="Hex"android:textColor="@color/colorWhite"/><EditTextandroid:id="@+id/etColor"android:layout_width="match_parent"android:layout_height="@dimen/size_input_h"android:layout_margin="@dimen/margin_3"android:textSize="@dimen/text_size_12"android:background="@drawable/frame_input"android:textColor="@color/colorWhite"android:textAlignment="center" /></LinearLayout></LinearLayout>v</LinearLayout>
</LinearLayout>
dimens.xml
<!--颜色板-->
<dimen name="size_input_h">34dp</dimen>
<dimen name="size_pre_view">40dp</dimen><dimen name="text_size_10">10sp</dimen><dimen name="text_size_12">12sp</dimen><dimen name="text_size_14">14sp</dimen><dimen name="text_size_16">16sp</dimen><dimen name="text_size_18">18sp</dimen><dimen name="text_size_20">20sp</dimen>
frame_input.xml(自定义输入边框样式)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle"><solid android:color="@color/colorTransparent"/><stroke android:color="#B1B1B1"android:width="2dp"/>
</shape>
2. VirgoSVPicker.java(饱和度、亮度控制器)
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.RelativeLayout;import com.nepalese.harinetest.R;/*** @author nepalese on 2024/12/03 14:33*/
public class VirgoSVPicker extends RelativeLayout {private static final String TAG = "VirgoSVPicker";private VirgoColorSVView svView;private VirgoSelectCy selectCy;public VirgoSVPicker(Context context) {this(context, null);}public VirgoSVPicker(Context context, AttributeSet attrs) {this(context, attrs, 0);}public VirgoSVPicker(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);LayoutInflater.from(context).inflate(R.layout.layout_color_sv, this, true);init();}private void init() {svView = findViewById(R.id.svView);selectCy = findViewById(R.id.svCircle);}//设置色调public void setmH(float mH) {svView.setmColorH(mH);}//设置圆形选择器的位置public void setSV(float s, float v) {
// Log.i(TAG, "setSV: s " + s + ", v " + v);selectCy.setSV(s, v);}public void setCallback(VirgoSelectCy.PointCallback callback) {selectCy.setCallback(callback);}
}
layout_color_sv.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><com.nepalese.harinetest.player.color.VirgoColorSVViewandroid:id="@+id/svView"android:layout_width="match_parent"android:layout_height="match_parent"/><com.nepalese.harinetest.player.color.VirgoSelectCyandroid:id="@+id/svCircle"android:layout_width="match_parent"android:layout_height="match_parent"/>
</RelativeLayout>
3. VirgoColorSVView.java(颜色面板)
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;import com.nepalese.harinetest.config.Constants;/*** @author nepalese on 2024/12/03 08:57* @usage 颜色面板*/
public class VirgoColorSVView extends View {private static final String TAG = "VirgoColorView";private Paint mPaint;private int mWidth, mHeight;//H表示色相(0-360),S表示饱和度(0-1),V表示亮度(0-1)private final float[] hsv = new float[3];private final int[] mColors = new int[2];//颜色组public VirgoColorSVView(Context context) {this(context, null);}public VirgoColorSVView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public VirgoColorSVView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {Color.colorToHSV(Color.RED, hsv);mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setStyle(Paint.Style.FILL);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);this.mWidth = this.getWidth();this.mHeight = this.getHeight();}private void setShader() {//渐变渲染Shader mShader = new LinearGradient(0, 0, mWidth, 0, mColors, null, Shader.TileMode.CLAMP);mPaint.setShader(mShader);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);for (int h = 0; h < mHeight; h++) {hsv[2] = (mHeight - h) / (mHeight * 1f);mColors[0] = getC1();mColors[1] = getC2();setShader();canvas.drawLine(0, h, mWidth, h, mPaint);}}private int getC1() {hsv[1] = 0;return Color.HSVToColor(hsv);}private int getC2() {hsv[1] = 1;return Color.HSVToColor(hsv);}/*** 设置色相** @param h; 0-360*/public void setmColorH(float h) {if (h > Constants.COLOR.HUE_MAX || h < 0) {return;}hsv[0] = h;invalidate();}/*** 设置颜色*/public void setColor(@ColorInt int color) {Color.colorToHSV(color, hsv);invalidate();}
}
4. VirgoSelectCy.java(圆形选择器)
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;import androidx.annotation.Nullable;/*** @author nepalese on 2024/12/03 14:38* @usage 圆形选择器*/
public class VirgoSelectCy extends View {private static final String TAG = "VirgoSelectCy";private Paint mPaint;private VirgoPointf point;private PointCallback callback;private int mWidth, mHeight;private int mRadius;private float mS, mV;public VirgoSelectCy(Context context) {this(context, null);}public VirgoSelectCy(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public VirgoSelectCy(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mRadius = 8;mS = 1f;mV = 1f;point = new VirgoPointf();mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setColor(Color.WHITE);mPaint.setStyle(Paint.Style.STROKE);mPaint.setStrokeWidth(2);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);this.mWidth = this.getWidth();this.mHeight = this.getHeight();point.set(mS * mWidth, (1 - mV) * mHeight);}@Overridepublic boolean onTouchEvent(MotionEvent event) {super.onTouchEvent(event);switch (event.getAction()) {case MotionEvent.ACTION_DOWN:case MotionEvent.ACTION_MOVE://生成新值updatePoint(event.getX(), event.getY());break;case MotionEvent.ACTION_UP:break;}return true;}private void updatePoint(float x, float y) {if (x < 0) {x = 0;}if (y < 0) {y = 0;}if (x > mWidth) {x = mWidth;}if (y > mHeight) {y = mHeight;}point.set(x, y);invalidate();float s = x / mWidth;float v = 1 - y / mHeight;if (s < 0) {s = 0;}if (v < 0) {v = 0;}callback.onUpdateSV(s, v);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.TRANSPARENT);canvas.drawCircle(point.getX(), point.getY(), mRadius, mPaint);}public interface PointCallback {void onUpdateSV(float s, float v);}//public void setCallback(PointCallback callback) {this.callback = callback;}public void setSV(float s, float v) {this.mS = s;this.mV = v;if (mWidth > 0) {point.set(s * mWidth, (1 - v) * mHeight);}}public void setmRadius(int mRadius) {this.mRadius = mRadius;invalidate();}
}
VirgoPointf.java
public class VirgoPointf {private float x;private float y;public VirgoPointf() {}public VirgoPointf(float x, float y) {this.x = x;this.y = y;}public float getX() {return x;}public void setX(float x) {this.x = x;}public float getY() {return y;}public void setY(float y) {this.y = y;}public void set(float x, float y) {this.x = x;this.y = y;}
}
5. VirgoHPicker.java(色相控制器)
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.RelativeLayout;import com.nepalese.harinetest.R;
import com.nepalese.harinetest.config.Constants;/*** @author nepalese on 2024/12/03 17:49*/
public class VirgoHPicker extends RelativeLayout {private static final String TAG = "VirgoHPicker";private VirgoSelectRect selectRect;public VirgoHPicker(Context context) {this(context, null);}public VirgoHPicker(Context context, AttributeSet attrs) {this(context, attrs, 0);}public VirgoHPicker(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);LayoutInflater.from(context).inflate(R.layout.layout_color_h, this, true);init();}private void init() {selectRect = findViewById(R.id.hRect);selectRect.setmMaxProgress( Constants.COLOR.HUE_MAX);}public void setmH(float mH) {selectRect.setProgress(mH);}public void setCallback(VirgoSelectRect.RectCallback callback) {selectRect.setCallback(callback);}
}
layout_color_h.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/colorTransparent"><com.nepalese.harinetest.player.color.VirgoColorHViewandroid:layout_margin="3dp"android:layout_width="match_parent"android:layout_height="match_parent"/><com.nepalese.harinetest.player.color.VirgoSelectRectandroid:id="@+id/hRect"android:layout_width="match_parent"android:layout_height="match_parent"/>
</RelativeLayout>
6. VirgoColorHView.java(色相选择器)
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;import androidx.annotation.Nullable;import com.nepalese.harinetest.config.Constants;/*** @author nepalese on 2024/12/03 09:57* @usage 色相选择器*/
public class VirgoColorHView extends View {private static final String TAG = "VirgoColorHView";private Paint mPaint;private int mWidth, mHeight;//H表示色调(0-360),S表示饱和度(0-1),V表示亮度(0-1)private final float[] hsv = new float[3];public VirgoColorHView(Context context) {this(context, null);}public VirgoColorHView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public VirgoColorHView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {Color.colorToHSV(Color.RED, hsv);mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setStyle(Paint.Style.FILL);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);this.mWidth = this.getWidth();this.mHeight = this.getHeight();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//纵向
// for (int h = 0; h < mHeight; h++) {
// hsv[0] = h / (mHeight * 1f) * 360;
// mPaint.setColor(Color.HSVToColor(hsv));
// canvas.drawLine(0, h, mWidth, h, mPaint);
// }//横向for (int w = 0; w < mWidth; w++) {hsv[0] = w / (mWidth * 1f) * Constants.COLOR.HUE_MAX;mPaint.setColor(Color.HSVToColor(hsv));canvas.drawLine(w, 0, w, mHeight, mPaint);}}
}
7. VirgoSelectRect.java(矩形选择器)
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;import androidx.annotation.Nullable;/*** @author nepalese on 2024/12/03 17:52* @usage 矩形选择器*/
public class VirgoSelectRect extends View {private static final String TAG = "VirgoSelectCy";private Paint mPaint;private RectF rectF;private RectCallback callback;private int mWidth, mHeight;private int mMaxProgress;//最大进度值private int mRW;//rect 宽private float mProgress;//进度值private float mRXY;//圆角半径public VirgoSelectRect(Context context) {this(context, null);}public VirgoSelectRect(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public VirgoSelectRect(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mRW = 12;mRXY = 5;mProgress = 0;mMaxProgress = 100;rectF = new RectF();mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setColor(Color.WHITE);mPaint.setStyle(Paint.Style.FILL);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);this.mWidth = this.getWidth() - mRW;//保留底部this.mHeight = this.getHeight();float t = mProgress / mMaxProgress * mWidth;rectF.set(t, 0, t + mRW, mHeight);}@Overridepublic boolean onTouchEvent(MotionEvent event) {super.onTouchEvent(event);switch (event.getAction()) {case MotionEvent.ACTION_DOWN:case MotionEvent.ACTION_MOVE://生成新值updateRect(event.getX());break;case MotionEvent.ACTION_UP:break;}return true;}private void updateRect(float x) {if (x < 0) {x = 0;}if (x > mWidth) {x = mWidth;}rectF.set(x, 0, x + mRW, mHeight);invalidate();mProgress = x / mWidth * mMaxProgress;callback.onProgress(mProgress);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawColor(Color.TRANSPARENT);canvas.drawRoundRect(rectF, mRXY, mRXY, mPaint);}public interface RectCallback {void onProgress(float progress);}//public void setCallback(RectCallback callback) {this.callback = callback;}public void setProgress(float progress) {this.mProgress = progress;if (mWidth > 0) {float off = progress / mMaxProgress * mWidth;rectF.set(off, 0, off + mRW, mHeight);invalidate();}}public void setmMaxProgress(int mMaxProgress) {this.mMaxProgress = mMaxProgress;}public void setmRW(int mRW) {this.mRW = mRW;invalidate();}
}
8. VirgoAPicker.java(透明度控制器)
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.RelativeLayout;import com.nepalese.harinetest.R;
import com.nepalese.harinetest.config.Constants;/*** @author nepalese on 2024/12/03 13:50*/
public class VirgoAPicker extends RelativeLayout {private static final String TAG = "VirgoAPicker";private VirgoColorAView aView;private VirgoSelectRect selectRect;public VirgoAPicker(Context context) {this(context, null);}public VirgoAPicker(Context context, AttributeSet attrs) {this(context, attrs, 0);}public VirgoAPicker(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);LayoutInflater.from(context).inflate(R.layout.layout_color_a, this, true);init();}private void init() {aView = findViewById(R.id.aView);selectRect = findViewById(R.id.aRect);selectRect.setmMaxProgress(Constants.COLOR.ALPHA_MAX);selectRect.setProgress(Constants.COLOR.ALPHA_MAX);}//设置色相public void setmH(float mH) {aView.setmColorH(mH);}public void setA(float a) {selectRect.setProgress(a);}public void setCallback(VirgoSelectRect.RectCallback callback) {selectRect.setCallback(callback);}
}
layout_color_a.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/colorTransparent"><com.nepalese.harinetest.player.color.VirgoColorAViewandroid:id="@+id/aView"android:layout_margin="3dp"android:layout_width="match_parent"android:layout_height="match_parent"/><com.nepalese.harinetest.player.color.VirgoSelectRectandroid:id="@+id/aRect"android:layout_width="match_parent"android:layout_height="match_parent"/>
</RelativeLayout>
9. VirgoColorAView.java
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;import androidx.annotation.ColorInt;
import androidx.annotation.Nullable;import com.nepalese.harinetest.config.Constants;/*** @author nepalese on 2024/12/03 14:03*/
public class VirgoColorAView extends View {private static final String TAG = "VirgoColorAView";private Paint mPaint;private RectF rectF;private int mWidth;private final int[] mColors = new int[2];public VirgoColorAView(Context context) {this(context, null);}public VirgoColorAView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public VirgoColorAView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {mColors[0] = Color.parseColor("#00000000");mColors[1] = Color.parseColor("#ffff0000");mPaint = new Paint();mPaint.setAntiAlias(true);mPaint.setStyle(Paint.Style.FILL);}private void setShader() {//渐变渲染Shader mShader = new LinearGradient(0, 0, mWidth, 0, mColors, null, Shader.TileMode.CLAMP);mPaint.setShader(mShader);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);//在measure之后, layout之前rectF = new RectF(0, 0, w, h);mWidth = w;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);setShader();canvas.drawRect(rectF, mPaint);}/public void setColor(@ColorInt int color) {mColors[1] = color;invalidate();}public void setmColorH(float h) {if (h > Constants.COLOR.HUE_MAX || h < 0) {return;}float[] hsv = new float[3];hsv[0] = h;hsv[1] = 1f;hsv[2] = 1f;setColor(Color.HSVToColor(hsv));}
}
相关文章:
Android -- [SelfView] 自定义弹窗式颜色选择器
Android – [SelfView] 自定义弹窗式颜色选择器 PS: 1. 弹框式显示; 2. 支持透明度设置; 3. 支持拖动控件选择颜色; 4. 支持 ARGB | HEX 数值填写预览颜色并返回; 5. 输出支持Hex 和 Int 两种格式;效果 使用方法&…...
vue-echarts高度缩小时autoresize失效
背景 项目中采用动态给x-vue-echarts style赋值width,height的方式实现echarts图表尺寸的改变 <v-chart...autoresize></v-chart>给v-chart添加autoresize后,在图表宽度变化,高度增加时无异常,高度减小时图表并未缩…...
rabbitMq的rabbitmqctl status报错
Error: unable to perform an operation on node rabbitASUS-PC. Please see diagnostics information and suggestions below. 遇到上图这个错大部分问题可能是由于 RabbitMQ CLI 工具的 Erlang Cookie 与服务器上的不匹配而导致连接问题。Erlang Cookie 在 RabbitMQ 节点之间…...
linux c++ uuid编译时的问题
linux c uuid编译时的问题 写在前面可能编译过和不能编译过的可以编译和link过的不能编译过的 写在前面 几次翻车与uuid相关,超出我认知。 所以,把一些遇到的相关问题写在这里。 可能编译过和不能编译过的 可以编译和link过的 cmake_minimum_require…...
【STM32】RTT-Studio中HAL库开发教程九:FLASH中的OPT
文章目录 一、概要二、内部FLASH排布三、内部FLASH主要特色四、OTP函数介绍五、测试验证 一、概要 STM32系列是一款强大而灵活的微控制器,它的片内Flash存储器可以用来存储有关代码和数据,在实际应用中,我们也需要对这个存储器进行读写操作。…...
[SWPUCTF 2021 新生赛]crypto9
[MoeCTF 2021]Web安全入门指北—GET 意思是GET传参,moeflag 就可以得到falg 输入?moeflag flag为: NSSCTF{ff26110b-8793-403c-990e-15c7f1820596} [SWPUCTF 2021 新生赛]crypto9 #gpt写的代码 from itertools import product letter_list ABCDEFG…...
vue中常用的指令
v - if 指令 功能详细解释 它是一种真正的条件渲染指令。在 Vue 实例初始化以及数据更新过程中,Vue.js 会对v - if指令中的表达式进行求值。这个表达式可以是简单的布尔变量,也可以是一个复杂的计算表达式,只要最终结果是布尔值就行。当表达式…...
Docker Compose实战三:轻松部署PHP
通过前面的文章(Docker Compose基础语法与MySQL部署),你已经掌握了Docker Compose的基本语法和常用指令,并成功部署了一个MySQL数据库服务器。今天,我们将继续深入探索Docker Compose的强大功能,介绍如何使…...
数据分析实战—房价特征关系
1.实战内容 (1) 读取房价特征关系表(house_price.npz)绘制离地铁站的距离与单位面积的房价的散点图,并对其进行分析; import pandas as pd import numpy as np import warnings warnings.filterwarnings(&…...
云和恩墨 zCloud 与华为云 GaussDB 完成兼容性互认证
近日,云和恩墨(北京)信息技术有限公司(以下简称:云和恩墨)的多元数据库智能管理平台 zCloud 与华为云计算技术有限公司(以下简称:华为云)的 GaussDB 数据库完成了兼容性互…...
【大语言模型LangChain】 ModelsIO OutputParsers详解
【大语言模型LangChain】 ModelsIO OutputParsers详解 一、简介二、OutputParsers 的优势三、解析器类型四、实战示例1、String 解析器2、Json 解析器3、Pydantic 解析器4、结构化输出解析器5、OpenAI 函数输出解析器5.1、JsonOutputFunctionsParser5.2、JsonKeyOutputFunction…...
PaddleSpeech本地部署文档
windows安装paddlespeech步骤: 1. 安装vs c编译环境 对于 Windows 系统,需要安装 Visual Studio 来完成 C 编译环境的安装。 Microsoft C Build Tools - Visual Studio 2. 安装conda conda create -y -p paddlespeech python3.8 conda activate pad…...
Android 第三方框架:RxJava:源码分析:责任链模式
文章目录 责任链模式RxJava中的责任链总结 责任链模式 RxJava中的责任链 链式调用的使用过程中形成了两个单向链表 第一个单向链表是Observable链表 它的形成过程: 1.首先调用Observable的静态方法创建第一个Observable对象,作为Observable链表的表…...
网络安全 与 加密算法
计算机中的网络安全 在本篇中介绍了以下几个方面: 机密性 密码学 对称加密算法(DES, 3DES, AES) 公开秘钥算法 RSA大素数的获取 完整性 散列函数(MD5, SHA-1, 并没有提及算法实现) 报文鉴别(MAC) 数字签名 端点鉴别 应用 SSL(TCP网络安全) 运行时安全 防火墙的基本知识 …...
UE4_贴花_贴花基础知识二
五、多表面投射 在本示例中,你将了解贴花如何在多个表面上进行投射。请注意,如果表面朝向与投射方向较为平行,贴花投射时必然会产生一些拉伸。另外,请记住,贴花可以在包括骨骼网格体在内的静态和动态网格体上进行投射。…...
ElasticSearch 搜索、排序、分页功能
一、DSL 查询文档 ElasticSearch 的查询依然是基于 json 风格的 DSL 来实现的。 官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/8.15/query-dsl.html 1.1 DSL 查询分类 常见的查询类型包括: 查询所有:查询出所有数…...
MySQL-9.1.0 实现最基础的主从复制
目录 1 实验介绍 2 实验准备 2.1 创建目录为MySQL挂载使用 2.2 编写 docker-compose.yml 文件 2.3 启动容器 3 主从复制操作 3.1 MASTER 操作指令 3.2 SLAVE1 操作指令 3.3 SLAVE2 操作指令 4 验证是否实现主从 4.1 导入sql脚本查看是否正常主从复制 4.2 检验从库是否看见复制…...
Java中的“泛型“
泛型(Generics)是Java中的一种重要特性,它允许在定义类、接口和方法时使用类型参数(type parameters)。泛型的主要目的是提高代码的类型安全性和重用性。下面我将详细讲解Java中的泛型。 1. 泛型的基本概念 泛型允许我…...
前端(五)css属性
css属性 文章目录 css属性一、字体属性二、文本属性三、背景属性四、盒子模型 一、字体属性 font-weight:文字粗细,在100到900之间,normal(400),bord(700),inherit(继承父类) font-style:文字风格,normal表示正常(默认…...
总结拓展十七:SAP 采购订单行项目“交货“页签解析
《 SAP采购订单行项目“交货”页签字段解析》 在 SAP 系统的采购流程中,采购订单行项目的“交货”页签承载着关键的信息,其中的字段更是对整个交货环节的精准描述和把控的重要元素。理解和正确解析这些字段,对于确保采购流程的顺利进行、优化…...
分布式日志系统设计
一、分布式日志系统定义 分布式日志系统是一种用于收集、存储和分析大规模分布式系统日志的系统。它可以帮助开发人员和系统管理员实时监控和调试系统,提高系统可靠性和可用性,同时也可以用于日志分析和故障排查。 二、简单设计思路 日志收集ÿ…...
DApp开发如何平衡性能与去中心化?
DApp的核心价值在于信任、透明和去中心化,但这些特点往往伴随着性能的瓶颈和高成本。在DApp开发中,如何在保证去中心化的前提下提升性能,成为开发者面临的重要挑战。如何实现性能与去中心化的平衡是一个重要课题。 一、为什么去中心化影响性…...
RK3588开发笔记-Buildroot编译Qt5WebEngine-5.15.10
目录 前言 一、Qt5WebEngine简介 二、Qt5WebEngine编译 总结 前言 Rockchip RK3588是一款强大的多核处理器,广泛应用于边缘计算、人工智能、嵌入式系统等领域。为了在RK3588上运行自定义的Linux系统,并使用Qt5WebEngine进行Web内容渲染,Buildroot是一个非常合适的工具。本…...
2024年12月GESPC++三级真题解析
一、单选题(每题2分,共30分) 题目123456789101112131415答案 B D A A D B C A A D D C D C A 1.下列二进制表示的十进制数值分别是( )[10000011]原( ) [10000011]补ÿ…...
vue-router路由传参的两种方式(params 和 query )
一、vue-router路由传参问题 1、概念: A、vue 路由传参的使用场景一般应用在父路由跳转到子路由时,携带参数跳转。 B、传参方式可划分为 params 传参和 query 传参; C、而 params 传参又可分为在 url 中显示参数和不显示参数两种方式&#x…...
Asp.net 做登录验证码(MVC)
public class ValidateCode{/// <summary>/// 创建随机数/// </summary>/// <param name"num"></param>/// <returns></returns>public string CreateRandom(int num){string str "ABCDEFGHJKMNPQRSTUVWXYZabcdefghjkmnpq…...
在 Chrome中直接调用大型语言模型的API
AI 时代的高速发展,我们都习惯了使用 ChatGPT、Claude、Gemini 和其他 AI 工具来询问各种问题,目前大部分的 AI 应用都是通过服务端 API 来实现的。 如果想要在 Web 上使用 AI 功能往往需要靠服务器来处理一些非常大的模型。这在制作一些生成内容的 AI …...
微信小程序调用腾讯地图-并解读API文档 JavaScript SDK和 WebService API
搜索:腾讯位置服务 找到API文档: 入门中第一步:申请开发者密钥key 前往控制台: 创建应用并获取key: 设置key的时候,还需要小程序的APPID。所以要前往微信公众平台中获取小程序的APPID: 限制要求:…...
WPF 控件
<div id"content_views" class"htmledit_views"><p id"main-toc"><strong>目录</strong></p> WPF基础控件 按钮控件: Button:按钮 RepeatButton:长按按钮 RadioButton:单选按钮 数据显示控件 Te…...
VScode执行任务
背景 在vscode 中 如果执行命令需要传递进来参数,那么直接通过命令行终端的方式不太方便。通过task 任务的方式来进行启动执行,降低反复输入参数等繁琐工作。 首先可以查看vscode 官方文档 task 启动 crtl shift p .vscode/task.json 示例 执行cp…...
淘宝客网站怎么做的/市场调研分析报告怎么写
发现美术给过来的资源,集合到unity后,发现用Spine的默认材质Spine/Skeleton有毛边问题。对比demo的图片后发现demo的图片(都是png格式)没有白色块,而自己的图片有。 原因是Spine工具导出png图片的时候没有选择premulti…...
成都网站建设开发/搜索引擎排名谷歌
忘记过去,超越自己 ❤️ 博客主页 单片机菜鸟哥,一个野生非专业硬件IOT爱好者 ❤️❤️ 本篇创建记录 2022-06-15 ❤️❤️ 本篇更新记录 2022-06-15 ❤️🎉 欢迎关注 🔎点赞 👍收藏 ⭐️留言📝🙏 此博客均由博主单独编写,不存在任何商业团队运营,如发现错误,请…...
网站开发技术协议怎么写/seo搜索引擎优化平台
图解CSS padding、margin、border属性 W3C组织建议把所有网页上的对像都放在一个盒(box)中,设计师可以通过创建定义来控制这个盒的属性,这些对像包括段落、列表、标题、图片以及层。盒模型主要定义四个区域:内容(content)、内边距(padding)、…...
阿里巴巴1688怎么做网站/长沙网站seo哪家公司好
1 网络IO模型 memcached是多线程,非阻塞IO复用的网络模型,分为监听主线程和worker子线程,监听线程监听网络连接,接受请求后,将连接描述字pipe传递给worker线程,进行读写IO,网络层使用libevent封…...
如何做购物网站推广/淘数据
海量数据的解决方案参考文章: (1)海量数据的解决方案 (2)https://www.cnblogs.com/guxia/p/6398674.html 备忘一下。...
网站开发时间段/seo范畴有哪些
[深入Python]sys.modules Python中所有加载到内存的模块都放在sys.modules。当import一个模块时首先会在这个列表中查找是否已经加载了此模块,如果加载了则只是将模块的名字加入到正在调用import的模块的Local名字空间中。如果没有加载则从sys.path目录中按照模块名…...