【Android 从入门到出门】第二章:使用声明式UI创建屏幕并探索组合原则

简介: 【Android 从入门到出门】第二章:使用声明式UI创建屏幕并探索组合原则




👋第二章:使用声明式UI创建屏幕并探索组合原则

移动应用程序需要一个用户界面(UI)来进行用户交互。

例如,创建UI的旧方法在Android中是必不可少的。

这意味着应用程序UI的单独原型使用独特的可扩展标记语言(XML)布局,而不是用于构建逻辑的相同语言。

然而,在现代Android开发中,有一种趋势是停止使用命令式编程,并开始使用声明式方式制作UI,这意味着开发人员根据接收到的数据设计UI。

这种设计范例使用一种编程语言来创建整个应用程序。

公平地说,对于新开发人员来说,在构建UI时决定学习什么似乎很困难:是使用旧的创建视图的方法,还是选择新的Jetpack Compose。

但是,假设您在Jetpack Compose时代之前构建了一个Android应用程序。

在这种情况下,您可能已经知道使用XML有点乏味,尤其是在代码库很复杂的情况下。

然而,使用Jetpack Compose作为您的首选使工作更容易。

此外,它通过确保开发人员使用更少的代码来简化UI开发,因为他们利用了直观的Kotlin api。

因此,新开发人员在创建视图时使用Jetpack Compose而不是XML是合乎逻辑的。

但是,了解这两者是有益的,因为许多应用程序仍然使用XML布局,您可能需要维护视图,但使用Jetpack Compose构建新的视图。

在本章中,我们将通过尝试使用列、行、框、惰性列等实现小示例来了解Jetpack Compose的基础知识。

在本章中,我们将介绍以下内容:

  • 在Jetpack Compose中实现Android视图
  • 在Jetpack Compose中实现一个可滚动列表
  • 使用Jetpack Compose实现第一个带有视图页的选项卡布局
  • 在Compose中实现动画
  • 在Jetpack Compose中实现可访问性
  • 使用Jetpack Compose实现声明式图形

⚽️1. 技术要求

为了能够查看所有指南,您需要分别运行所有预览功能。因此,寻找@Preview可组合函数来查看创建的UI。

⚽️2. 在Jetpack Compose中实现Android视图

在每个Android应用程序中,拥有一个UI元素是非常重要的。Android中的视图是一个简单的UI构建块。

视图确保用户可以通过点击或其他动作与应用程序进行交互。

本指南将介绍不同的Compose UI元素,并了解如何构建它们。

⚾️2.1 准备

在这个指南中,我们将创建一个项目,我们将在整个章节中重复使用,所以让我们继续并按照第1章的步骤,开始与现代Android开发技能,如何创建你的第一个Android项目。

创建一个项目,并将其命名为Compose Basics。

此外,我们将主要使用预览部分来查看我们创建的UI元素。

⚾️2.2 如何实现

创建项目后,按照以下步骤构建几个Compose UI元素:

  1. 在我们的项目中,让我们继续创建一个新包,并将其称为components。这是我们将添加创建的所有组件的地方。
  2. 创建一个Kotlin文件,并将其命名为UIComponents.kt;在UIComponent中,创建一个可组合的函数,命名为EditTextExample(),并调用OutlinedTextField()函数;这将提示你导入所需的导入,即androidx.composer.material.OutlinedTextField:
@Composable
fun EditTextExample() {
    OutlinedTextField()
}
  1. 当您深入研究OutlineTextField时,您将注意到该函数接受多个输入,当您需要自定义自己的可组合函数时,这非常有用。

  1. 对于我们的示例,我们不会对我们创建的UI做太多的操作,而只是看看我们如何创建它们。
  2. 现在,为了完全创建我们的OutlinedTextField()基于我们看到它接受的输入类型,我们可以给它一个文本和颜色,我们可以使用Modifier()修饰它;也就是说,通过给它特定的指令,比如fillMaxWidth(),它设置了最大宽度。
    当我们说fill时,我们只是指定它应该被完全填充。
    我们将.padding(top)设置为16 .dp,它在dp中的内容的每个边缘上应用额外的空间。
    它还有一个值,该值是要在OutlinedTextField中输入的值,还有一个onValueChange lambda侦听输入更改。
  3. 我们还在聚焦和不聚焦时为OutlinedText赋予一些边框颜色,以反映不同的状态。
    因此,如果你开始输入,框的颜色将变为蓝色,如下代码所示:
