




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】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
提交评论