中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何在Android中自定義半圓形圓盤滾動選擇器

發布時間:2021-06-08 16:46:07 來源:億速云 閱讀:158 作者:Leah 欄目:移動開發

如何在Android中自定義半圓形圓盤滾動選擇器?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

attrs.xml文件代碼:

<!--自定義半圓形展示效果轉盤選擇器控件-->
 <declare-styleable name="ringview_half">
 <attr name="image_angle_rh" format="integer" />
 <attr name="image_padding_rh" format="integer" />
 <attr name="max_speed_rh" format="integer" />
 <attr name="min_speed_rh" format="integer" />
 <attr name="list_rh" format="integer" />
 <attr name="can_scroll_rh" format="boolean" />
 <attr name="is_right_select_icon_rh" format="boolean" />
</declare-styleable>

自定義控件的類代碼:

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.wj.R;
import com.wj.utils.DensityUtil;
import com.wj.utils.ScreenUtils;
import java.util.ArrayList;
import java.util.List;

/**
 * @time 2018/6/8
 * @author JunJieW
 * @since 1376881525@qq.com
 * @description 自定義半圓形展示效果轉盤選擇器控件
 */
public class RingViewHalf extends ViewGroup {
 /**
 * 上一次滑動的坐標
 */
 private float mLastX;
 private float mLastY;
 /**
 * 檢測按下到抬起時使用的時間
 */
 private long mDownTime;
 /**
 * 自動滾動線程
 */
 private ScrollResetRunnable mScrollResetRunnable;
 /**
 * 檢測按下到抬起時旋轉的角度
 */
 private float mTmpAngle;
 /**
 * 每秒最大移動角度
 */
 private int mMax_Speed;
 /**
 * 如果移動角度達到該值,則屏蔽點擊
 */
 private int mMin_Speed;
 /**
 * 圓的直徑
 */
 private int mRadius;
 /**
 * 判斷是否正在自動滾動
 */
 private boolean isMove;
 /**
 * 布局滾動角度
 */
 private int mStartAngle = 0;
 /**
 * 中間條的寬度
 */
 private int mCircleLineStrokeWidth;
 /**
 * 圖片內容偏移角度
 */
 private int mImageAngle;
 /**
 * 是否初始化布局
 */
 private boolean isChekc = false;
 /**
 * 布局view
 */
 private List<Integer> mImageList = new ArrayList<>();
 /**
 * 是否可點擊
 */
 private boolean isCanClick = true;

 /**
 * 圖片與環之間的padding
 */
 private int mPadding;
 /**
 * 是否是右邊居中的圖標為選中圖標
 */
 private boolean is_right_select_icon = true;
 /**
 * 是否是右邊居中的圖標為選中圖標
 */
 private Rect select_icon_rect = new Rect();


 //是否能轉動
 private boolean mCanScrool;

 public RingViewHalf(Context context) {
 this(context, null, 0);
 }

 public RingViewHalf(Context context, AttributeSet attrs) {
 this(context, attrs, 0);
 }

 public RingViewHalf(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 //獲取自定義控件設置的值
 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ringview_half, 0, 0);
 mMax_Speed = array.getInteger(R.styleable.ringview_half_max_speed_rh, 300);
 mMin_Speed = array.getInteger(R.styleable.ringview_half_min_speed_rh, 3);
 mImageAngle = array.getInteger(R.styleable.ringview_half_image_angle_rh, 0);
 mPadding = array.getInteger(R.styleable.ringview_half_image_padding_rh, 0);
 mCanScrool = array.getBoolean(R.styleable.ringview_half_can_scroll_rh, true);
 is_right_select_icon = array.getBoolean(R.styleable.ringview_half_is_right_select_icon_rh, true);

 //獲取xml定義的資源文件
 TypedArray mList = context.getResources().obtainTypedArray(array.getResourceId(R.styleable.ringview_half_list_rh, 0));
 int len = mList.length();
 if (len > 0) {
 for (int i = 0; i < len; i++)
 mImageList.add(mList.getResourceId(i, 0));
 } else {
 mImageList.add(R.mipmap.icon);
 mImageList.add(R.mipmap.icon);
 mImageList.add(R.mipmap.icon);
 }
 mList.recycle();
 array.recycle();

