还在担心Android功能不会用吗?Intro Showcase View助你快速实现功能引导

科技   2024-08-15 07:01   浙江  

还在担心Android功能不会用吗?Intro Showcase View助你快速实现功能引导

1. 引言

在现代应用开发中,如何有效引导用户快速上手并掌握应用的核心功能,是提升用户体验的重要一环。功能引导不仅帮助用户理解复杂功能,还能提高用户留存率,减少因操作复杂度带来的用户流失。随着 Android 平台的不断发展,功能引导的实现方式也在不断演进。本文将深入探讨如何在 Android 开发中实现高效的功能引导,特别是在传统 View 系统与 Jetpack Compose 环境中的实现。

2. 功能引导的设计原则

功能引导的设计需要遵循一定的规范和原则,以确保用户能够快速理解并掌握应用的关键功能。根据 Material Design 的设计规范,引导设计应注重以下几个方面:

  • • 可见性:引导内容应足够突出,避免被用户忽略。通过颜色、动画等方式增强其视觉吸引力。

  • • 简洁性:信息传达要简洁明了,避免过多的文字说明,用户能够一眼理解。

  • • 互动性:引导应与用户的操作相关联,提供即时的反馈,增强用户的参与感。

了解用户心理,特别是在首次使用应用时的心理状态,有助于设计更具吸引力和有效的引导流程。

3. 功能引导的技术实现

使用传统 View 系统实现功能引导

在传统 Android 开发中,MaterialTapTargetPrompt 是一个广泛使用的库,旨在帮助开发者实现基于 Material Design 的功能引导。以下是如何使用该库的详细步骤:

  • • 依赖导入:首先,在 build.gradle 文件中添加库的依赖:

    dependencies {
        implementation 'uk.co.samuelwall:material-tap-target-prompt:3.3.2'
    }
  • • 基本实现:通过以下代码,快速实现一个功能引导,该引导会在 FloatingActionButton 上显示一个提示:

    MaterialTapTargetPrompt.Builder(this)
        .setTarget(R.id.fab)
        .setPrimaryText("发送你的第一封邮件")
        .setSecondaryText("点击信封图标开始撰写你的第一封邮件")
        .setPromptStateChangeListener { prompt, state ->
            if (state == MaterialTapTargetPrompt.STATE_FOCAL_PRESSED) {
                // 用户已点击引导目标
            }
        }
        .show()
  • • 状态变化处理:通过 setPromptStateChangeListener,你可以监控引导的状态变化,并根据用户操作执行相应的逻辑。

Example

以下示例展示了在不同场景下如何使用该库进行功能引导:

1. 简单的视图目标引导

最基本的功能引导只需要指定目标视图(通过 ID 或 View 对象)和引导文本。

通过 ID 设置目标视图:

MaterialTapTargetPrompt.Builder(this)
    .setTarget(R.id.fab)
    .setPrimaryText("发送你的第一封邮件")
    .show()

通过 View 对象设置目标视图:

MaterialTapTargetPrompt.Builder(this)
    .setTarget(findViewById(R.id.fab))
    .setPrimaryText("发送你的第一封邮件")
    .show()

2. 引导 App Bar 中的菜单项

对于在 App Bar 中显示的菜单项,可以通过其 ID 进行目标设置。

菜单 XML 示例:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/action_search"
        android:icon="@drawable/ic_search"
        android:title="搜索"
        app:showAsAction="always" />

</menu>

引导菜单项:

MaterialTapTargetPrompt.Builder(this)
    .setTarget(R.id.action_search)
    .setPrimaryText("点击这里开始搜索")
    .setIcon(R.drawable.ic_search)
    .show()

3. RecyclerView 中的卡片引导

在 RecyclerView 中,你可以针对卡片或列表项的特定子视图设置引导目标。

获取卡片视图:

val card = mLinearLayoutManager.findViewByPosition(0as LinearLayout

获取 ViewHolder 并设置引导:

if (card != null) {
    val viewHolder = mRecyclerView.getChildViewHolder(card) as CardAdapter.ViewHolder
    MaterialTapTargetPrompt.Builder(this)
        .setTarget(viewHolder.mImageView)
        .setClipToView(card.getChildAt(0))
        .setPrimaryText("这是一张卡片")
        .setSecondaryText("点击图片查看更多内容")
        .show()
}

4. 定位在屏幕中央的引导

当目标视图距离屏幕边缘超过 88dp 时,引导提示会自动调整位置,以不覆盖目标视图。

MaterialTapTargetPrompt.Builder(this)
    .setTarget(targetView)
    .setPrimaryText("中心位置的引导")
    .show()

5. 自定义文本样式

你可以使用 SpannableStringBuilder 自定义引导文本的样式,如改变文本颜色、背景等。

自定义主文本样式:

val primaryText = SpannableStringBuilder("发送你的第一封邮件")
val backgroundColour = BackgroundColorSpan(ContextCompat.getColor(this, R.color.colorAccent))
primaryText.setSpan(backgroundColour, 04, Spanned.SPAN_INCLUSIVE_INCLUSIVE)

自定义次文本样式:

val secondaryText = SpannableStringBuilder("点击信封图标开始撰写你的第一封邮件")
val foregroundColour = ForegroundColorSpan(ContextCompat.getColor(this, R.color.colorAccent))
secondaryText.setSpan(foregroundColour, 815, Spanned.SPAN_INCLUSIVE_INCLUSIVE)

应用自定义文本样式:

MaterialTapTargetPrompt.Builder(this)
    .setTarget(targetView)
    .setPrimaryText(primaryText)
    .setSecondaryText(secondaryText)
    .show()

通过上述示例,你可以灵活地在 Android 应用中实现不同场景下的功能引导,从简单的视图引导到复杂的 RecyclerView 卡片引导,再到自定义文本样式,这些都能极大地提升用户体验。

在 Jetpack Compose 中实现功能引导

随着 Android 开发逐渐向 Jetpack Compose 过渡,功能引导的实现也需要适应新的 UI 框架。intro-showcase-view 是一个专门为 Compose 设计的引导库,支持流畅的 Compose 风格的引导实现。

  • • 选择 Jetpack Compose 的原因:Jetpack Compose 提供了更灵活、更强大的 UI 构建方式,使引导的设计和实现更加直观和高效。

  • • 基于 intro-showcase-view 的实现:通过 intro-showcase-view,你可以快速创建一个引导,并与 Compose 组件无缝集成。

在 Jetpack Compose 中,IntroShowcaseView 是一个非常方便的库,它可以帮助你快速创建功能引导。以下是如何在 Compose 中使用该库的示例。

引入依赖

首先,在 build.gradle 文件中添加以下依赖:

implementation 'com.canopas.intro-showcase-view:introshowcaseview:<latest-version>'

示例代码

以下是一个使用 IntroShowcaseView 的完整示例,演示了如何在 Jetpack Compose 中创建一个功能引导:

@Composable
fun ShowcaseSample() {
    var showAppIntro by remember {
        mutableStateOf(true)
    }

    IntroShowcase(
        showIntroShowCase = showAppIntro,
        dismissOnClickOutside = false,
        onShowCaseCompleted = {
            // App Intro 完成后执行的操作
            showAppIntro = false
        },
    ) {
        FloatingActionButton(
            onClick = {},
            modifier = Modifier.introShowCaseTarget(
                index = 0,
                style = ShowcaseStyle.Default.copy(
                    backgroundColor = Color(0xFF1C0A00), // 背景颜色
                    backgroundAlpha = 0.98f// 背景透明度
                    targetCircleColor = Color.White // 目标圆圈的颜色
                ),
                content = {
                    Column {
                        Text(
                            text = "检查邮件",
                            color = Color.White,
                            fontSize = 24.sp,
                            fontWeight = FontWeight.Bold
                        )
                        Text(
                            text = "点击这里检查/发送邮件",
                            color = Color.White,
                            fontSize = 16.sp
                        )
                        Spacer(modifier = Modifier.height(10.dp))
                        Icon(
                            painterResource(id = R.drawable.right_arrow),
                            contentDescription = null,
                            modifier = Modifier
                                .size(80.dp)
                                .align(Alignment.End),
                            tint = Color.White
                        )
                    }
                }
            ),
            backgroundColor = ThemeColor,
            contentColor = Color.White,
            elevation = FloatingActionButtonDefaults.elevation(6.dp)
        ) {
            Icon(
                Icons.Filled.Email,
                contentDescription = "Email"
            )
        }
    }
}

功能说明

  • • IntroShowcase 是库中提供的主要组件,用于包裹需要引导的内容。

  • • introShowCaseTarget 是扩展函数,用于设置引导的目标视图、样式和内容。

  • • ShowcaseStyle 可以用于自定义引导的样式,例如背景颜色、透明度和目标圈颜色。

通过 IntroShowcaseView,在 Jetpack Compose 中实现功能引导变得非常简单。这种方式不仅简化了开发流程,还为用户提供了直观的操作提示,提升了用户体验。示例代码:https://github.com/canopas/compose-intro-showcase/tree/master/app

4. 自定义与高级应用

在许多情况下,默认的引导形式可能无法满足需求。此时,可以通过自定义来实现更复杂的引导场景。

  • • 自定义形状与动画MaterialTapTargetPrompt 提供了扩展接口,可以自定义引导的形状(如矩形、椭圆)和动画效果,使引导更符合应用的整体风格。

  • • 根据应用场景定制引导:例如,在引导多个步骤的复杂流程时,确保每一步都与用户操作密切相关,并通过视觉提示引导用户完成整个流程。

  • • 高级应用:在实现多步骤引导或处理复杂的用户场景时,可以结合条件判断、用户数据等实现更具针对性的引导体验。

在使用 MaterialTapTargetPrompt 库时,除了默认的功能外,你还可以通过自定义 BuilderShapesText 等组件,进一步增强功能引导的灵活性和可扩展性。以下内容将介绍如何进行这些自定义操作。

1. 自定义 Builder

MaterialTapTargetPrompt 中的默认 Builder 实现继承自 PromptOptions,而 PromptOptions 提供了创建点击目标的通用功能。你可以扩展 PromptOptions 来实现自定义功能。

例如,以下自定义 Builder 在引导显示时,会将指定的键值存储为 true 到 SharedPreferences,并且只有在该键值为 false 时才会显示引导提示。

class CustomTapTargetPromptBuilder(context: Context) :
    MaterialTapTargetPrompt.Builder(context) {

    private val sharedPreferences = context.getSharedPreferences("MyPrefs", Context.MODE_PRIVATE)

    fun setPreferenceKey(key: String): CustomTapTargetPromptBuilder {
        val shouldShow = sharedPreferences.getBoolean(key, false)
        if (!shouldShow) {
            this.setOnHidePromptListener {
                sharedPreferences.edit().putBoolean(key, true).apply()
            }
        } else {
            this.setPrimaryText("Prompt already shown")
        }
        return this
    }
}

使用自定义 Builder

CustomTapTargetPromptBuilder(this)
    .setTarget(R.id.fab)
    .setPrimaryText("点击这里开始")
    .setPreferenceKey("show_prompt_fab")
    .show()

2. 自定义形状(Shapes)

默认情况下,MaterialTapTargetPrompt 使用圆形作为引导形状。不过,你可以通过扩展 PromptBackground 和 PromptFocal 类,渲染任何其他形状。例如,使用矩形作为引导背景。

new MaterialTapTargetPrompt.Builder(this)
                .setTarget(view)
                .setPrimaryText("Different shapes")
                .setSecondaryText("Extend PromptFocal or PromptBackground to change the shapes")
                .setPromptBackground(new RectanglePromptBackground())
                .setPromptFocal(new RectanglePromptFocal())
                .show();

3. 自定义背景效果

可以通过设置 PromptBackground 来使背景变暗,从而突出引导目标。

builder.setPromptBackground(DimmedPromptBackground())
    .setPrimaryText("这是一个暗背景效果的引导")
    .show()
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.annotation.NonNull;
import android.util.DisplayMetrics;

import uk.co.samuelwall.materialtaptargetprompt.extras.PromptOptions;
import uk.co.samuelwall.materialtaptargetprompt.extras.backgrounds.CirclePromptBackground;

/**
 * Prompt background implementation that darkens behind the circle background.
 */

public class DimmedPromptBackground extends CirclePromptBackground
{
    @NonNull private RectF dimBounds = new RectF();
    @NonNull private Paint dimPaint;

    public DimmedPromptBackground()
    {
        dimPaint = new Paint();
        dimPaint.setColor(Color.BLACK);
    }

    @Override
    public void prepare(@NonNull final PromptOptions options, final boolean clipToBounds, @NonNull Rect clipBounds)
    {
        super.prepare(options, clipToBounds, clipBounds);
        DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
        // Set the bounds to display as dimmed to the screen bounds
        dimBounds.set(00, metrics.widthPixels, metrics.heightPixels);
    }

    @Override
    public void update(@NonNull final PromptOptions options, float revealModifier, float alphaModifier)
    {
        super.update(options, revealModifier, alphaModifier);
        // Allow for the dimmed background to fade in and out
        this.dimPaint.setAlpha((int) (200 * alphaModifier));
    }

    @Override
    public void draw(@NonNull Canvas canvas)
    {
        // Draw the dimmed background
        canvas.drawRect(this.dimBounds, this.dimPaint);
        // Draw the background
        super.draw(canvas);
    }
}

4. 自定义文本(Text)

MaterialTapTargetPrompt 中的文本由 PromptText 类渲染。大多数情况下,可以通过使用 SpannableStringBuilder 来实现文本内容和样式的更改。如果需要进一步自定义文本的布局和渲染方式,可以扩展 PromptText 类。

val primaryText = SpannableStringBuilder("发送你的第一封邮件")
primaryText.setSpan(
    BackgroundColorSpan(ContextCompat.getColor(this, R.color.colorAccent)),
    04, Spanned.SPAN_INCLUSIVE_INCLUSIVE
)

val secondaryText = SpannableStringBuilder("点击信封图标开始撰写邮件")
secondaryText.setSpan(
    ForegroundColorSpan(ContextCompat.getColor(this, R.color.colorAccent)),
    815, Spanned.SPAN_INCLUSIVE_INCLUSIVE
)

MaterialTapTargetPrompt.Builder(this)
    .setTarget(R.id.fab)
    .setPrimaryText(primaryText)
    .setSecondaryText(secondaryText)
    .show()

如果你需要更复杂的文本布局,可以扩展 PromptText 类,并通过 builder.setPromptText() 方法将自定义的文本处理类应用到引导中。

class CustomPromptText : PromptText() {
    override fun draw(canvas: Canvas, paint: Paint, clipBounds: Rect, focalBounds: Rect) {
        // 自定义文本绘制逻辑
    }
}

MaterialTapTargetPrompt.Builder(this)
    .setPromptText(CustomPromptText())
    .setPrimaryText("自定义文本布局")
    .show()

通过自定义 BuilderShapes 和 Text,你可以为 Android 应用的功能引导添加更丰富、更个性化的功能。这种灵活性使得 MaterialTapTargetPrompt 成为一个强大而易用的工具,能够满足各种应用场景的需求。

5. 性能优化与兼容性考虑

功能引导的性能优化和兼容性问题也是开发者需要关注的重点:

  • • 性能影响分析:在引导显示过程中,动画、资源加载等可能会对性能产生影响,特别是在低端设备上。通过优化资源、减少不必要的动画,可以提升引导的流畅性。

  • • 兼容性适配:由于 Android 设备和版本的多样性,在实现功能引导时需要考虑不同版本之间的兼容性问题,确保在所有目标设备上都能正常运行。

6. 结束语

功能引导是提升用户体验的重要手段,随着 Android 开发环境的不断变化,引导的实现方式也在不断演进。本文介绍了在传统 View 系统与 Jetpack Compose 中实现功能引导的方法,并探讨了自定义引导、性能优化与兼容性问题。希望通过这些实践,开发者能够在未来的项目中更好地实现功能引导,提升应用的用户体验。

在实现功能引导的过程中,开发者应始终关注用户的实际需求,通过不断优化和改进,使引导成为用户与应用之间更加顺畅的桥梁。


这篇博客旨在为 Android 开发者提供全面的功能引导实现指南,从设计原则到技术实现,从自定义应用到性能优化,帮助开发者更好地掌握并应用功能引导技术。

参考

https://github.com/sjwall/MaterialTapTargetPrompt

https://sjwall.github.io/MaterialTapTargetPrompt

https://github.com/canopas/Intro-showcase-view

https://canopas.github.io/compose-intro-showcase/


虎哥Lovedroid
Android技术达人 近10年一线开发经验 关注并分享Android、Kotlin新技术,新框架 多年Android底层框架修改经验,对Framework、Server、Binder等架构有深入理解
 最新文章