Início do Lado Tático e Barra de Topo Personalizada - YouTuber Android App - Parte 2

Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba grátis conteúdos Android sem precedentes! Você receberá um email de confirmação. Somente depois de confirma-lo é que eu poderei lhe enviar os conteúdos semanais exclusivos. Os artigos em PDF são entregues somente para os inscritos na lista.

Email inválido.
Blog /Android /Início do Lado Tático e Barra de Topo Personalizada - YouTuber Android App - Parte 2

Início do Lado Tático e Barra de Topo Personalizada - YouTuber Android App - Parte 2

Vinícius Thiengo
(774) (10)
Go-ahead
"Sempre sonhe e mire mais alto do que você sabe que você pode fazer. Não se preocupe em ser melhor do que seus contemporâneos e antecessores. Tente ser melhor do que você mesmo."
William Faulkner
Kotlin Android
Capa do livro Mapas Android de Alta Qualidade - Masterização Android
TítuloMapas Android de Alta Qualidade - Masterização Android
CategoriasAndroid, Kotlin, Masterização, Especialização
AutorVinícius Thiengo
Edição
Ano2020
Capítulos11
Páginas166
Acessar Livro
Quer aprender a programar para Android? Acesse abaixo o curso gratuito no Blog.
Conteúdo Exclusivo
Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba gratuitamente conteúdos Android sem precedentes!
Email inválido

Tudo bem?

Neste artigo vamos continuar com o nosso projeto de aplicativo Android para YouTubers. Aplicativo mobile completo.

Aqui vamos literalmente iniciar a parte tática do projeto, começar a codificar.

Vamos criar um simples app e já adicionar a nossa barra de topo personalizada.

Barra de topo do aplicativo Android para YouTubers

Antes de prosseguir, saiba que:

A versão e-book (PDF 📙) do projeto completo está disponível somente para os inscritos da lista de e-mails 📧 do Blog.

Se você se inscrever ainda hoje é possível que o link do e-book esteja disponível na página de confirmação de sua inscrição na lista de e-mails do Blog.

É isso.

A seguir os tópicos que estaremos abordando neste segundo conteúdo do projeto de aplicativo Android para YouTubers:

O que já temos até aqui

Se você chegou no projeto somente agora, saiba que está não é a primeira e nem mesmo a última parte, artigo já publicado.

Todo o roteiro está na listagem a seguir:

Para tirar o máximo proveito do projeto de aplicativo Android que estaremos desenvolvendo é inteligente seguir cada um dos conteúdos na ordem apresentada na lista anterior.

Repositório

Para ter acesso a todos os fontes do projeto já finalizado, entre no repositório GitHub dele em:

➙ GitHub do projeto de aplicativo Android para YouTuber.

Iniciando um novo aplicativo

Vamos primeiro criar um simples aplicativo no Android Studio IDE, com um atividade vazia, "Empty Activity".

Depois deste passo vamos prosseguir colocando no novo projeto todos os requisitos definidos no lado estratégico do projeto.

Com o seu ambiente de desenvolvimento aberto (Android Studio IDE), inicie um novo aplicativo Kotlin com as seguintes configurações:

  • Nome da aplicação: Canal Vinícius Thiengo;
  • API mínima: 21 (Android Lollipop) - mais de 94% dos aparelhos Android em mercado sendo atendidos;
  • Atividade inicial: Empty Activity;
  • Nome da atividade inicial: MainActivity;
  • Para todos os outros campos, mantenha os valores já definidos por padrão.

Tela de configuração padrão de um novo projeto no Android Studio

Note que em "Package name" você deve preferencialmente utilizar o comum em seu ambiente de desenvolvimento. E não o meu, digo, o nome de pacote com o meu prefixo "thiengo.com.br".

Estou dando essa ênfase em "Package name", pois a partir desta segunda parte do projeto de aplicativo o nome raiz de pacote aparecerá em inúmeros pontos do código do app.

E se você estiver seguindo o projeto passo a passo, então essa será a única parte diferente entre o projeto dos conteúdos publicados aqui e à versão em seu ambiente de desenvolvimento.

Sendo assim, vamos aos arquivos de automação do projeto.

Configurações Gradle

A seguir a configuração inicial de ambos os arquivos Gradle do projeto.

Primeiro o arquivo Gradle Nível de Projeto, ou build.gradle (Project: Canal_Vinícius_Thiengo):

buildscript {
ext.kotlin_version = "1.4.0"
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

allprojects {
repositories {
google()
jcenter()
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}

 

Agora o arquivo Gradle Nível de Aplicativo, ou build.gradle (Module: app):

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
compileSdkVersion 30
buildToolsVersion "30.0.0"

defaultConfig {
applicationId "thiengo.com.br.canalvinciusthiengo"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
}
}
}

dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"

implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.0'
}

 