 int [] location =new int [2];
 getLocationInWindow(location);
 Log.d("locationInWindow",">>>>X=="+location[0]+"y=="+location[1]);
 addImgIcon();
 }

 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
 if (!isChekc) {
 initView();
 mRadius = getWidth();
 isChekc = true;
 }

 }

 /**
 * 測量
 */
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 int childCount = this.getChildCount();
 for (int i = 0; i < childCount; i++) {
 View child = this.getChildAt(i);
 this.measureChild(child, widthMeasureSpec, heightMeasureSpec);
 child.getMeasuredWidth();
 }

 }

 /**
 * 排版布局
 */
 private void initView() {
 int width = this.getWidth();
 int height = this.getHeight();
 if (width != height) {
 int min = Math.min(width, height);
 width = min;
 height = min;
 }
 //不同屏幕分辨率下做不同的處理
 float instPadding = 70f;
 if (ScreenUtils.getScreenWidth(getContext())<=720){
 instPadding = 55f;
 }

 //圖片擺放的圓弧半徑
 mCircleLineStrokeWidth = getChildAt(0).getMeasuredHeight() + DensityUtil.dip2px(getContext(),instPadding) + mPadding;
 //計算圖片圓的半徑
 final int mContent = width / 2 - mCircleLineStrokeWidth / 2;
 for (int i = 0; i < getChildCount(); i++) {
 View child = this.getChildAt(i);
 //計算每個圖片擺放的角度
 int mAnGle = 360 / mImageList.size() * (i + 1) + mImageAngle;
 //獲取每個圖片擺放的左上角的x和y坐標
 float left = (float) (width / 2 + mContent * Math.cos(mAnGle * Math.PI / 180)) - child.getMeasuredWidth() / 2;
 float top = (float) (height / 2 + mContent * Math.sin(mAnGle * Math.PI / 180)) - child.getMeasuredHeight() / 2;
 /**
 * 一四象限
 */
 if (getQuadrantByAngle(mAnGle) == 1 || getQuadrantByAngle(mAnGle) == 4) {
// child.setRotation(mAnGle - 270);
 /**
  * 二三象限
  */
 } else {
// child.setRotation(mAnGle + 90);
 }

 child.layout((int) left, (int) top, (int) left + child.getMeasuredWidth(), (int) top + child.getMeasuredHeight());


 }

 }

 /**
 * 添加子控件
 */
 private void addImgIcon() {
 for (int i = 1; i < mImageList.size() + 1; i++) {
 //新建imageview
 final ImageView mImageView = new ImageView(getContext());
 mImageView.setImageResource(mImageList.get(i - 1));
 LayoutParams layoutParams = null;

 mImageView.setScaleType(ImageView.ScaleType.FIT_XY);
 if (is_right_select_icon){
 //右側icon為選中狀態
 if (i==mImageList.size()){
  mImageView.setAlpha(1f);
  layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
 }else {
  mImageView.setAlpha(0.5f);
  layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
 }
 }else {
 // 左側icon為選中狀態
 if (i==5){
  mImageView.setAlpha(1f);
  layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
 }else {
  mImageView.setAlpha(0.5f);
  layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
 }
 }

 mImageView.setLayoutParams(layoutParams);
 final int finalI = i;
 //添加點擊事件
 mImageView.setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View view) {
  if (isCanClick) {
//  Toast.makeText(getContext(),finalI + " ---", Toast.LENGTH_SHORT).show();
  if (mOnLogoItemClick != null)
  mOnLogoItemClick.onItemClick(view, finalI - 1);
  }

 }
 });
 //添加view
 addView(mImageView);
 }
 //添加view點擊事件
 setOnClickListener(new OnClickListener() {
 @Override
 public void onClick(View view) {
 if (isCanClick) {
 }
 }
 });

 }

 /**
 * 觸摸監聽
 */
 @Override
 public boolean dispatchTouchEvent(MotionEvent event) {
 if (mCanScrool) {
 float x = event.getX();
 float y = event.getY();


 switch (event.getAction()) {
 case MotionEvent.ACTION_DOWN:

  mLastX = x;
  mLastY = y;
  mDownTime = System.currentTimeMillis();
  mTmpAngle = 0;

  // 如果當前已經在快速滾動
  if (isMove) {
  // 移除快速滾動的回調
  removeCallbacks(mScrollResetRunnable);
  isMove = false;
  return true;
  }

  break;
 case MotionEvent.ACTION_MOVE:
  /**
  * 獲得開始的角度
  */
  float start = getAngle(mLastX, mLastY);
  /**
  * 獲得當前的角度
  */
  float end = getAngle(x, y);
  Log.e("TAG", "start = " + start + " , end =" + end);
  // 一四象限
  if (getQuadrant(x, y) == 1 || getQuadrant(x, y) == 4) {
  mStartAngle += end - start;
  mTmpAngle += end - start;
  //二三象限
  } else {
  mStartAngle += start - end;
  mTmpAngle += start - end;
  }
  // 重新布局
  getCheck();

  break;
 case MotionEvent.ACTION_UP:
  // 獲取每秒移動的角度
  float anglePerSecond = mTmpAngle * 1000
  / (System.currentTimeMillis() - mDownTime);
  // 如果達到最大速度
  if (Math.abs(anglePerSecond) > mMax_Speed && !isMove) {
  // 慣性滾動
  post(mScrollResetRunnable = new ScrollResetRunnable(anglePerSecond));
  return true;
  }

  // 如果當前旋轉角度超過minSpeed屏蔽點擊
  if (Math.abs(mTmpAngle) > mMin_Speed) {
  return true;
  }

  break;
 }
 }
 return super.dispatchTouchEvent(event);
 }

 /**
 * 獲取移動的角度
 */
 private float getAngle(float xTouch, float yTouch) {
 double x = xTouch - (mRadius / 2d);
 double y = yTouch - (mRadius / 2d);
 return (float) (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI);
 }

 /**
 * 根據當前位置計算象限
 */
 private int getQuadrant(float x, float y) {
 int tmpX = (int) (x - mRadius / 2);
 int tmpY = (int) (y - mRadius / 2);
 if (tmpX >= 0) {
 return tmpY >= 0 ? 4 : 1;
 } else {
 return tmpY >= 0 ? 3 : 2;
 }

 }

 /**
 * 在activity的onCreate方法中獲取當前自定義view中在屏幕中的絕對坐標始終為0,
 * 改成在onWindowFocusChanged函數中獲取即可,這時view都已經加載完成
 * 但這里特別注意一點要:如果是fragment種使用該自定義view的話,這里的方法就應該注釋掉
 * 因為不但獲取到的矩形的值是空的,而且當你的fragment執行了跳轉的邏輯后,再返回后會發
 * 一種特別惡心的異常,你獲取到判斷選中位置的矩形的left,top,right,bottom的值會和
 * 初始化的時候不一樣,導致你選中時候的狀態出現異常情況,本人已經被坑過,希望后面的同學
 * 一定注意吸取教訓
 */
 @Override
 public void onWindowFocusChanged(boolean hasWindowFocus) {
 super.onWindowFocusChanged(hasWindowFocus);

 getSelectIconReft();

 }
 //獲取選中icon位置的矩形范圍
 private void getSelectIconReft() {

 int [] location = new int [2];
 getLocationOnScreen(location);
 //計算出右側選中時圖標的位置
 if (is_right_select_icon){
 //選中的icon動態設置寬高為60,沒選中寬高55,這里60/2為選中按鈕的寬度或者高度的一半,即中心點
 select_icon_rect.left = location[0]+getWidth()-mCircleLineStrokeWidth/2-DensityUtil.dip2px(getContext(),40f)/2;
 select_icon_rect.top =(location[1]+getHeight()/2)-DensityUtil.dip2px(getContext(),40f)/2;
 select_icon_rect.right = location[0]+getWidth()-mCircleLineStrokeWidth/2+DensityUtil.dip2px(getContext(),40f)/2;
 select_icon_rect.bottom = (location[1]+getHeight()/2)+DensityUtil.dip2px(getContext(),40f)/2;
 }else {
 //計算出左側選中時圖標的位置
 //選中的icon動態設置寬高為60,沒選中寬高55,這里60/2為選中按鈕的寬度或者高度的一半,即中心點
 select_icon_rect.left = location[0]+mCircleLineStrokeWidth/2-DensityUtil.dip2px(getContext(),40f)/2;
 select_icon_rect.top = (location[1]+getHeight()/2)-DensityUtil.dip2px(getContext(),40f)/2;
 select_icon_rect.right = location[0]+mCircleLineStrokeWidth/2+DensityUtil.dip2px(getContext(),40f)/2;
 select_icon_rect.bottom = (location[1]+getHeight()/2)+DensityUtil.dip2px(getContext(),40f)/2;
 }
 Log.d("onFocusChanged","-----getHeight=="+getChildAt(0).getHeight()+";getWidth=="+getChildAt(0).getWidth());
 }


 /**
 * 通過角度判斷象限
 */
 private int getQuadrantByAngle(int angle) {
 if (angle <= 90) {
 return 4;
 } else if (angle <= 180) {
 return 3;
 } else if (angle <= 270) {
 return 2;
 } else {
 return 1;
 }
 }

 /**
 * 慣性滾動
 */
 private class ScrollResetRunnable implements Runnable {

 private float angelPerSecond;

 public ScrollResetRunnable(float velocity) {
 this.angelPerSecond = velocity;
 }

 public void run() {
 //小于20停止
 if ((int) Math.abs(angelPerSecond) < 20) {
 isMove = false;
 return;
 }
 isMove = true;
 // 滾動時候不斷修改滾動角度大小
// mStartAngle += (angelPerSecond / 30);
 mStartAngle += (angelPerSecond / 40);
 //逐漸減小這個值
 angelPerSecond /= 1.0666F;
 postDelayed(this, 30);
 // 重新布局
 getCheck();
 }
 }


 /**
 * 點擊事件接口
 */
 public interface OnLogoItemClick {
 void onItemClick(View view, int pos);
 }

 private OnLogoItemClick mOnLogoItemClick;
 private OnIconSelectedListener mOnIconSelectedListener;

 /**
 * 設置點擊事件
 * @param mOnLogoItemClick
 */
 public void addOnItemClick(OnLogoItemClick mOnLogoItemClick) {
 this.mOnLogoItemClick = mOnLogoItemClick;
 }

 /**
 * 到選中位置后選中事件接口
 */
 public interface OnIconSelectedListener{
 void onIconSelected( int pos);
 }

 /**
 * 設置點擊事件
 * @param mOnIconSelectedListener
 */
 public void addOnIconSelectedListener(OnIconSelectedListener mOnIconSelectedListener) {
 this.mOnIconSelectedListener = mOnIconSelectedListener;
 }
 /**
 * 旋轉圓盤
 */
 private void getCheck() {
 mStartAngle %= 360;
 setRotation(mStartAngle);
 //改變選中的icon的狀態
 setSelectedIcon();

 }

 //改變選中的icon的狀態
 private void setSelectedIcon() {
 if (select_icon_rect.left==0&&select_icon_rect.top==0){
 //fragment中onWindowFocusChanged會出現計算select_icon_rect.left和select_icon_rect.top等于0的情況,
 // 所以做下判斷,如果為0則重新調用下計算方法
 getSelectIconReft();
 }
 for (int j =0;j<getChildCount();j++){
 LayoutParams layoutParams = null;
 int [] location = new int [2];
 getChildAt(j).getLocationOnScreen(location);
 Log.d("getCheck","location[0]=="+location[0]+";select_icon_rect.left=="+select_icon_rect.left+"location[1]=="+location[1]+";select_icon_rect.top=="+select_icon_rect.top);
 if (is_right_select_icon){
 //右邊icon是選中狀態的時候
 if (select_icon_rect.left-22<=location[0]&&location[0]<=select_icon_rect.right+22){
  if (select_icon_rect.top-22<=location[1]&&location[1]<=select_icon_rect.bottom+22){
  getChildAt(j).setAlpha(1);
  layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
  //把選中的icon所在list中的position通過接口回傳過去
  if (mOnIconSelectedListener!=null){
  mOnIconSelectedListener.onIconSelected(j);
  }
  }else {
  getChildAt(j).setAlpha(0.5f);
  layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
  }
 }else {
  getChildAt(j).setAlpha(0.5f);
  layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
 }

 }else {
 //左邊icon是選中狀態的時候
 if (select_icon_rect.left-22<=location[0]&&location[0]<=select_icon_rect.right+22){
  if (select_icon_rect.top-22<=location[1]&&location[1]<=select_icon_rect.bottom+22){
  getChildAt(j).setAlpha(1);
  layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
  //把選中的icon所在list中的position通過接口回傳過去
  if (mOnIconSelectedListener!=null){
  mOnIconSelectedListener.onIconSelected(j);

  }
  }else {
  getChildAt(j).setAlpha(0.5f);
  layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
  }
 }else {
  getChildAt(j).setAlpha(0.5f);
  layoutParams = new LayoutParams(DensityUtil.dip2px(getContext(),40f), DensityUtil.dip2px(getContext(),40f));
 }
 }
 getChildAt(j).setLayoutParams(layoutParams);
 getChildAt(j).invalidate();
 Log.d("getChildCount","=="+j+";class=="+getChildAt(j).getClass()+";left=="+getChildAt(j).getLeft()+";top=="+getChildAt(j).getTop()+";right=="+getChildAt(j).getRight()+";bottom=="+getChildAt(j).getBottom()+";getLocationOnScreen:x="+location[0]+"y="+location[1]+";getRotationX=="+getRotationX()+";getRotationY=="+getRotationY());
 }
 }

}