@OptIn(ExperimentalMaterial3Api::class)
@Preview
@Composable
fun EditTextExample() {
  OutlinedTextField(
    value = "",
    onValueChange = {},
    label = { Text(stringResource(id = R.string.sample)) },
    modifier = Modifier
      .fillMaxWidth()
      .padding(top = 16.dp),
    colors = TextFieldDefaults.outlinedTextFieldColors(
      focusedBorderColor = Color.Blue,
      unfocusedBorderColor = Color.Black
    )
  )
}
  1. 我们还有另一种类型的TextField,它没有轮廓,如果你比较OutlinedTextField作为输入的内容,你会注意到它们非常相似:
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun NotOutlinedEditTextExample() {
    TextField(
        value = "",
        onValueChange = {},
        label = { Text(stringResource(id = R.string.sample)) },
        modifier = Modifier
            .fillMaxWidth()
            .padding(top = 8.dp, bottom = 16.dp),
        colors = TextFieldDefaults.outlinedTextFieldColors(
            focusedBorderColor = Color.Blue,
            unfocusedBorderColor = Color.Black
        )
    )
}
  1. 您可以通过在@Preview可组合函数中添加Compose函数来运行应用程序。
    在我们的示例中,我们可以创建UIElementPreview(),这是一个用于显示UI的预览函数。
    在下图中,顶视图是OutlinedTextField,而第二个视图是普通的TextField。

  1. 现在,让我们来看看按钮的例子。我们将看看用不同的方法创建不同形状的按钮。
    如果您将鼠标悬停在Button()可组合函数上,您将看到它接受的输入,如下图所示。

在第二个示例中,我们将尝试创建一个带有图标的按钮。

此外,我们将添加文本,这在创建按钮时是至关重要的,因为我们需要向用户指定单击按钮后将执行什么操作或执行什么操作。

  1. 因此,继续在同一个Kotlin文件中创建一个Compose函数,并将其命名为ButtonWithIcon(),然后导入Button()可组合函数。
  2. 在它里面,你需要导入一个带有painterResource输入、内容描述、Modifier和色调的Icon()。
    我们还需要Text(),它将给我们的按钮一个名称。对于我们的例子,我们不会使用浅色:
@Composable
fun ButtonWithIcon() {
    Button(onClick = {}) {
        Icon(
            painterResource(id = R.drawable.ic_baseline_shopping_bag_24),
            contentDescription = stringResource(id = R.string.shop),
            modifier = Modifier.size(20.dp)
        )
        Text(text = stringResource(id = R.string.buy), Modifier.padding(start = 10.dp))
    }
}
  1. 让我们继续创建一个新的可组合函数,并将其命名为CornerCutShapeButton();在这个例子中,我们将尝试创建一个有捷径的按钮:
@Composable
fun CornerCutShapeButton() {
    Button(onClick = {}, shape = CutCornerShape(10)) {
        Text(text = stringResource(id = R.string.cornerButton))
    }
}
  1. 让我们继续创建一个新的可组合函数,并将其命名为RoundCornerShapeButton();在这个例子中,我们将尝试创建一个圆角按钮:
@Composable
fun RoundCornerShapeButton() {
    Button(onClick = {}, shape = RoundedCornerShape(10.dp)) {
        Text(text = stringResource(id = R.string.rounded))
    }
}
  1. 让我们继续创建一个新的可组合函数,并将其命名为ElevatedButtonExample();在这个例子中,我们将尝试创建一个带有elevation的按钮:
@Composable
fun ElevatedButtonExample() {
    Button(
        onClick = {},
        elevation = ButtonDefaults.elevation(
            defaultElevation = 10.dp,
            pressedElevation = 15.dp,
            disabledElevation = 0.dp
        )
    ) {
        Text(text = stringResource(id = R.string.elevated))
    }
}
  1. 当您运行应用程序时,您应该有一个类似于下图的图像;
    TextField之后的第一个按钮是ButtonWithIcon(),第二个是CornerCutShapeButton(),第三个是RoundCornerShapeButton(),最后,我们有ElevatedButtonExample()

  1. 现在,让我们看最后一个例子,因为我们将在整个书中使用不同的视图和样式,并将在这个过程中学习更多。
    现在,让我们看一下图像视图;Image()可组合函数接受多个输入,如下图所示。

  1. 在我们的例子中,Image()将只有一个painter,它是不可空的,这意味着你需要为这个可组合函数提供一个图像,一个可访问性的内容描述,和一个修饰符:
@Composable
fun ImageViewExample() {
    Image(
        painterResource(id = R.drawable.android),
        contentDescription = stringResource(id = R.string.image),
        modifier = Modifier
            .size(200.dp)
    )
}
  1. 您还可以尝试使用其他东西,例如添加RadioButton()和CheckBox()元素并自定义它们。
    当您运行您的应用程序时,您应该得到类似于下图的结果。

⚾️2.3 如何工作

每个可组合函数都用@Composable注释。该注释告诉Compose编译器,所提供的编译器打算将所提供的数据转换为UI。

同样重要的是要注意,每个可组合的函数名都需要是名词,而不是动词或形容词,谷歌提供了这些指导方针。

您创建的任何可组合函数都可以接受参数,使应用程序逻辑能够描述或修改您的UI。

我们提到了Compose编译器,这意味着编译器是任何特殊的程序,它接受我们编写的代码,检查它,并将其翻译成计算机可以理解的东西-或机器语言。

在Icon()中,painterresource指定我们要添加到按钮上的图标,内容描述有助于实现可访问性,修饰符用于修饰图标。

我们可以通过添加@Preview注释和showBackground = true来预览我们构建的UI元素:

@Preview(showBackground = true)

@Preview功能强大,我们将在以后的章节中介绍如何更好地利用它。

⚽️3. 在Jetpack Compose中实现一个可滚动列表

在构建Android应用程序时,我们都同意的一件事是你必须知道如何构建一个RecyclerView来显示你的数据。

有了我们新的、现代的Android应用程序构建方式,如果我们需要使用RecyclerView,我们可以使用LazyColumn,这是类似的。

在本指南中,我们将查看行、列和LazyColumn,并使用我们的虚拟数据构建一个可滚动列表。

此外,我们将在这个过程中学习一些Kotlin。

⚾️3.1 准备

我们将继续使用Compose Basics项目来构建可滚动列表;因此,要开始,您需要完成前面的配方。

⚾️3.2 如何实现

按照以下步骤构建第一个可滚动列表:

  1. 让我们继续构建第一个可滚动列表,但首先,我们需要创建虚拟数据,这是我们希望显示在列表上的项。因此,创建一个名为favoritecity的包,我们的可滚动示例将位于其中。
  2. 在favoritecity包中,创建一个新的数据类,并将其命名为City;这将是我们的虚拟数据源——数据类City()。
  3. 让我们对City数据类建模。在添加了带注释的值之后,确保添加了必要的导入:
data class City(
  @StringRes val nameResourceId: Int,
  @DrawableRes val imageResourceId: Int
)
  1. 现在,在我们的虚拟数据中,我们需要创建一个Kotlin类,并将这个类称为CityDataSource。
    在这个类中,我们将创建一个名为loadCities()的函数,它将返回list 的列表,我们将在可滚动列表中显示该列表。
    检查技术要求部分的所有需要的导入,以获得所有的代码和图像:
class CityDataSource {
    fun loadCities(): List<City> {
        return listOf(
            City(R.string.spain, R.drawable.spain),
            City(R.string.new_york, R.drawable.newyork),
            City(R.string.tokyo, R.drawable.tokyo),
            City(R.string.switzerland, R.drawable.switzerland),
            City(R.string.singapore, R.drawable.singapore),
            City(R.string.paris, R.drawable.paris),
        )
    }
}
  1. 现在,我们有了虚拟数据,是时候将其显示在可滚动列表上了。
    让我们在组件包中创建一个新的Kotlin文件,并将其命名为CityComponents。
    在CityComponents中,我们将创建@Preview函数:
@Preview(showBackground = true)
@Composable
private fun CityCardPreview() {
    CityApp()
}
  1. 在@Preview函数中,我们有另一个可组合函数CityApp();在这个函数中,我们将调用CityList可组合函数,该函数将列表作为参数。
    此外,在这个可组合函数中,我们将调用LazyColumn,项目将是CityCard(城市)。
    有关LazyColumn和items的进一步解释,请参阅它的工作原理一节:
@Composable
fun CityList(cityList: List<City>) {
    LazyColumn {
        items(cityList) { cities ->
            CityCard(cities)
        }
    }
}
  1. 最后,让我们构造CityCard(城市)可组合函数:
@Composable
fun CityCard(city: City) {
    Card(modifier = Modifier.padding(10.dp), elevation = CardDefaults.cardElevation(4.dp)) {
        Column {
            Image(
                painter = painterResource(city.imageResourceId),
                contentDescription = stringResource(R.string.city_images),
                modifier = Modifier
                    .fillMaxWidth()
                    .height(154.dp),
                contentScale = ContentScale.Crop
            )
            Text(
                text = LocalContext.current.getString(city.nameResourceId),
                modifier = Modifier.padding(16.dp),
                style = MaterialTheme.typography.headlineLarge
            )
        }
    }
}
  1. 当运行CityCardPreview可组合函数时,应该有一个可滚动的列表,如下图所示。

⚾️3.3 如何工作

在Kotlin中,列表有两种类型,不可变和可变。

不可变列表是不能修改的项,而可变列表是列表中可以修改的项。

要定义列表,我们可以说列表是元素的一般有序集合,这些元素可以是整数、字符串、图像等形式,这主要取决于我们希望列表包含的数据类型。

例如,在我们的示例中,我们有一个字符串和图像来帮助通过名称和图像识别我们最喜欢的城市。

在我们的City数据类中,我们使用@StringRes和@DrawableRes是为了方便地直接从res文件夹中为Drawable和String提取数据,它们也表示图像和字符串的ID。

我们创建了CityList,并用可组合函数对其进行注释,并将城市对象列表声明为函数中的参数。

Jetpack Compose中的可滚动列表是使用LazyColumn生成的。

LazyColumn和Column之间的主要区别在于,当使用Column时,您只能显示小项,而Compose会一次加载所有项。

此外,列只能保存固定的可组合函数,而LazyColumn,顾名思义,可以根据需要加载内容,因此可以在需要时加载更多项。

此外,LazyColumn还内置了滚动功能,这使得开发人员的工作更轻松。

我们还创建了一个可组合函数CityCard,在其中从Compose导入Card()元素。

一张卡片包含关于单个对象的内容和动作;例如,在我们的示例中,我们的卡片具有图像和城市名称。

Compose中的Card()元素在其参数中有以下输入:

@Composable
@ComposableInferredTarget
public fun Card(
  modifier: Modifier,
  shape: Shape,
  colors: CardColors,
  elevation: CardElevation,
  border: BorderStroke?,
  content: @Composable() (ColumnScope.() -> Unit)
): Unit