Para ambos os arquivos Gradle:

Se no momento em que você estiver implementando este projeto houverem versões mais atuais das bibliotecas, plugins e APIs referenciadas nesses arquivos de automação.

Então prossiga com as versões mais atuais, pois o projeto deverá funcionar sem problema algum.

Ao final dessa configuração, se o IDE exigir, sincronize o projeto.

Note que já adicionamos a biblioteca com.google.android.material.

Pois estaremos já nesta parte do projeto utilizando componentes visuais do Material Design (CardView, por exemplo) que estão dentro dela.

Strings de sistema

Nosso arquivo de Strings estáticas de projeto, ao menos neste início, estará bem "magrinho".

Em /res/values/strings.xml coloque:

<resources>
<string name="app_name">
Canal Vinícius Thiengo
</string>
</resources>

 

Lembrando que todas as Strings estáticas de projeto que podem sofrer tradução caso o aplicativo passe por internacionalização...

... todas essas devem entrar no arquivo de conteúdo estático próprio para Stringsstrings.xml.

Configurações AndroidManifest

A seguir a configuração inicial de um dos principais arquivos de aplicativos Android, o AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="thiengo.com.br.canalvinciusthiengo">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">

<activity
android:name=".ui.MainActivity"
android:screenOrientation="portrait">

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

 

Você deve ter notado que na tag <activity> definimos que o aplicativo funcionará somente em modo portrait (na vertical), android:screenOrientation="portrait".

Está é uma limitação válida para este primeiro release. Tendo em mente que o propósito central do app é permitir que o usuário seja avisado sobre um novo vídeo no canal e então acione a abertura do vídeo no app nativo do YouTube.

Ou seja, o seguidor do canal que também é usuário do app não passará, a princípio, muitos minutos com o aplicativo aberto.

Vamos prosseguir, pois durante todo o projeto ainda voltaremos algumas vezes ao AndroidManifest.xml.

Ícones de abertura do app

Para os ícones de abertura de aplicativo, que ficam na área de apps do aparelho, também conhecidos como Launcher Icons.

Para esses teremos as duas versões esperadas e ainda utilizando imagens rasterizadas.

Primeiro o ícone em versão retangular, ic_launcher.png:

Ícone retangular de abertura de aplicativo

Então o ícone em versão circular, ic_launcher_round.png:

Ícone circular de abertura de aplicativo

Não esqueça de fazer o download dos ícones acima e coloca-los nos corretos folders mipmap (sobrescrevendo os ícones atuais).

Os códigos XML de ícones adaptativos:

  • /res/drawable/ic_launcher_background.xml;
  • /res/drawable-v24/ic_launcher_foreground.xml;
  • /res/mipmap-anydpi-v26/ic_launcher;
  • /res/mipmap-anydpi-v26/ic_launche_round.

Esses podem ser removidos do projeto com segurança, pois não utilizaremos aqui.

Configurações de estilo

Agora a configuração inicial de cada um dos arquivos responsáveis pelo estilo, tema, do projeto.

Cores

Primeiro o simples (por enquanto) arquivo de cores.

Coloque as seguintes definições em /res/values/colors.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#FFFFFF</color>
<color name="colorPrimaryDark">#FFFFFF</color>
<color name="colorAccent">#595959</color>
</resources>

 

É isso mesmo que você notou: as cores definidas em colorPrimary e em colorDarkPrimary são as mesmas.

Por agora é um tanto difícil enxergar que essa é uma boa estratégia para o projeto que estamos desenvolvendo, mas no decorrer do conteúdo tudo vai se encaixar (se auto-explicar) como definido em protótipo estático.

Tema

Então a versão inicial simples do arquivo de definição de temas, estilos, em projeto.

Segue configuração de /res/values/styles.xml:

<resources>
<!-- Tema base do aplicativo. -->
<style
name="AppTheme"
parent="Theme.AppCompat.Light.NoActionBar">

<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>

 

Curiosidade:

É possível abreviar o uso de parent (definição de tema ancestral) em tag <style> utilizando ponto (.).

Ou seja, a definição a seguir:

...
<style
name="Theme.AppCompat.Light.NoActionBar.AppTheme">
...

 

É equivalente à seguinte definição:

...
<style
name="AppTheme"
parent="Theme.AppCompat.Light.NoActionBar">
...

Tela de abertura (Splash Screen)

Agora vamos criar a popular e necessária tela de abertura de aplicativo, também conhecida como Launcher Screen ou Splash Screen.

Delay de carregamento de layout principal

Essa tela é importante, pois sempre que o aplicativo não está já em memória, então há um pequeno delay no carregamento do layout inicial.

E nesse delay o comum, caso nenhuma tela de abertura tenha sido definida, é uma tela toda branca (ou preta, depende de qual tema root está definido em app) sendo apresentada ao usuário.

Antes de continuar quero ressaltar que:

