使用 Android Studio 创建自定义视图
Posted
技术标签:
【中文标题】使用 Android Studio 创建自定义视图【英文标题】:Create a custom view with Android Studio 【发布时间】:2020-08-20 11:01:07 【问题描述】:我正在尝试在 android Studio 中创建一个可以将其从右向左拖动的小视图。此视图将有 2 个按钮。
当你选择其中一个或按下它的外部时,小菜单将再次隐藏。
我一直在搜索,但没有任何类似的库。我也不知道该怎么做。
我可以在单独的视图(布局 xml)中绘制小视图,但我不知道如何添加它并创建要通过拖动打开或关闭的事件。
我该怎么做?
谢谢。
【问题讨论】:
你尝试NavigationView
组件吗?
不完全是,视图更小并且水平包含图标。虽然它的行为相似,因为它是从一侧拖动并且在向外按下时必须关闭
我认为您可以更改navigationView
的大小,然后在其中定义一个relativeLayout
,它包含两个button
。
你试过我的答案了吗?
这是个好主意,我尝试了@Lakindu 的想法。谢谢。
【参考方案1】:
这是创建自定义可拖动抽屉的基本示例。
这些是我看过的参考资料。
为了检测拖动/投掷手势,我使用了 GestureDetectorCompat,并且 我指的是:https://developer.android.com/training/gestures/detector
要创建抽屉打开和关闭动画我提到:https://youtu.be/OHcfs6rStRo
请注意,这是一个非常基本的示例。 您可以以此为基础来创建您的最终目标。 您将不得不过滤掉您收到的不需要的拖拽/甩动回调。 你将不得不忽略你会在抽屉上得到的水龙头。
这是实现。
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.view.GestureDetectorCompat;
import android.os.Bundle;
import android.transition.TransitionManager;
import android.view.GestureDetector;
import android.view.MotionEvent;
public class MainActivity extends AppCompatActivity
private boolean mIsDrawerOpened;
private ConstraintLayout mRootConstraintLayout;
private final ConstraintSet mDrawerClosedConstraintSet = new ConstraintSet();
private final ConstraintSet mDrawerOpenedConstraintSet = new ConstraintSet();
private GestureDetectorCompat mGestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_drawer_closed);
// Drawer is initially closed
mIsDrawerOpened = false;
mRootConstraintLayout = findViewById(R.id.rootConstraintLayout);
mDrawerClosedConstraintSet.clone(this, R.layout.activity_main_drawer_closed);
mDrawerOpenedConstraintSet.clone(this, R.layout.activity_main_drawer_opened);
mGestureDetector = new GestureDetectorCompat(
getApplicationContext(),
new GestureDetector.SimpleOnGestureListener()
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
// Drag / Fling gesture detected
// TODO: Recongnize unwanted drag / fling gestures and ignore them.
TransitionManager.beginDelayedTransition(mRootConstraintLayout);
// Drawer is closed?
if(!mIsDrawerOpened)
// Open the drawer
mDrawerOpenedConstraintSet.applyTo(mRootConstraintLayout);
mIsDrawerOpened = true;
return true;
@Override
public boolean onSingleTapUp(MotionEvent e)
// Single tap detected
// TODO: If user has tapped on the drawer, do not close it.
TransitionManager.beginDelayedTransition(mRootConstraintLayout);
// Drawer is opened?
if(mIsDrawerOpened)
// Close the drawer
mDrawerClosedConstraintSet.applyTo(mRootConstraintLayout);
mIsDrawerOpened = false;
return true;
@Override
public boolean onDown(MotionEvent e)
return true;
);
@Override
public boolean onTouchEvent(MotionEvent event)
mGestureDetector.onTouchEvent(event);
return super.onTouchEvent(event);
res/layout/activity_main_drawer_closed.xml
<ConstraintLayout
android:id="@+id/rootConstraintLayout"
android:clipChildren="false" >
<ConstraintLayout
android:id="@+id/drawerConstraintLayout"
android:layout_
android:layout_
android:background="@color/colorPrimaryDark"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="parent" >
<Button
android:id="@+id/button1"
android:layout_
android:layout_
android:text="1"
android:backgroundTint="@color/colorAccent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/button2" />
<Button
android:id="@+id/button2"
android:layout_
android:layout_
android:text="2"
android:backgroundTint="@color/colorAccent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/button1"
app:layout_constraintEnd_toEndOf="parent" />
</ConstraintLayout>
<ImageView
android:id="@+id/notch"
android:layout_
android:layout_
android:src="@drawable/drawer_notch"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/drawerConstraintLayout" />
</ConstraintLayout>
res/layout/activity_main_drawer_opened.xml
<ConstraintLayout
android:id="@+id/rootConstraintLayout" >
<ConstraintLayout
android:id="@+id/drawerConstraintLayout"
android:layout_
android:layout_
android:background="@color/colorPrimaryDark"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" >
<Button
android:id="@+id/button1"
android:layout_
android:layout_
android:text="1"
android:backgroundTint="@color/colorAccent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/button2" />
<Button
android:id="@+id/button2"
android:layout_
android:layout_
android:text="2"
android:backgroundTint="@color/colorAccent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/button1"
app:layout_constraintEnd_toEndOf="parent" />
</ConstraintLayout>
<ImageView
android:id="@+id/notch"
android:layout_
android:layout_
android:src="@drawable/drawer_notch"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/drawerConstraintLayout" />
</ConstraintLayout>
res/drawable/drawer_notch.xml
<shape
android:shape="rectangle">
<corners android:radius="4dp" />
<solid android:color="@color/colorAccent" />
</shape>
app/build.gradle
android
defaultConfig
minSdkVersion 19
.
.
.
.
.
.
结果:
【讨论】:
非常好,它对我来说工作正常。您只需指出必须将以下内容添加到 Main_Activity.xml:<include layout="@layout/activity_main_drawer_closed" />
。谢谢@Lakindu
我很高兴它对你有用。在此示例中,用于MainActivity
的布局资源为activity_main_drawer_closed.xml
。您可以在onCreate
方法中看到它。这里没有main_activity.xml
。是的,如果你愿意,你可以有一个main_activity.xml
并在其中包含activity_main_drawer_closed
布局。
嗨@Lakindu,我在使用旧的 Android 版本时遇到了问题(例如,版本 21)。抽屉打开布局不显示,只有缺口。你能模仿它看看发生了什么吗?谢谢。
@KrmX,是的,你是对的。当我在 Android L 模拟器上运行它时,我可以看到这一点。 TransitionManager
API 在 API 级别 14 中可用。因此,动画也应该在级别 21 中工作。我会调查并尝试为您提供解决方案。
@KrmX,您可以找到解决方案here 来解决问题。我在 API 级别 29 和 19 上对其进行了测试,并在两个平台上都获得了预期的行为。我编辑此答案以包含该修复程序。【参考方案2】:
首先在你的Gradle
中添加android material
依赖:
implementation 'com.google.android.material:material:1.1.0'
然后你可以像这样使用NavigationView
组件:
<com.google.android.material.navigation.NavigationView
android:id="@+id/navi_view"
android:layout_
android:layout_
android:background="@color/colorPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">
<Button
android:id="@+id/btn1"
android:layout_
android:layout_
android:text="btn1" />
<Button
android:id="@+id/btn2"
android:layout_
android:layout_
android:layout_gravity="end"
android:text="btn2" />
</com.google.android.material.navigation.NavigationView>
这是一个非常简单的例子,没有约定,你应该改进它。
【讨论】:
以上是关于使用 Android Studio 创建自定义视图的主要内容,如果未能解决你的问题,请参考以下文章
如何正确连接并显示从 Firebase 到自定义列表视图 Android Studio 的数据
Android Studio,如何使用数组或光标中的数据填充自定义 ListView?