Android實(shí)現(xiàn)繪畫(huà)板功能
實(shí)現(xiàn)流程:
一、預(yù)期效果
二、設(shè)置橫豎屏切換
三、確定布局
四、自定義滑動(dòng)條
五、繪畫(huà)區(qū)域
六、MainActivity
實(shí)現(xiàn)步驟:
一、預(yù)期效果
二、設(shè)置橫豎屏切換
screenOrientation屬性 | 作用 |
---|---|
user | 用戶當(dāng)前設(shè)置的方向。 |
unspecified | 由系統(tǒng)選擇顯示方向,不同的設(shè)備可能會(huì)有所不同。(旋轉(zhuǎn)手機(jī),界面會(huì)跟著旋轉(zhuǎn)) |
landscape | 限制界面為橫屏,旋轉(zhuǎn)屏幕也不會(huì)改變當(dāng)前狀態(tài)。 |
portrait | 限制界面為豎屏,旋轉(zhuǎn)屏幕也不會(huì)改變當(dāng)前狀態(tài)。 |
behind | 與前一個(gè)activity方向相同。 |
sensor | 根據(jù)傳感器定位方向,旋轉(zhuǎn)手機(jī)90度,180,270,360,界面都會(huì)發(fā)生變化。 |
nosensor | 不由傳感器確定方向。旋轉(zhuǎn)設(shè)備的時(shí)候,界面不會(huì)跟著旋轉(zhuǎn)。初始界面方向由系統(tǒng)提供。 |
sensorLandscape | (橫屏的旋轉(zhuǎn),不會(huì)出現(xiàn)豎屏的現(xiàn)象)根據(jù)傳感器定位方向,旋轉(zhuǎn)手機(jī)180度界面旋轉(zhuǎn)。一般橫屏游戲會(huì)是這個(gè)屬性。 |
sensorPortrait | (豎屏的旋轉(zhuǎn),不會(huì)出現(xiàn)橫屏的現(xiàn)象)根據(jù)傳感器定位方向,旋轉(zhuǎn)手機(jī)180度界面會(huì)旋轉(zhuǎn)。 |
三、確定布局
因?yàn)闄M豎屏切換后控件的寬高都是不一樣的,也就是不固定的,不能用線性布局,而是根據(jù)相對(duì)位置進(jìn)行布局。先用constraintLayout約束,再將小控件組合成一個(gè)線性布局,然后對(duì)整個(gè)線性布局進(jìn)行相對(duì)布局。
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="0dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toTopOf="@id/operation" > <!--滑動(dòng)條--> <com.example.a16drawboard.Slider android:id="@+id/slider" android:layout_width="20dp" android:layout_height="match_parent" android:layout_marginLeft="20dp" android:layout_marginTop="20dp" android:layout_marginBottom="20dp" app:layout_constraintLeft_toLeftOf="parent" /> <!--畫(huà)板--> <com.example.a16drawboard.DrawBoardView android:id="@+id/board" android:layout_width="0dp" android:layout_height="match_parent" app:layout_constraintLeft_toRightOf="@id/slider" app:layout_constraintRight_toLeftOf="@id/color"/> <!--選顏色--> <LinearLayout android:id="@+id/color" android:layout_width="60dp" android:layout_height="match_parent" android:orientation="vertical" android:layout_marginRight="20dp" app:layout_constraintRight_toRightOf="parent" android:gravity="center"> <Button android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/colorAccent" android:onClick="choiceColor"/> <Button android:layout_width="match_parent" android:layout_height="50dp" android:background="@color/colorPrimary" android:onClick="choiceColor"/> <Button android:layout_width="match_parent" android:layout_height="50dp" android:background="#f00" android:onClick="choiceColor"/> <Button android:layout_width="match_parent" android:layout_height="50dp" android:background="#000" android:onClick="choiceColor"/> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> <LinearLayout android:id="@+id/operation" android:layout_width="match_parent" android:layout_height="60dp" android:background="#f00" android:orientation="horizontal" app:layout_constraintBottom_toBottomOf="parent" android:gravity="center"> <Button android:layout_width="70dp" android:layout_height="wrap_content" android:text="撤銷" android:onClick="goBack"/> <Button android:layout_width="70dp" android:layout_height="wrap_content" android:text="清空" android:onClick="clear"/> <Button android:layout_width="70dp" android:layout_height="wrap_content" android:text="橡皮擦" android:onClick="eraser"/> <Button android:layout_width="70dp" android:layout_height="wrap_content" android:text="保存" android:onClick="save"/> <Button android:layout_width="70dp" android:layout_height="wrap_content" android:text="上一步" android:onClick="lastStep"/> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>
四、自定義滑動(dòng)條
public class Slider extends View { private int lineSize = 6; // 線條的粗細(xì) private int lineColor = Color.BLACK;// 默認(rèn)線條顏色 private Paint linePaint; private Paint circlePaint; // 圓點(diǎn)畫(huà)筆 private int thumbColor = Color.MAGENTA; // 圓點(diǎn)顏色 private int cx; // 中心點(diǎn)x private int cy; // 中心點(diǎn)y private int radius; // 小圓點(diǎn)半徑 private int thumbScale = 4; // 圓點(diǎn)縮放尺寸 private float position; // 觸摸點(diǎn)的坐標(biāo) private Paint progressPaint; // 進(jìn)度條進(jìn)度的畫(huà)筆 private int progressColor = Color.MAGENTA; // 進(jìn)度條顏色 public static int PROGRESS = 0; // 進(jìn)度條 public static int SLIDER = 1; // 滑動(dòng)條 private int style = PROGRESS; // 用戶選擇的樣式,默認(rèn)為進(jìn)度條 public int max = 100; // 設(shè)置最大值 public float progress; // 進(jìn)度值 private OnSliderChangeListener onSliderChangeListener; // 滑動(dòng)改變監(jiān)聽(tīng)者 public Slider(Context context) { super(context); } public Slider(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init(){ // 背景線 linePaint = new Paint(Paint.ANTI_ALIAS_FLAG); linePaint.setColor(lineColor); linePaint.setStrokeWidth(lineSize); // 圓點(diǎn) circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); circlePaint.setColor(thumbColor); circlePaint.setStyle(Paint.Style.FILL); // 進(jìn)度條 progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); progressPaint.setColor(progressColor); progressPaint.setStrokeWidth(lineSize); } @Override protected void onDraw(Canvas canvas) { if (getWidth() > getHeight()){ // 橫著 canvas.drawLine(0, getHeight()/2, getWidth(), getHeight()/2, linePaint); if (position>0){ canvas.drawLine(0, getHeight()/2, position, getHeight()/2, progressPaint); } radius = getHeight()/thumbScale; cy = getHeight()/2; // 確定cx的值 if (position < radius) { cx = radius; }else if (position > getWidth()-radius){ cx = getWidth()-radius; }else { cx = (int) position; } }else{ // 豎著 canvas.drawLine(getWidth()/2, 0, getWidth()/2, getHeight(), linePaint); if (position>0){ canvas.drawLine(getWidth()/2, 0, getWidth()/2, position, progressPaint); } radius = getWidth()/thumbScale; cx = getWidth()/2; // 確定中心點(diǎn)cy的值 if (position<radius){ cy = radius; }else if (position > getHeight()-radius){ cy = getHeight()-radius; }else { cy = (int) position; } } // 畫(huà)小圓點(diǎn) if (style == SLIDER){ canvas.drawCircle(cx,cy,radius,circlePaint); } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: // 圓點(diǎn)放大 thumbScale = 2; // 點(diǎn)下去就到那個(gè)位置 if (getWidth()>getHeight()){ // 橫向時(shí),y不變 x改變 position = event.getX(); }else { // 縱向時(shí),x不變 y改變 position = event.getY(); } callback(); break; case MotionEvent.ACTION_MOVE: // 獲取當(dāng)前觸摸點(diǎn)的值XY if (getWidth()>getHeight()){ // 橫向時(shí),y不變 x改變 position = event.getX(); if (position<0){ progress = 0; }else if (position>getWidth()){ position = getWidth(); } }else { // 豎著時(shí),x不變 y改變 position = event.getY(); if (position<0){ progress = 0; }else if (position>getHeight()){ position = getHeight(); } } callback(); break; case MotionEvent.ACTION_UP: thumbScale = 4; break; } if (style == SLIDER){ invalidate(); } return true; } private void callback(){ if (onSliderChangeListener != null){ if (getWidth()>getHeight()){ progress = position/getWidth(); }else { progress = position/getHeight(); } onSliderChangeListener.progressChange(progress*max); } } public int getStyle() { return style; } public void setStyle(int style) { this.style = style; } public float getProgress() { return progress; } public void setProgress(int progress){ // 計(jì)算比例 float rate = (float)(progress*1.0/max); setProgress(rate); } public void setProgress(float progress) { this.progress = progress; if (progress <1.001) { // 將進(jìn)度值轉(zhuǎn)化為控件中的尺寸位置 if (getWidth() > getHeight()) { position = progress * getWidth(); } else { position = progress * getHeight(); } invalidate(); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { if (getWidth() > getHeight()) { position = progress * getWidth(); } else { position = progress * getHeight(); } } public void setMax(int max) { this.max = max; } public interface OnSliderChangeListener{ void progressChange(float progress); } public void setOnSliderChangeListener(OnSliderChangeListener onSliderChangeListener) { this.onSliderChangeListener = onSliderChangeListener; } }
五、繪畫(huà)區(qū)域
public class DrawBoardView extends View { private ArrayList<Graph> graphs; // 操作數(shù)組 private ArrayList<Graph> orginalGraphs; // 原始數(shù)組 private int lineColor = Color.BLACK; private int lineSize = 5; Path mPath; public DrawBoardView(Context context) { super(context); } public DrawBoardView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); } private void init(){ // 初始化數(shù)組 graphs = new ArrayList<>(); orginalGraphs = new ArrayList<>(); setBackgroundColor(Color.WHITE); } @Override protected void onDraw(Canvas canvas) { // 遍歷數(shù)組 Iterator<Graph> iterator = graphs.iterator(); while (iterator.hasNext()){ // 從集合中獲取一個(gè)圖形對(duì)象 Graph line = iterator.next(); // 繪制圖形 canvas.drawPath(line.path,line.paint); } } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: // 創(chuàng)建這條線對(duì)應(yīng)的paint和path Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setColor(lineColor); mPaint.setStrokeWidth(lineSize); mPaint.setStyle(Paint.Style.STROKE); mPath = new Path(); // 設(shè)置圖形的起點(diǎn) mPath.moveTo(event.getX(),event.getY()); // 保存當(dāng)前這個(gè)圖形的詳細(xì)信息 Graph temp = new Graph(mPaint,mPath); graphs.add(temp); orginalGraphs.add(temp); break; case MotionEvent.ACTION_MOVE: // 連接從path終點(diǎn)到當(dāng)前觸摸點(diǎn)的線 mPath.lineTo(event.getX(),event.getY()); break; case MotionEvent.ACTION_UP: break; } invalidate(); return true; } // 用私有類來(lái)管理圖形的畫(huà)筆和路徑 private class Graph{ Paint paint; Path path; public Graph(Paint paint,Path path){ this.paint=paint; this.path=path; } } // 刪除最后一個(gè)圖形 撤銷 public void removeLast(){ if (graphs.size() >0){ graphs.remove(graphs.size()-1); invalidate(); } } // 刪除所有 清空 public void removeAll(){ graphs.clear(); invalidate(); } // 還原上一步 public void returnToLastStep(){ // 判斷緩存中是否有 if (graphs.size() < orginalGraphs.size()){ // 獲取上一步的索引值 int index = graphs.size()-1+1; // 從緩存中獲取index,添加到操作數(shù)組中 graphs.add(orginalGraphs.get(index)); invalidate(); } } public int getLineSize() { return lineSize; } public void setLineSize(int lineSize) { this.lineSize = lineSize; } public int getLineColor() { return lineColor; } public void setLineColor(int lineColor) { this.lineColor = lineColor; } }
六、MainActivity
public class MainActivity extends AppCompatActivity { private DrawBoardView boardView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 獲取畫(huà)板對(duì)象 boardView = findViewById(R.id.board); // 獲取滑動(dòng)條對(duì)象 final Slider slider = findViewById(R.id.slider); slider.setStyle(Slider.SLIDER); slider.setMax(30); slider.setOnSliderChangeListener(new Slider.OnSliderChangeListener() { @Override public void progressChange(float progress) { boardView.setLineSize((int) progress); } }); slider.setProgress(boardView.getLineSize()); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); } @Override protected void onStart() { super.onStart(); } @Override protected void onResume() { super.onResume(); // 設(shè)置橫屏 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); } @Override protected void onPause() { super.onPause(); } @Override protected void onStop() { super.onStop(); } // 選擇顏色 獲取按鈕上面的背景顏色 public void choiceColor(View view) { // 獲取按鈕上面的背景顏色 ColorDrawable drawable = (ColorDrawable) view.getBackground(); // 獲取顏色 boardView.setLineColor(drawable.getColor()); } // 撤回 public void goBack(View view) { boardView.removeLast(); } // 清空 public void clear(View view) { boardView.removeAll(); } // 橡皮擦 public void eraser(View view) { // 獲取畫(huà)板的drawable ColorDrawable drawable = (ColorDrawable) boardView.getBackground(); // 設(shè)置線條顏色和背景色相同 if (drawable != null){ boardView.setLineColor(drawable.getColor()); }else { boardView.setLineColor(Color.TRANSPARENT); } } // 保存 public void save(View view) { } // 還原 public void lastStep(View view) { boardView.returnToLastStep(); } }
到這里就結(jié)束啦。
以上就是Android實(shí)現(xiàn)畫(huà)板功能的詳細(xì)內(nèi)容,更多關(guān)于Android 畫(huà)板功能的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Android實(shí)現(xiàn)畫(huà)板功能(二)
- Android實(shí)現(xiàn)畫(huà)板功能(一)
- Android實(shí)現(xiàn)簡(jiǎn)單畫(huà)圖畫(huà)板
- Android studio實(shí)現(xiàn)畫(huà)板功能
- Android SurfaceView畫(huà)板操作
- Android實(shí)現(xiàn)畫(huà)畫(huà)板案例
- Android畫(huà)板開(kāi)發(fā)之添加文本文字
- Android畫(huà)板開(kāi)發(fā)之添加背景和保存畫(huà)板內(nèi)容為圖片
- Android畫(huà)板開(kāi)發(fā)之撤銷反撤銷功能
- Android畫(huà)板開(kāi)發(fā)之基本畫(huà)筆功能
- Android畫(huà)板開(kāi)發(fā)之橡皮擦功能
- Android曲線更圓滑的簽名畫(huà)板
相關(guān)文章
Android開(kāi)發(fā)之組件GridView簡(jiǎn)單使用方法示例
這篇文章主要介紹了Android開(kāi)發(fā)之組件GridView簡(jiǎn)單使用方法,涉及Android GridView組件圖片瀏覽及保存圖片等相關(guān)操作技巧,需要的朋友可以參考下2019-03-03Android 網(wǎng)絡(luò)圖片查看器與網(wǎng)頁(yè)源碼查看器
本篇文章主要介紹了Android 網(wǎng)絡(luò)圖片查看器與網(wǎng)頁(yè)源碼查看器的相關(guān)知識(shí)。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-04-04詳解Flutter手游操縱桿移動(dòng)的原理與實(shí)現(xiàn)
這篇文章將為大家詳細(xì)介紹一下Android?Flutter手游中操縱桿移動(dòng)角色的原理與實(shí)現(xiàn)過(guò)程,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-07-07ExpandableListView實(shí)現(xiàn)手風(fēng)琴效果
這篇文章主要為大家詳細(xì)介紹了ExpandableListView實(shí)現(xiàn)手風(fēng)琴效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08Android應(yīng)用開(kāi)發(fā)中WebView的常用方法筆記整理
WebView即是在安卓本地應(yīng)用中打開(kāi)網(wǎng)頁(yè)視圖功能,其中對(duì)于JavaScript加載的各項(xiàng)操作是重點(diǎn)和難點(diǎn),本文就為大家送上Android應(yīng)用開(kāi)發(fā)中WebView的常用方法筆記整理2016-05-05Android 仿淘寶、京東商品詳情頁(yè)向上拖動(dòng)查看圖文詳情控件DEMO詳解
本文給大家介紹android 仿淘寶、京東商品詳情頁(yè)向上拖動(dòng)查看圖文詳情控件DEMO詳解,使用兩個(gè)scrollView,兩個(gè)scrollView 豎直排列,通過(guò)自定義viewGroup來(lái)控制兩個(gè)scrollView的豎直排列,以及滑動(dòng)事件的處理。對(duì)android 拖動(dòng)查看圖文詳情知識(shí)感興趣的朋友一起學(xué)習(xí)吧2016-09-09Android實(shí)現(xiàn)城市選擇三級(jí)聯(lián)動(dòng)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)城市選擇三級(jí)聯(lián)動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12Android編程中TextView寬度過(guò)大導(dǎo)致Drawable無(wú)法居中問(wèn)題解決方法
這篇文章主要介紹了Android編程中TextView寬度過(guò)大導(dǎo)致Drawable無(wú)法居中問(wèn)題解決方法,以實(shí)例形式較為詳細(xì)的分析了TextView設(shè)置及xml布局與調(diào)用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-10-10