Diferente do que muitos (principalmente aqueles que estão iniciando no Android) possam pensar, não são todos os aplicativos que têm uma tela de abertura definida.

Consequentemente o valor padrão de tela de abertura (valor padrão de windowBackground) acaba sendo utilizado, deixando assim o app pouco profissional ao menos em termos de design.

Então é isso.

Vamos sim dar uma atenção especial a este detalhe, pois em termos de "entregar algo profissional" isso faz sim diferença no projeto.

Imagens da estrutura

Teremos duas imagens em nossa tela de abertura:

Imagem de centro de tela, com a logo do canal YouTube.

Logo do canal YouTube

Imagem de fundo, informando quem (ou qual empresa) desenvolveu o aplicativo Android.

PoweredBy do aplicativo Android

Com os links informados anteriormente, realize o download de cada uma das versões das imagens e coloque-as em seus respectivos folders drawable.

Confesso que o processo de criar imagens não é nem de perto uma expertise minha. Mas posso lhe dar algumas dicas sobre isso.

Para as imagens de tela de abertura eu utilizei o Adobe Fireworks (software pago) e fui na "martelada" tentando vários tamanhos até encontrar um ideal de imagens e de texto.

Depois disso utilizei os recursos gratuitos:

  • Fotoram para arredondar as bordas da imagem retangular de logo. Este recurso eu utilizei antes mesmo de construir a logo com imagem e texto;
  • Native Script Image Buider para gerar todas as versões DPI de cada uma das duas imagens da tela de abertura. Este recurso foi o último que utilizei antes de colocar as imagens já formatadas no projeto dentro do Android Studio.

Apesar de eu ter utilizado o Adobe Fireworks, você pode utilizar inúmeros outros softwares gratuitos (o GIMP é um deles) e até mesmo free online, para construir as imagens de sua versão de app.

Definindo o layer-list

Com as imagens já definidas e migradas para o projeto de aplicativo, agora precisamos definir a estrutura que vai juntar tudo para ser carregada como "layout" de tela de abertura.

Sendo assim, no folder /res/drawable, crie o arquivo XML launcher_screen.xml com a seguinte definição:

<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:opacity="opaque">
<!--
A definição android:opacity=”opaque” é
fundamental para evitar um flash em preto
durante a transição do tema de tela de
abertura em app.

Note que a ordem das tags <item> importa.
A que vem antes em arquivo é então o layer
mais abaixo na estrutura do layout.
-->

<!--
A cor de background. Preferencialmente a
mesma cor definida para a StatusBar.

A cor de StatusBar para essa nossa versão
de projeto será #595959.
-->
<item android:drawable="@color/colorStatusBar" />

<!--
A logo central na tela. Aqui estamos utilizando
uma com a seguinte definição em DP:
➙ width: 264dp;
➙ height: 60dp.
-->
<item>
<bitmap
android:gravity="center"
android:src="@drawable/launcher_screen_logo" />
</item>

<!--
Definição do PoweredBy, "Desenvolvido por", logo
ao fundo na tela. Precisamos trabalhar com um
texto em imagem, pois até o momento da construção
deste projeto não era possível colocar texto
String como uma das camadas em layer-list.

Aqui estamos utilizando a seguinte definição em
DP para essa imagem:
➙ width: 250dp;
➙ height: 20dp.

A definição android:bottom="58dp" é necessária, pois
caso contrário, devido a android:gravity="center_horizontal|bottom",
a imagem fica literalmente "colada" no fundo da
tela e assim, dependendo do aparelho (modelo), a
bottom bar padrão do Android fica sobre a imagem
de PoweredBy.
-->
<item android:bottom="58dp">
<bitmap
android:gravity="center_horizontal|bottom"
android:src="@drawable/powered_by" />
</item>
</layer-list>

 

Por favor, leia todos os comentários da estrutura XML anterior para assim entender o porquê de cada camada, <item>.

Definindo o tema

Sim, vamos precisar de um novo tema. Somente para carregamento da tela de abertura.

Sendo assim, em /res/values/styles.xml, adicione o novo tema AppTheme.Launcher logo no início desse arquivo e com a seguinte definição:

...
<!--
Tema da launcher screen. Carregado antes de tudo
para que não fique em tela uma definição de
windowBackground que é padrão e sem relação com
o design do app.
-->
<style name="AppTheme.Launcher">
<item name="android:windowBackground">
@drawable/launcher_screen
</item>
</style>
...

Atualizando o AndroidManifest

Ainda é preciso mudar o tema de <application> no AndroudManifest.xml.

Vamos colocar nosso novo tema AppTheme.Launcher como o tema do app, exatamente como a seguir:

<application
...
android:theme="@style/AppTheme.Launcher">

 

Por fim é preciso colocar no onCreate() da atividade principal do projeto, antes de super.onCreate(), a invocação do verdadeiro tema do app via setTheme().

