【移动应用开发技术】Android中怎么自定义一个底部上拉控件_第1页
【移动应用开发技术】Android中怎么自定义一个底部上拉控件_第2页
【移动应用开发技术】Android中怎么自定义一个底部上拉控件_第3页
【移动应用开发技术】Android中怎么自定义一个底部上拉控件_第4页
【移动应用开发技术】Android中怎么自定义一个底部上拉控件_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

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

文档简介

【移动应用开发技术】Android中怎么自定义一个底部上拉控件

Android中怎么自定义一个底部上拉控件,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1.在Project的build.gradle文件中添加:allprojects

{

repositories

{

...

maven

{

url

'https://jitpack.io'

}

}

}2.在Module的build.gradle文件中添加:dependencies

{

compile

'com.github.qingmei2:SlideBottomLayout-Android:1.2.3'

}3.Addviewinyourlayout:需要注意的是:为了简单实现,笔者偷了个懒,设定为该布局下只能有一个直接的子View(类似ScrollView)因此如果您添加需要一个布局,请在外面嵌套一个ViewGroup:<com.qingmei2.library.SlideBottomLayout

android:id="@+id/slideLayout"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_alignParentBottom="true"

android:layout_marginTop="200dp"

app:handler_height="50dp">

<!--app:handler_height:该属性就是您要暴露出来Handle的高度,详见下方的TextView(id=handle)-->

<!--Just

one

child-->

<LinearLayout

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="vertical">

<TextView

android:id="@+id/handle"

android:layout_width="match_parent"

android:layout_height="50dp"

android:background="#d95858"

android:gravity="center"

android:text="handle"

android:textColor="@android:color/white"

android:textSize="16sp"

/>

<android.support.v7.widget.RecyclerView

android:id="@+id/recycler_view"

android:layout_width="match_parent"

android:layout_height="wrap_content">

</android.support.v7.widget.RecyclerView>

</LinearLayout>

</com.qingmei2.library.SlideBottomLayout>实现步骤具体代码如下,其中上述需求的设置方式都已经在代码中声明:先看下属性声明:<?xml

version="1.0"

encoding="utf-8"?>

<resources>

<declare-styleable

name="SlideBottomLayout">

<attr

name="handler_height"

format="dimension"></attr>

</declare-styleable>

</resources>public

class

SlideBottomLayout

extends

LinearLayout

