紅橙Darren視訊筆記 自定義RatingBar touch事件學習 dp轉px listener監聽
效果圖:
一 需求分析
我們需要實現評分的控制元件 那麼主要有幾步
1.繪製出評分控制元件
2.響應使用者的觸控改變星星數
3.控制元件發生星星變化時通知監聽者
二 自定義屬性
需要屬性:
星星總數
選中星星的圖片id
空白星星的圖片id
星星之間的間隔
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomRatingBar">
<attr name="pressedStar" format="reference" />
<attr name="normalStar" format="reference" />
<attr name="starNumber" format="integer" />
<attr name="starGap" format="dimension" />
</declare-styleable>
</resources>
三 建立自定義View檔案 獲取自定義屬性 初始化各種變數
private static final String TAG = "CustomRatingBar";
private Paint starPaint;
private Bitmap starPressed, starNormal;
private int starNumberSum = 0, starGap = 0, currentPressedStarIndex = -1;
private TouchListener touchListener;
public CustomRatingBar(Context context) {
this(context, null);
}
public CustomRatingBar(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomRatingBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs, context);
}
private void init(AttributeSet attrs, Context context) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomRatingBar);
int normalStarRes = array.getResourceId(R.styleable.CustomRatingBar_normalStar, -1);
int pressedStarRes = array.getResourceId(R.styleable.CustomRatingBar_pressedStar, -1);
starGap = (int) array.getDimension(R.styleable.CustomRatingBar_starGap, dp2px(10));
if (normalStarRes == -1 || pressedStarRes == -1) {
throw new RuntimeException("請指定資源id pressedStar normalStar! ");
}
starPressed = BitmapFactory.decodeResource(getResources(), pressedStarRes);
starNormal = BitmapFactory.decodeResource(getResources(), normalStarRes);
starNumberSum = array.getInt(R.styleable.CustomRatingBar_starNumber, 2);
starPaint = new Paint();
starPaint.setAntiAlias(true);//抗鋸齒
starPaint.setDither(true);//防抖動
array.recycle();
}
private float dp2px(int dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
四 測量控制元件
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = starPressed.getHeight() + getPaddingBottom() + getPaddingTop();
int width = starPressed.getWidth() * starNumberSum + starGap * (starNumberSum - 1) + getPaddingStart() + getPaddingEnd();
setMeasuredDimension(width, height);
}
五 繪製自定義控制元件
@Override
protected void onDraw(Canvas canvas) {
for (int i = 0; i < starNumberSum; i++) {
int startX = getPaddingStart() + (starNormal.getWidth() + starGap) * i;
int startY = getPaddingTop();
if (i <= currentPressedStarIndex) {
canvas.drawBitmap(starPressed, startX, startY, starPaint);
} else {
canvas.drawBitmap(starNormal, startX, startY, starPaint);
}
}
}
六 觸控事件
@Override
public boolean onTouchEvent(MotionEvent event) {
//Log.d(TAG, "onTouchEvent: " + event.getAction() + " event.getX() " + event.getX() + " event.getY() " + event.getY());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
//判斷Y座標落在有效區間
if (event.getY() < getPaddingTop() || event.getY() > (starNormal.getHeight() + getPaddingTop())) {
return true;
}
//判斷X座標落在有效區間
if (event.getX() < getPaddingStart() || event.getX() > (starNormal.getWidth() * starNumberSum + starGap * (starNumberSum - 1) + getPaddingStart())) {
return true;
}
//判斷落在第幾個星星
int starNum = (int) ((event.getX() - getPaddingStart()) / (starNormal.getWidth() + starGap));
if (currentPressedStarIndex != starNum) {
Log.d(TAG, "onTouchEvent: starNum" + starNum);
currentPressedStarIndex = starNum;
invalidate();
}
break;
case MotionEvent.ACTION_UP:
if (touchListener != null) {
touchListener.actionUp(currentPressedStarIndex);
}
break;
}
return true;//不消費事件
}
七 補充 dp轉px listener增加
1.增加listener
public void setTouchListener(TouchListener touchListener) {
this.touchListener = touchListener;
}
interface TouchListener {
void actionUp(int currentStarIndex);
}
在主介面找到自定義view並且註冊監聽
2.記憶體優化 不要頻繁呼叫invalidate 必要時才呼叫
3.各種單位轉px:
private float dp2px(int dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
}
八 其他程式碼
佈局檔案
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<com.example.chj.customratingbar.CustomRatingBar
android:id="@+id/customRatingBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
app:normalStar="@drawable/star_normal"
app:pressedStar="@drawable/star_pressed"
app:starGap="20dp"
app:starNumber="5" />
</RelativeLayout>
主介面
public class MainActivity extends AppCompatActivity implements CustomRatingBar.TouchListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CustomRatingBar customRatingBar = findViewById(R.id.customRatingBar);
customRatingBar.setTouchListener(this);
}
@Override
public void actionUp(int currentStarIndex) {
Toast.makeText(this, "按下了第" + (currentStarIndex + 1) + "個星星", Toast.LENGTH_SHORT).show();
}
}
全程式碼
https://github.com/caihuijian/learn_darren_android.git
相關文章
- JavaScript學習筆記10: 事件繫結&監聽JavaScript筆記事件
- 紅橙Darren視訊筆記 view的繪製流程(上) onMeasure測量程式碼分析 基於API27筆記ViewAPI
- 記錄下學習筆記(Laravel 中的事件監聽)筆記Laravel事件
- 7、listener監聽
- 使用 TypeScript 自定義裝飾器給類的方法增添監聽器 ListenerTypeScript
- DP學習筆記筆記
- Netty中自定義事件處理程式和監聽器Netty事件
- 使用 TypeScript 自定義裝飾器給類的屬性增添監聽器 ListenerTypeScript
- spring boot學習(3): SpringApplication 事件監聽Spring BootAPP事件
- iOS學習筆記--PresentedVC自定義彈窗iOS筆記
- Springboot中自定義監聽器Spring Boot
- Pytest學習筆記6-自定義標記mark筆記
- ASP.NET MVC 學習筆記-7.自定義配置資訊ASP.NETMVC筆記
- 數位DP 學習筆記筆記
- 學習筆記:數位dp筆記
- DP學習筆記(五)(2024.11.16)筆記
- DP學習筆記(四)(2024.10.2)筆記
- 【學習筆記】數位DP筆記
- 插頭DP學習筆記筆記
- 自定義元件-資料監聽器元件
- Vue學習筆記(六):監視屬性Vue筆記
- Spring筆記(7) - Spring的事件和監聽機制Spring筆記事件
- day25-Listener監聽器
- (長期更新)DP 學習筆記筆記
- 步步學習自定義View:Hencoder 精簡版學習筆記(一)View筆記
- VUE-UNI事件轉發監聽Vue事件
- element-ui - 原始碼學習 - 自定義事件UI原始碼事件
- Dotnetty學習筆記——自定義初始化處理器Netty筆記
- HarmonyOS NEXT開發之ArkTS自定義元件學習筆記元件筆記
- [學習筆記] 單調佇列最佳化DP - DP筆記佇列
- listener_scan1.log、listener.log監聽日誌清理
- Javasript學習筆記-Event事件Java筆記事件
- dotnet 讀 WPF 原始碼筆記 從 WM_POINTER 訊息到 Touch 事件原始碼筆記事件
- 安卓學習筆記31:使用自定義檢視繪製文字、圖形與影像安卓筆記
- 元件間通訊--自定義事件元件事件
- JVM狂神說視訊學習筆記JVM筆記
- 高維字首和/SOS DP 學習筆記筆記
- 事件和事件監聽器事件