Exemplo:

...
override fun onCreate( savedInstanceState: Bundle? ){
setTheme( R.style.AppTheme )
super.onCreate( savedInstanceState )
...
}
...

 

Enfim... sobre a tela de abertura é isso.

Na parte de códigos dinâmicos da atividade principal já teremos essa definição de setTheme().

Quando o app for carregado e não estiver já em memória, teremos a seguinte tela de abertura sendo apresentada:

Tela de abertura, splash screen, do aplicativo Android para YouTubers

Atividade principal

Para um projeto inicial com uma "Empty Activity" a atividade inicial e o layout dessa atividade são ambos bem simples.

Apesar dos inúmeros fragmentos que teremos em projeto, atividade nós teremos apenas uma. E já adianto aqui (spoiler), teremos também um Service.

É isso, vamos aos códigos da atividade. Começando pelo fácil: os códigos estáticos.

Layout XML

Como layout inicial temos em /res/layout/activity_main.xml a seguinte estrutura:

Diagrama da versão inicial do layout activity_main.xml

Simples, certo?

Então a versão em código deste layout, código XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.MainActivity">

<!-- TODO -->
</LinearLayout>

 

Ainda voltaremos algumas vezes a este layout.

Classe Kotlin

Por fim, para a apresentação da versão inicial de projeto, vamos aos primeiros códigos Kotlin da atividade principal.

Primeiro, na raiz do pacote do projeto, crie o pacote /ui. Logo depois coloque (arraste) a classe MainActivity para dentro deste pacote.

Assim temos o código da atividade:

package thiengo.com.br.canalvinciusthiengo.ui

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import thiengo.com.br.canalvinciusthiengo.R

/**
* Atividade principal e única atividade do
* aplicativo.
*
* @constructor cria um objeto completo do tipo
* [MainActivity].
*/
class MainActivity : AppCompatActivity() {

override fun onCreate( savedInstanceState: Bundle? ) {
setTheme( R.style.AppTheme ) /* Devido ao uso de uma Splash Screen personalizada. */
super.onCreate( savedInstanceState )
setContentView( R.layout.activity_main )
}
}

 

Bem simples, certo?

Note que como estamos desenvolvendo um aplicativo que funcionará como uma espécie de framework... devido a isto teremos comentários em muitos trechos do projeto.

Comentários padrões de códigos Kotlin:

...
/**
* Atividade principal e única atividade do
* aplicativo.
*
* @constructor cria um objeto completo do tipo
* [MainActivity].
*/
...

 

Isso para que seja o menor possível o número de dúvidas enquanto um outro desenvolvedor estiver reutilizando o projeto para algum outro canal YouTube.

Agora podemos partir para os códigos específicos de domínio do aplicativo. Digo, alguns desses códigos ainda nesta segunda parte de nosso projeto Android.

Assinatura de topo

Vamos iniciar com a assinatura de topo do aplicativo:

Barra de topo do app Android de YouTubers

Que diferente do que alguns possam imaginar:

Nós não estaremos utilizando componentes Android exclusivos para barra de topo e sim componentes comuns em layout de conteúdo.

Esse caminho foi o escolhido, pois infelizmente a Toolbar e a AppBarLayout ainda são "barreiras" para barras de topo muito diferentes do convencional, aquilo que prega o Material Design.

Estáticos de interface

Primeiro a parte "tranquila", a atualização dos recursos estáticos, XML, de projeto.

Arquivo de Strings

Em /res/values/strings.xml adicione as novas Strings a seguir:

...
<!-- MainActivity -->
<string name="channel_name">
Vinícius Thiengo
</string>
<string name="channel_desc">
Seu canal sobre Desenvolvimento de Aplicativos
Android e TI.
</string>
<string name="youtube_content_icon_content_desc">
Ícone do YouTube.
</string>
<string name="channel_thumb_content_desc">
Thumb do canal YouTube Vinícius Thiengo.
</string>
<string name="channel_toast_alert">
É preciso ter o aplicativo do YouTube instalado
para acessar o canal.
</string>
...

 

Algo que ainda não comentei, mas é válido principalmente se você estiver iniciando no desenvolvimento de aplicativos Android, é:

Todos os rótulos de recursos estáticos (em XML) e de recursos dinâmicos (em Kotlin - variáveis, classes, ...) serão definidos em inglês.

Pois esse é o idioma "comum" em desenvolvimento de software e também porque as APIs nativas são todas em inglês.

Seria muito bruto utilizar rótulos em português e ao mesmo tempo ter que consumir APIs com rótulos em inglês. Certamente ao menos a leitura do código ficaria dificultada.

Mas, os valores e os comentários em código, todos eles serão em português.

Dimens

Apesar de que vamos utilizar esse arquivo estático para apenas uma definição...