这意味着你可以很容易地塑造你的卡到最适合;我们的卡片有padding和elevation, scope有column。

在本专栏中,我们有一个图像和文本,这有助于描述图像以获得更多上下文。

⚾️3.4 参考

在Compose中有更多关于列表和网格的知识要学习;您可以使用此链接了解更多信息:https://developer.android.com/jetpack/compose/lists。

⚽️4. 使用Jetpack Compose实现第一个带有视图页的选项卡布局

在Android开发中,在页面之间使用幻灯片是非常常见的,这是一个重要的用例,甚至当你试图以标签和轮播方式显示特定数据时。

在这个指南中,我们将在Compose中构建一个简单的水平分页器,并看看我们如何利用新知识来构建更好、更现代的Android应用程序。

⚾️4.1 准备

在本例中,我们将构建一个水平分页器,它在被选中时改变颜色,以显示已选中的状态。

为了更好地理解状态,我们将在第3章处理Jetpack Compose中的UI状态和使用Hilt中查看状态。打开Compose Basics项目开始。

⚾️4.2 如何实现

遵循以下步骤来构建您的选项卡轮播:

  1. 将以下页面依赖项添加到build.gradle(Module:app):
implementation("androidx.compose.material3:material3")
    implementation "com.google.accompanist:accompanist-pager:0.32.0"
    implementation "com.google.accompanist:accompanist-pager-indicators:0.32.0"

Jetpack Compose提供了accompanist,这是一组库,旨在支持开发人员通常需要的功能——例如,在我们的例子中,页面调度器。

  1. 在与前面的食谱相同的项目中,让我们创建一个名为pagerexample的包;在其中创建一个名为CityTabExample的Kotlin文件;在这个文件中,创建一个可组合的函数,并将其命名为CityTabCarousel:
@Composable
fun CityTabCarousel(){}
  1. 现在,让我们继续构建CityTabCarousel;在我们的例子中,我们将创建一个虚拟的页面列表,其中包含我们之前项目中的城市:
@RequiresApi(Build.VERSION_CODES.M)
@OptIn(ExperimentalPagerApi::class)
@Composable
fun CityTabCarousel(
    pages: MutableList<String> = arrayListOf(
        "Spain",
        "New York",
        "Tokyo",
        "Switzerland",
        "Singapore",
        "Paris"
    )
) {}
  1. 我们需要根据状态改变按钮的颜色,为此;我们需要使用LocalContext,它提供了我们可以使用的上下文。
    我们还需要创建一个var pagerState = memorberPagerState(),它将记住我们的分页状态,最后,当单击时,我们将需要移动到分页中的下一个城市,这将非常有用。
    因此,在CityTabCarousel可组合函数中添加以下代码:
val context = LocalContext.current
var pagerState = rememberPagerState()
val coroutineScope = rememberCoroutineScope()
  1. 现在,让我们创建Column元素并添加ScrollableTabRow()可组合函数:
Column {
        ScrollableTabRow(
            selectedTabIndex = pagerState.currentPage,
            indicator = { tabPositions ->
                TabRowDefaults.Indicator(
                    Modifier
                        .pagerTabIndicatorOffset(pagerState, tabPositions)
                        .fillMaxHeight(0f)
                )
            },
            edgePadding = 0.dp,
            backgroundColor = Color(context.resources.getColor(R.color.white, null)),
        ) {
            pages.forEachIndexed { index, title ->
                val isSelected = pagerState.currentPage == index
                TabHeader(
                    title,
                    isSelected,
                    onClick = { coroutineScope.launch { pagerState.animateScrollToPage(index) } },
                )
            }
        }
        HorizontalPager(
            count = pages.size,
            state = pagerState,
            modifier = Modifier
                .fillMaxWidth()
                .fillMaxHeight()
                .background(Color.White)
        ) { page ->
            Text(
                text = "Display City Name: ${pages[page]}",
                modifier = Modifier.fillMaxWidth(),
                style = TextStyle(
                    textAlign = TextAlign.Center
                )
            )
        }
    }
  1. 为HorizontalPager添加Text()和TabHeader():
