【移动应用开发技术】如何在Android中自定义半圆形圆盘滚动选择器_第1页
【移动应用开发技术】如何在Android中自定义半圆形圆盘滚动选择器_第2页
【移动应用开发技术】如何在Android中自定义半圆形圆盘滚动选择器_第3页
【移动应用开发技术】如何在Android中自定义半圆形圆盘滚动选择器_第4页
【移动应用开发技术】如何在Android中自定义半圆形圆盘滚动选择器_第5页
已阅读5页,还剩19页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

【移动应用开发技术】如何在Android中自定义半圆形圆盘滚动选择器

如何在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@

*

@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"

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论