... apesar disso ele será útil, pois é uma definição de espaçamento que será utilizada em vários layouts do projeto.

Em /res/values crie o arquivo dimens.xml com a seguinte estrutura:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="standard_screen_side_margin">25dp</dimen>
</resources>

 

Se você é iniciante no Android deve estar sendo bem confuso ver alguns arquivos XML com o prólogo definido, <?xml version="1.0" encoding="utf-8"?>, e outros arquivos sem o prólogo.

No começo eu também achei, mas se o IDE oficial cria os arquivos assim e os projetos executam sem problemas... então vamos seguir assim.

Novas cores

Agora as cores. Em /res/values/colors.xml adicione as novas definições de cores como a seguir:

...
<!-- Top -->
<color name="colorStatusBar">#595959</color>
<color name="colorTopIcon">#FFFFFF</color>
<color name="colorTopWave">#555555</color>
<color name="colorTopText">#FFFFFF</color>
...

 

Thiengo, porque manter duas definições ou mais para um mesmo valor de cor? Como em colorTopIcon e colorTopText, onde ambas as definições têm o valor #FFFFFF (branco).

Boa pergunta!

Realmente são duas definições com os mesmos valores, porém são definições de contextos diferentes.

Ou seja, se for necessário trocar a cor apenas do ícone de topo (colorTopIcon) e a definição de cor for somente uma para os contextos "ícone de topo" (colorTopIcon) e "texto de topo" (colorTopText)...

... se isso ocorrer você terá que atualizar o código fonte de ao menos um layout na unha, terá que criar uma nova definição... olha a dor de cabeça.

O "reaproveitar código" tem muito mais haver com igualdade de contexto do que com igualdade de valor de propriedade.

Por isso é prudente manter valores repetidos quando os contextos são distintos e podem passar por atualizações diferentes.

StatusBar

Vamos também deixar a StatusBar do aparelho com a cor que "encaixa" com o que foi definido em protótipo estático:

StatusBar do aplicativo Android para YouTubers

Em /res/values/styles.xml adicione o trecho em destaque (com statusBarColor):

...
<style
name="AppTheme"
parent="Theme.AppCompat.Light.NoActionBar">
...

<item name="android:statusBarColor">@color/colorStatusBar</item>
</style>
...

Ícone do YouTube

O ícone de topo do YouTube é um ícone vetorial, ic_youtube_logo.xml:

Ícone YouTube de barra de topo

Realize o download dele e coloque-o no folder /res/drawable de sua versão de projeto.

Waves SVG

No topo, mesmo que não pareça, temos na verdade algumas imagens vetoriais de ondas (waves), fazendo com que o background de topo fique como a seguir:

Background SVG de ondas na barra de topo do aplicativo Android

São exatas quatro imagens vetoriais de onda com variados:

  • Configuração de desenho em plano cartesiano;
  • e Valor do canal alpha (transparência).

Realize o download de cada uma nos links a seguir:

E então coloque-as no folder /res/drawable.

Para que elas possam ser colocadas de maneira eficiente no topo, uma sobre a outra, vamos criar uma lista de camadas (layer list).

Ainda em /res/drawable crie o arquivo bg_top.xml com o código a seguir:

<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">

<item android:drawable="@drawable/bg_wave_01" />
<item android:drawable="@drawable/bg_wave_02" />
<item android:drawable="@drawable/bg_wave_03" />
<item android:drawable="@drawable/bg_wave_04" />
</layer-list>

 

Antes de partirmos para a "logo do canal", saiba que as waves em XML foram geradas no site GetWaves.IO e depois colocadas em projeto utilizando o Vector Asset Studio.

Logo do canal

A logo do canal que vem no topo...

Logo do canal Vinícius Thiengo em aplicativo Android

... deve ser gerada em cinco versões tendo como base o tamanho 65dp x 65dp:

Realize o download das imagens acima e coloque-as nos folders drawable corretos em sua versão de projeto.

Provavelmente você terá que criar em /res os folders a seguir:

  • /drawable-mdpi;
  • /drawable-hdpi;
  • /drawable-xhdpi;
  • /drawable-xxhdpi;
  • /drawable-xxxhdpi.

Eu utilizei o rápido e prático Generic Icon Generator para gerar as cinco versões da logo em 65dp.

Também como parte do resultado temos as cinco versões de /drawable. Basta copiar e colocar em /res.

Família de fontes

Note que a fonte do título do canal está em uma família diferente da convencional Roboto:

Título do canal na barra de topo do aplicativo Android

Em /res crie o folder /font e coloque dentro deste novo folder a seguinte família de fontes:

Layout

E por fim, na parte estática exclusiva da nossa barra de topo, o layout.

Que terá a seguinte estrutura:

Diagrama do layout top_signature.xml