{

public

void

setShortSlideListener(ShortSlideListener

listener)

{

this.shortSlideListener

=

listener;

}

private

ShortSlideListener

shortSlideListener;

/**

*

The

{@link

MotionEvent#ACTION_DOWN}

gesture

location.

*/

private

int

downY;

/**

*

The

{@link

MotionEvent#ACTION_MOVE}

gesture

location.

*/

private

int

moveY;

/**

*

the

value

of

moved

distance

by

the

gesture.

When

the

value

was

modified

and

not

exceed

*

the

{@link

#movedMaxDis},

then

make

this

ViewGroup

move.

*/

private

int

movedDis;

/**

*

The

max

distance

that

the

{@link

SlideBottomLayout}

can

scroll

to,

it

used

to

compare

with

the

*

{@link

#downY},

determine

whether

it

can

slide

by

the

gesture.

*/

private

int

movedMaxDis;

/**

*

ChildView

of

the

{@link

SlideBottomLayout},

you

can

set

a

Layout

such

as

the

{@link

LinearLayout}、

*

{@link

android.widget.RelativeLayout}

ect.

*

We

set

the

rules

that

{@link

SlideBottomLayout}

just

can

have

one

child-view,

or

else

get

a

*

{@link

RuntimeException}

at

{@link

#onFinishInflate()}

*/

private

View

childView;

/**

*

The

control

{@link

SlideBottomLayout}

automatically

switches

the

threshold

of

the

state.

if

*

this

ViewGroup

moved

distance

more

than

{@link

#movedMaxDis}

*

it,

switch

the

state

of

*

{@link

#arriveTop}

right

now.

*

</p>

*

See

the

{@link

#touchActionUp(float)}.

*/

private

float

hideWeight

=

0.25f;

//3.注意,这个接口用来设置「需要自定义自动到达顶部/隐藏的阈值」

public

void

setHideWeight(float

hideWeight)

{

if

(hideWeight

<=

0

||

hideWeight

>

1)

throw

new

IllegalArgumentException("hideWeight

should

belong

(0f,1f]");

this.hideWeight

=

hideWeight;

}

private

Scroller

mScroller;

/**

*

It

means

the

{@link

#childView}

is

arriving

the

top

of

parent

or

else.

*/

private

boolean

arriveTop

=

false;

/**

*

the

{@link

#childView}

Initially

visible

height

*/

private

float

visibilityHeight;

//1.初始化Handle显示高度,建议您在xml中设置对应属性来实现该效果

public

void

setVisibilityHeight(float

visibilityHeight)

{

this.visibilityHeight

=

visibilityHeight;

}

public

SlideBottomLayout(@NonNull

Context

context)

{

super(context);

}

public

SlideBottomLayout(@NonNull

Context

context,

@Nullable

AttributeSet

attrs)

{

super(context,

attrs);

initAttrs(context,

attrs);

}

public

SlideBottomLayout(@NonNull

Context

context,

@Nullable

AttributeSet

attrs,

int

defStyleAttr)

{

super(context,

attrs,

defStyleAttr);

initAttrs(context,

attrs);

}

/**

*

Get

the

config

from

{@link

R.styleable},

then

init

other

configrations{@link

#initConfig(Context)}.

*

*

@param

context

the

{@link

Context}

*

@param

attrs

the

configs

in

layout

attrs.

*/

private

void

initAttrs(Context

context,

AttributeSet

attrs)

{

final

TypedArray

ta

=

context.obtainStyledAttributes(attrs,

R.styleable.SlideBottomLayout);

visibilityHeight

=

ta.getDimension(R.styleable.SlideBottomLayout_handler_height,

0);

ta.recycle();

initConfig(context);

}

private

void

initConfig(Context

context)

{

if

(mScroller

==

null)

mScroller

=

new

Scroller(context);

this.setBackgroundColor(Color.TRANSPARENT);

}

/**

*

It

start

a

judgement

for

ensure

the

child-view

be

unique

in

this

method,then

assgin

it

*

to

{{@link

#childView}.

*

this

method

will

be

called

before

the

{@link

#onMeasure(int,

int)}

*/

@Override

protected

void

onFinishInflate()

{

super.onFinishInflate();

if

(getChildCount()

==

0

||

getChildAt(0)

==

null)

{

throw

new

RuntimeException("there

have

no

child-View

in

the

SlideBottomLayout!");

}

if

(getChildCount()

>

1)

{

throw

new

RuntimeException("there

just

alow

one

child-View

in

the

SlideBottomLayout!");

}

childView

=

getChildAt(0);

}

@Override

protected

void

onMeasure(int

widthMeasureSpec,

int

heightMeasureSpec)

{

super.onMeasure(widthMeasureSpec,

heightMeasureSpec);

movedMaxDis

=

(int)

(childView.getMeasuredHeight()

-

visibilityHeight);

}

@Override

protected

void

onLayout(boolean

changed,

int

l,

int

t,

int

r,

int

b)

{

super.onLayout(changed,

l,

t,

r,

b);

childView.layout(0,

movedMaxDis,

childView.getMeasuredWidth(),

childView.getMeasuredHeight()

+

movedMaxDis);

}

@Override

public

boolean

onTouchEvent(MotionEvent

event)

{

final

float

dy

=

event.getY();

switch

(event.getAction())

{

case

MotionEvent.ACTION_DOWN:

if

(touchActionDown(dy))

return

true;

break;

case

MotionEvent.ACTION_MOVE:

if

(touchActionMove(dy))

return

true;

break;

case

MotionEvent.ACTION_UP:

if

(touchActionUp(dy))

return

true;

break;

}

return

super.onTouchEvent(event);

}

@Override

public

void

computeScroll()

{

puteScroll();

if

(mScroller

==

null)

mScroller

=

new

Scroller(getContext());

if

(mSputeScrollOffset())

{

scrollTo(0,

mScroller.getCurrY());

postInvalidate();

}

}

/**

*

When

the

touch

event

is

{@link

MotionEvent#ACTION_UP},

*

then

judge

the

state

of

view

group

and

control

the

{@link

Scroller}

to

scroll.

*

<p>

*

In

this

ViewGroup,

we

set

the

rules

that

is

if

this

scroll

gesture's

move

distance

*

more

than

{@link

#movedMaxDis}

*

{@link

#hideWeight}(default

hideWeight

value

is

1/4

heights

*

of

this

ViewGroup),

then

call

{@link

#hide()}

or

{@link

#show()}

right

now.

which

method

will

*

be

call

depends

on

{@link

#arriveTop}.

*

<p

*

if

the

scroll

gesture's

move

distance

don't

reach

the

goal

value,

then

call

the

*

{@link

ShortSlideListener#onShortSlide(float)}

if

you

call

{@link

#setShortSlideListener(ShortSlideListener)}

*

init

this

ViewGroup.

else

will

call

{@link

#hide()}.

*

*

@param

eventY

The

location

of

trigger

*

@return

Be

used

to

determine

consume

this

event

or

else.

*/

public

boolean

touchActionUp(float

eventY)

{

if

(movedDis

>

movedMaxDis

*

hideWeight)

{

switchVisible();

}

else

{

if

(shortSlideListener

!=

null)

{

shortSlideListener.onShortSlide(eventY);

}

else

{

hide();

}

}

return

true;

}

/**

*

When

the

touch

event

is

{@link

MotionEvent#ACTION_MOVE},

*

then

judge

the

state

of

view

group

and

control

the

{@link

Scroller}

to

scroll.

*

<p>

*

In

this

ViewGroup,

we

set

the

rules

that

is

if

this

scroll

gesture's

move

distance

*

more

than

{@link

#movedMaxDis}

*

{@link

#hideWeight}(default

hideWeight

value

is

1/4

heights

of

this

ViewGroup),

*

then

call

{@link

#hide()}

or

{@link

#show()}

right

now.

*

<p>

*

*

@param

eventY

The

location

of

trigger

*

@return

Be

used

to

determine

consume

this

event

or

else.

*/

public

boolean

touchActionMove(float

eventY)

{

moveY

=

(int)

eventY;

//the

dy

is

sum

of

the

move

distance,

the

value

>

0

means

scroll

up,

the

value

<

0

means

scroll

down.

final

int

dy

=

downY

-

moveY;

if

(dy

>

0)

{

//scroll

up

movedDis

+=

dy;

if

(movedDis

>

movedMaxDis)

movedDis

=

movedMaxDis;

if

(movedDis

<

movedMaxDis)

{

scrollBy(0,

dy);

downY

=

moveY;

return

true;

}

}

else

{

//scroll

down

movedDis

+=

dy;

if

(movedDis

<

0)

movedDis

=

0;

if

(movedDis

>

0)

{

scrollBy(0,

dy);

}

downY

=

moveY;

return

true;

}

return

false;

}

/**

*

When

the

touch

event

is

{@link

MotionEvent#ACTION_DOWN},

*

Record

the

location

of

this

action.

*

*

@param

eventY

The

location

of

trigger

*

@return

Be

used

to

determine

consume

this

event

or

else.

*/

public

boolean

touchA

温馨提示

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

评论

0/150

提交评论