然后就是你在activity中根據回調方法獲取選中的對象:
//左右側方法相同,這里列出左側圓盤獲取方法:

view.ringView_half_left.addOnIconSelectedListener { position ->
 // ToDo 根據postion從你的list中獲取對應的選中的對象的bean類屬性即可

 }

最后貼下布局文件:

<RelativeLayout
 android:layout_width="match_parent"
 android:layout_height="match_parent">



 <RelativeLayout
 android:id="@+id/ring_left_outside_rl"
 android:layout_width="@dimen/dp_350"
 android:layout_height="@dimen/dp_350"
 android:layout_alignParentLeft="true"
 android:layout_marginLeft="-240dp">

 <com.wj.views.RingViewHalf
  android:id="@+id/ringView_half_left"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="@drawable/bg_compatibility"
  app:image_angle_rh="15"
  app:image_padding_rh="20"
  app:is_right_select_icon_rh="true"
  app:list_rh="@array/zodiac_list" />

 <ImageView
  android:layout_width="70dp"
  android:layout_height="70dp"
  android:layout_alignParentLeft="true"
  android:layout_centerVertical="true"
  android:layout_marginLeft="@dimen/dp_220"
  android:src="@drawable/icon_match_boy" />


 </RelativeLayout>

 <RelativeLayout
 android:id="@+id/ring_right_outside_rl"
 android:layout_width="@dimen/dp_350"
 android:layout_height="@dimen/dp_350"
 android:layout_alignParentRight="true"
 android:layout_marginRight="-240dp">

 <com.wj.views.RingViewHalf
  android:id="@+id/ringView_half_right"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:layout_alignParentRight="true"
  android:layout_centerVertical="true"
  android:background="@drawable/bg_compatibility"
  app:image_angle_rh="15"
  app:image_padding_rh="20"
  app:is_right_select_icon_rh="false"
  app:list_rh="@array/zodiac_list" />

 <ImageView
  android:layout_width="70dp"
  android:layout_height="70dp"
  android:layout_alignParentRight="true"
  android:layout_centerVertical="true"
  android:layout_marginRight="@dimen/dp_220"
  android:src="@drawable/icon_match_girl" />

 </RelativeLayout>

 <Button
 android:id="@+id/check_btn"
 android:layout_width="@dimen/dp_265"
 android:layout_height="@dimen/dp_46"
 android:layout_alignParentBottom="true"
 android:layout_marginBottom="@dimen/dp_25"
 android:layout_marginTop="@dimen/dp_25"
 android:layout_centerHorizontal="true"
 android:alpha="0.5"
 android:enabled="true"
 android:clickable="true"
 android:background="@drawable/check" />