Em /res/layout crie o XML top_signature.xml com a seguinte configuração:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_top"
android:paddingStart="@dimen/standard_screen_side_margin"
android:paddingTop="25dp"
android:paddingEnd="@dimen/standard_screen_side_margin"
android:paddingBottom="65dp">

<ImageView
android:id="@+id/iv_youtube_logo"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_gravity="end"
android:layout_marginBottom="15dp"
android:contentDescription="@string/youtube_content_icon_content_desc"
android:onClick="openYouTubeChannel"
android:src="@drawable/ic_youtube_logo"
app:tint="@color/colorTopIcon" />

<androidx.cardview.widget.CardView
android:id="@+id/cv_channel_logo"
android:layout_width="65dp"
android:layout_height="65dp"
android:layout_below="@+id/iv_youtube_logo"
android:layout_alignParentStart="true"
app:cardCornerRadius="8dp"
app:cardElevation="0dp">

<ImageView
android:layout_width="65dp"
android:layout_height="65dp"
android:contentDescription="@string/channel_thumb_content_desc"
android:onClick="openYouTubeChannel"
android:scaleType="center"
android:src="@drawable/channel_logo" />
</androidx.cardview.widget.CardView>

<TextView
android:id="@+id/tv_channel_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/cv_channel_logo"
android:layout_marginStart="10dp"
android:layout_toEndOf="@id/cv_channel_logo"
android:ellipsize="end"
android:fontFamily="@font/quicksand_variable_font_wght"
android:maxLines="1"
android:onClick="openYouTubeChannel"
android:text="@string/channel_name"
android:textColor="@color/colorTopText"
android:textSize="19sp" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_channel_name"
android:layout_marginStart="10dp"
android:layout_toEndOf="@id/cv_channel_logo"
android:ellipsize="end"
android:maxLines="2"
android:onClick="openYouTubeChannel"
android:text="@string/channel_desc"
android:textColor="@color/colorTopText"
android:textStyle="normal" />
</RelativeLayout>

 

Note que já temos configurado em alguns componentes do layout acima o atributo android:onClick.

Criaremos o método openYouTubeChannel() logo logo na MainActivity.

Classe YouTube de configuração

Antes de irmos às configurações finais da atividade principal em projeto. Vamos primeiro iniciar uma das classes de configuração importantes em todo o aplicativo.

Na raiz do projeto crie o pacote /config.

Dentro deste novo pacote crie a classe abstrata YouTubeConfig com a seguinte configuração inicial:

package thiengo.com.br.canalvinciusthiengo.config

/**
* Classe que contém os principais dados estáticos de
* configuração de acesso à YouTube Data API. E também
* dados para acesso a recursos alternativos externos
* do YouTube.
*
* As classes internas ([Key], [Channel], [ApiV3] e [Notification])
* e também os rótulos de todos os companion object.
* Estes estão presentes em código somente para
* facilitar a leitura dele. Ou seja, em termos de
* regras de sintaxe esses não são obrigatórios.
*/
abstract class YouTubeConfig {

abstract class Channel {
companion object {
/**
* Constante com o identificador único do
* canal. Com esse ID é possível
* carregar da YouTube Data API os dados do
* canal correto.
*/
const val CHANNEL_ID = "UCG3gFuIkRF3PpNkRk3Wp6dw"

/**
* Constante com a URL do canal.
*/
const val CHANNEL_URL = "https://www.youtube.com/channel/$CHANNEL_ID"
}
}
}

 

Vamos seguir com essa estratégia de dados de configuração em projeto ao invés de simplesmente criarmos constantes em qualquer classe.

Pois assim a leitura do código que precisar de alguma das constantes definidas nesta classe...

... essa leitura ficará mais explicativa, pois a constante deverá ser acessada como YouTubeConfig.Channel.CHANNEL_URL, por exemplo.

Ao longo de todo o projeto voltaremos a esta classe para adicionarmos ainda mais configurações.

Se o canal YouTube que você estiver configurando em aplicativo não tiver o ID dele na url, então você pode utilizar o site YouTube Channel ID, Info & Stats para acessar esse ID de canal.

Não adianta utilizar o User Name do canal que aparece em algumas URLs do YouTube, é preciso o identificador único do canal.

Configuração na atividade principal

Por fim a configuração de topo na atividade principal.

No layout

A estrutura do layout /res/layout/activity_main.xml ficará como a seguir:

Diagrama da segunda versão do layout activity_main.xml

Agora em activity_main.xml temos o seguinte XML:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.MainActivity">

<include layout="@layout/top_signature" />
</LinearLayout>

Na atividade

Precisamos colocar na atividade principal o listener de clique já configurado em alguns componentes do layout de topo.

Listener de clique que vai permitir que o usuário do app tenha também acesso imediato ao canal no YouTube.

Sendo assim, na MainActivity adicione o método openYouTubeChannel() como a seguir:

...
/**
* Invoca o aplicativo do YouTube para que o usuário
* tenha acesso direto ao canal.
*
* Esse listener de clique está vinculado aos
* componentes visuais do topo do aplicativo.
*
* Caso o aplicativo nativo do YouTube e nem mesmo um
* navegador Web esteja instalado no aparelho (algo
* utópico), então uma mensagem de falha é apresentada
* ao usuário.
*
* @param view componente visual que teve o evento de
* toque (clique) disparado.
*/
fun openYouTubeChannel( view: View ){

val intent = Intent(
Intent.ACTION_VIEW,
Uri.parse( YouTubeConfig.Channel.CHANNEL_URL )
)

if( intent.resolveActivity( packageManager ) != null ){
startActivity( intent )
}
else{
Toast
.makeText(
this,
getString( R.string.channel_toast_alert ),
Toast.LENGTH_LONG
)
.show()
}
}
...

 

E está lá, nossa classe abstrata de configuração sendo utilizada:

...
Uri.parse( YouTubeConfig.Channel.CHANNEL_URL )
...

 

O que não é incomum ver por aí é o uso de "valor mágico" em código.

No caso anterior seria o valor bruto (inline) do argumento ao invés de uma referência (uma constante, por exemplo):

...
Uri.parse( "O valor inline da String URL" )
...

 

Evite o uso de valores mágicos a qualquer custo, pois em tempo de manutenção, mesmo que ainda em primeiro release, isso dá uma baita dor de cabeça.

Utilize constantes, enum, XML... mas evite valores mágicos.

Ainda faltam os imports das novas entidades adicionadas junto ao método openYouTubeChannel():

...
import android.content.Intent
import android.net.Uri
import android.view.View
import android.widget.Toast
import thiengo.com.br.canalvinciusthiengo.config.YouTubeConfig
...

 

É isso.

Neste ponto do software a configuração física dele em IDE deve estar como a seguir:

Configuração física do projeto Android

Para está segunda parte de nosso projeto de aplicativo Android profissional para YouTubers... chegamos ao fim.

Próximo conteúdo

Aos poucos nós vamos passo a passo desenvolvendo algo que ajuda, mesmo que uma parcela mínima (os YouTubers), a comunidade de não desenvolvedores.

No próximo artigo nós vamos continuar no lado tático do projeto, codificando o bottom menu principal:

➙ Criando e Configurando o Menu Principal - Parte 3.

Então é isso.

Dê uma descansada, tome um café ☕ 🍞. E...

... te vejo na Parte 3.

Se houverem dúvidas ou dicas desta segunda parte do projeto, então deixe nos comentários que logo eu lhe respondo.

Não esqueça de conhecer também o meu canal no YouTube (caso você ainda não conheça) e...

... não deixe de se inscrever na 📩 lista de emails para também garantir a versão em PDF não somente deste projeto de aplicativo Android, mas também de cada novo "conteúdo mini-curso".

Abraço.

Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba grátis conteúdos Android sem precedentes!
Email inválido

Relacionado

Como Criar Protótipos AndroidComo Criar Protótipos AndroidAndroid
Freelancer AndroidFreelancer AndroidAndroid
ViewModel Android, Como Utilizar Este Componente de ArquiteturaViewModel Android, Como Utilizar Este Componente de ArquiteturaAndroid
Porque e Como Utilizar Vetores no AndroidPorque e Como Utilizar Vetores no AndroidAndroid

Compartilhar

Comentários Facebook

Comentários Blog (10)

Para código / script, coloque entre [code] e [/code] para receber marcação especifica.
Forneça seu nome válido.
Forneça seu email válido.
Forneça o comentário.
Enviando, aguarde...
15/09/2020
Opa Thiengo achei bacana essa abordagem do launcher screen, porem tentei aplicar em um outro projeto, e quando seto o setTheme( R.style.AppTheme ) ele da erro, algo relacionado ao    setSupportActionBar(toolbar)
Responder
Vinícius Thiengo (0) (0)
16/09/2020
John, tudo bem?

Se não me engano eu tinha conversado contigo no grupo no WhatsApp, certo?

Acho que aqui será possível dar um melhor esclarecimento do que está ocorrendo em seu caso.

O seu projeto de aplicativo faz uso de uma barra de topo "artificial", uma Toolbar.

Neste caso a sua atividade principal tem um tema definido nela (o que não ocorre em nosso projeto de app framework para YouTubers).

Provavelmente é o tema AppTheme.NoActionBar.

Sendo assim, para colocar a Launcher Screen para funcionar como esperado...

... neste caso é necessário que você tenha como tema alvo de substituição em tempo de execução o tema da atividade principal e não o tema padrão do aplicativo (que seria o tema AppTheme).

Em termos de código, o que estou falando é o seguinte:

A tag <application> no AndroidManifest.xml não deve ser modificada, ou seja, não deve ter o tema AppTheme substituído pelo tema da Launcher Screen.

A substituição, ainda no arquivo AndroidManifest.xml, deve ocorrer na tag da atividade principal. Que é uma tag <activity>.

Exemplo:

...
<activity
        ...
        android:theme=?@style/AppTheme.Launcher">
...

E então, na definição de tema no onCreate() da atividade principal deverá ter o tema real da atividade sendo definido em setTheme().

Exemplo:

...
setTheme( R.style.AppTheme_NoActionBar )
...

Note que em código dinâmico, ao invés de . (ponto) nós utilizando um _ (underline) no nome do tema.

Isso AppTheme.NoActionBar em código XML é o mesmo que AppTheme_NoActionBar em código dinâmico (Kotlin).

John, é isso.

Assim sua Launcher Screen (Splash Screen) deverá funcionar sem problemas.

Surgindo mais dúvidas, pode enviar.

Abraço.
Responder
Fabricio (1) (0)
11/09/2020
Thiengo tenho uma dúvida em relação à construção de layouts xml, no caso eu tenho uma nestedscrollview como pai do layout com height  match_parent porque eu  gostaria que um relative layout filho preenchesse toda a tela mesmo quando esta esteja vazia sem nenhum item num recyclerview que sera colocado dentro, mas por alguma razão o layout não preenche a tela mesmo com match_parent setado voce sabe o que poderia ser feito nesse caso?
Responder
Vinícius Thiengo (0) (0)
16/09/2020
Fabricio, tudo bem?

Faça o seguinte.

Adicione atributo / valor android:fillViewport="true" ao NestedScrollView e veja se assim o problema é resolvido.

Abraço.
Responder
Marcia (1) (0)
26/08/2020
Qual a diferença entre usar app ou android no atributo ImageView? Must use app:tint instead of android:tint Tive que mudar este código (em top_signature.xml):
android:tint="@color/colorTopIcon"
por:
app:tint="@color/colorTopIcon"
Responder
Vinícius Thiengo (0) (0)
27/08/2020
Marcia, tudo bem?

Quando eu estava codificando pela primeira vez este nosso projeto framework, ainda utilizando android:tint, o Lint do Android Studio não acusava problemas.

Posterior a uma nova atualização do Android Studio o IDE começou a me indicar um Warning quando utilizava em componentes visuais (direto na tag) o atributo tint com o namespace android.

Então fiz o que o Lint informou: troquei de android:tint para app:tint.

Ainda não encontrei nada oficial.

Mas sei que atributos Android que não entram no namespace android (que utilizam o namespace  app, por exemplo) são na verdade atributos de suporte a versões antigas do Android.

Ou seja, provavelmente abaixo de alguma versão "XYZ" do Android (partindo da API 21) não mais será possível utilizar android:tint.

Teremos que ficar com o suporte, app:tint.

Marcia, é isso.

Com melhores informações disponíveis eu volto a postar aqui ou no e-mail do Blog.

Surgindo mais dúvidas, pode perguntar.

Abraço.
Responder
Marcia (1) (0)
26/08/2020
Thiengo,

No arquivo /res/drawable/launcher_screen.xml tive que alterar

[code]drawable="#595959"[code]
por
[code]drawable="@color/colorAccent"[code]

@color/colorAccent é #595959

Estava dando essa mensagem quando mandava executar:

CanalVinciusThiengo/app/src/main/res/drawable/launcher_screen.xml:6: AAPT: error: '#595959' is incompatible with attribute drawable (attr) reference.

E parabéns pelo material! Como sempre, excelente ;)
Responder
Vinícius Thiengo (0) (0)
27/08/2020
Marcia, tudo bem?

Incrível este problema.

Você já não é a primeira que aponta ele.

No meu ambiente (Android Studio - versão estável atualizada) o Lint não acusa nada de errado.

De qualquer forma, mudei o valor para @color/colorStatusBar (referência) ao invés de #595959 (inline).

Utilize colorStatusBar no lugar de colorAccent.

É isso.

Surgindo mais dúvidas, pode enviar.

Abraço.
Responder
17/08/2020
boa tarde Thiengo vi que teve ajuste no build.gradle já que foi feito uso de uma cardview, porem não notei ta comentário de uso e ao acessa o projeto notei varias libs informadas.
Responder
Vinícius Thiengo (0) (0)
17/08/2020
John, tudo bem?

Não entendi a dúvida.

No caso você percebeu que a library que permite acesso ao CardView foi adicionada em projeto, porém não comentada e não colocada na versão em artigo?

Um detalhe: se você baixar o projeto no GitHub ele realmente já terá todas as librarias necessárias em projeto, pois a versão em GitHub é a final (ainda passando por pequenos ajustes).

John, é isso.

Aguardo o seu retorno.

Abraço.
Responder