HorizontalPager(
            count = pages.size,
            state = pagerState,
            modifier = Modifier
                .fillMaxWidth()
                .fillMaxHeight()
                .background(Color.White)
        ) { page ->
            Text(
                text = "Display City Name: ${pages[page]}",
                modifier = Modifier.fillMaxWidth(),
                style = TextStyle(
                    textAlign = TextAlign.Center
                )
            )
        }
  1. 请按照技术需求部分提供的链接下载此配方的完整代码,以添加所需的所有代码。
    最后,运行@Preview函数,您的应用程序应该如下图所示。

⚾️4.3 如何工作

Accompanist 带有一些重要的库,例如,系统UI控制器,AppCompact撰写主题适配器,材料主题适配器,Pager, Drawable Painter和Flow Layouts,仅举几个例子。

我们在CityTabCarousel函数的Column中使用的ScrollableTabRow()包含一行选项卡,并帮助在当前聚焦或选中的选项卡下方显示指示器。

此外,顾名思义,它支持滚动,您不必实现进一步的滚动工具。

它还将标签偏移量放在起始边缘,您可以快速滚动屏幕外的标签,正如您运行@Preview功能并使用它时所看到的那样。

当我们在Compose中调用remember()时,这意味着我们在整个重组中保持任何值的一致性。

Compose提供了这个函数来帮助我们在内存中存储单个对象。

当我们触发应用程序运行时,记住()存储初始值。

顾名思义,它只是保留值并返回存储的值,以便可组合函数可以使用它。

此外,无论何时存储的值发生变化,您都可以更新它,并且remember()函数将保留它。

下次我们在应用程序中触发另一次运行并发生重组时,remember()函数将提供最新的存储值。

您还会注意到我们的MutableList在每个位置都被索引,我们这样做是为了检查哪个被选中。

在这个Lambda中,我们调用TabHeader并显示所选的选项卡页面。

forEachIndexed对每个元素执行给定的操作,提供元素的顺序索引。

我们还确保当用户单击特定选项卡时,我们在正确的页面上:

onClick = { coroutineScope.launch { pagerState.
animateScrollToPage(index) } }

HorizontalPager是一个水平滚动布局,允许我们的用户从左到右在项目之间翻转。

它接受几个输入,但是我们为它提供计数、状态和修饰符,以便在我们的用例中修饰它。

在Lambda中,我们在我们的示例中显示文本,显示我们在哪个页面,这有助于导航,如下所示:

@Deprecated
@Composable
@ComposableInferredTarget
public fun HorizontalPager(
    count: Int,
    modifier: Modifier,
    state: PagerState,
    reverseLayout: Boolean,
    itemSpacing: Dp,
    contentPadding: PaddingValues,
    verticalAlignment: Alignment.Vertical,
    flingBehavior: FlingBehavior,
    key: ((Int) -> Any)?,
    userScrollEnabled: Boolean,
    content: @Composable() (PagerScope.(Int) -> Unit)
): Unit

TabHeader可组合函数有一个Box();Jetpack Compose中的框将始终调整大小以适合内容,这受到指定的约束。

在我们的示例中,我们用selectable修饰符修饰Box,它将组件配置为可选的,作为互斥组的一部分,允许每个项在任何给定时间只被选中一次。

👬 交友小贴士:

博主GithubGitee同名账号,Follow 一下就可以一起愉快的玩耍了,更多精彩文章请持续关注。


专栏推荐