</RelativeLayout>

//這里是放半圓形轉盤選擇器上顯示的圖片list,我這里是用的xml靜態傳進去的,也可以改為動態方式傳遞

app:list_rh="@array/zodiac_list"

然后在values下面創建一個arrays.xml文件

<?xml version="1.0" encoding="utf-8"?>
<resources>

 <string-array name="zodiac_list">
 <item>@drawable/zodiac_1</item>
 <item>@drawable/zodiac_2</item>
 <item>@drawable/zodiac_3</item>
 <item>@drawable/zodiac_4</item>
 <item>@drawable/zodiac_5</item>
 <item>@drawable/zodiac_6</item>
 <item>@drawable/zodiac_7</item>
 <item>@drawable/zodiac_8</item>
 <item>@drawable/zodiac_9</item>
 <item>@drawable/zodiac_10</item>
 <item>@drawable/zodiac_11</item>
 <item>@drawable/zodiac_12</item>
 </string-array>
</resources>

關于如何在Android中自定義半圓形圓盤滾動選擇器問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

从化市| 永州市| 电白县| 大安市| 理塘县| 宜川县| 山东省| 吴桥县| 河源市| 阳高县| 阆中市| 阿合奇县| 阳西县| 历史| 新余市| 始兴县| 南郑县| 塔河县| 隆回县| 泾阳县| 千阳县| 通州区| 梁平县| 轮台县| 达日县| 织金县| 合山市| 滕州市| 祁连县| 巨鹿县| 临汾市| 股票| 乐山市| 保靖县| 辉南县| 星座| 建阳市| 浦县| 灌南县| 西乌| 随州市|