目录
相关文章
|
25天前
|
消息中间件 安全 数据处理
Android为什么不能在子线程更新UI
Android为什么不能在子线程更新UI
26 0
|
13天前
|
编解码 Android开发 UED
安卓UI/UX设计原则:打造引人入胜的用户体验
【4月更文挑战第13天】本文探讨了安卓UI/UX设计的关键原则,包括一致性、简洁性、反馈、清晰性、效率和适应性。一致性要求视觉和行为保持一致,利用系统UI;简洁性减少用户行动,简化导航;反馈需即时且明确;清晰性强调表达清晰,布局有序;效率关注性能优化和任务简化;适应性涉及多设备适配和用户多样性。遵循这些原则,可创建出色应用,提供无缝用户体验。设计应持续迭代,适应技术发展和用户需求。
|
17天前
|
XML 移动开发 Android开发
构建高效安卓应用:采用Jetpack Compose实现动态UI
【4月更文挑战第10天】 在现代移动开发中,用户界面的流畅性和响应性对于应用的成功至关重要。随着技术的不断进步,安卓开发者寻求更加高效和简洁的方式来构建动态且吸引人的UI。本文将深入探讨Jetpack Compose这一革新性技术,它通过声明式编程模型简化了UI构建过程,并提升了性能与跨平台开发的可行性。我们将从基本概念出发,逐步解析如何利用Jetpack Compose来创建具有数据动态绑定能力的安卓应用,同时确保应用的高性能和良好用户体验。
15 0
|
19天前
|
XML Java Android开发
Android之UI基础控件
Android之UI基础控件
|
19天前
|
XML 开发工具 Android开发
构建高效的安卓应用:使用Jetpack Compose优化UI开发
【4月更文挑战第7天】 随着Android开发不断进化,开发者面临着提高应用性能与简化UI构建流程的双重挑战。本文将探讨如何使用Jetpack Compose这一现代UI工具包来优化安卓应用的开发流程,并提升用户界面的流畅性与一致性。通过介绍Jetpack Compose的核心概念、与传统方法的区别以及实际集成步骤,我们旨在提供一种高效且可靠的解决方案,以帮助开发者构建响应迅速且用户体验优良的安卓应用。
|
6天前
|
Linux 编译器 Android开发
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
在Linux环境下,本文指导如何交叉编译x265的so库以适应Android。首先,需安装cmake和下载android-ndk-r21e。接着,下载x265源码,修改crosscompile.cmake的编译器设置。配置x265源码,使用指定的NDK路径,并在配置界面修改相关选项。随后,修改编译规则,编译并安装x265,调整pc描述文件并更新PKG_CONFIG_PATH。最后,修改FFmpeg配置脚本启用x265支持,编译安装FFmpeg,将生成的so文件导入Android工程,调整gradle配置以确保顺利运行。
24 1
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
|
28天前
|
Java Android开发
Android 开发获取通知栏权限时会出现两个应用图标
Android 开发获取通知栏权限时会出现两个应用图标
14 0
|
1月前
|
XML 缓存 Android开发
Android开发,使用kotlin学习多媒体功能(详细)
Android开发,使用kotlin学习多媒体功能(详细)
103 0
|
1月前
|
设计模式 人工智能 开发工具
安卓应用开发:构建未来移动体验
【2月更文挑战第17天】 随着智能手机的普及和移动互联网技术的不断进步,安卓应用开发已成为一个热门领域。本文将深入探讨安卓平台的应用开发流程、关键技术以及未来发展趋势。通过分析安卓系统的架构、开发工具和框架,本文旨在为开发者提供全面的技术指导,帮助他们构建高效、创新的移动应用,以满足不断变化的市场需求。
18 1
|
3天前
|
数据库 Android开发 开发者
安卓应用开发:构建高效用户界面的策略
【4月更文挑战第24天】 在竞争激烈的移动应用市场中,一个流畅且响应迅速的用户界面(UI)是吸引和保留用户的关键。针对安卓平台,开发者面临着多样化的设备和系统版本,这增加了构建高效UI的复杂性。本文将深入分析安卓平台上构建高效用户界面的最佳实践,包括布局优化、资源管理和绘制性能的考量,旨在为开发者提供实用的技术指南,帮助他们创建更流畅的用户体验。