Como você cria uma tela de demonstração transparente para um aplicativo Android?

105

Estou tentando criar uma tela de demonstração semitransparente que é iniciada apenas quando um usuário instala meu aplicativo pela primeira vez. Aqui está um exemplo do aplicativo Pulse News:

Galaxy Nexus

Captura de tela de exemplo do Pulse News no Galaxy Nexus

Nexus One

insira a descrição da imagem aqui

Em vez de um recurso 'tocar para dispensar', quero que o usuário possa deslizar por algumas dessas páginas de demonstração transparentes.

Para minha primeira tentativa, modifiquei um exemplo da biblioteca ViewPagerIndicator . Usei PNGs semitransparentes em ImageViews dentro de cada um dos fragmentos do pager de visualização. Em seguida, lancei isso como uma 'atividade de demonstração' no método onCreate da minha 'atividade principal'.

Problema: a 'atividade principal' não podia ser vista no fundo - em vez disso, era apenas preto. Tentei as soluções aqui , mas isso não resolveu o problema.

Existe uma abordagem melhor para criar algo assim ou estou no caminho certo?

Eu também tinha outra pergunta relacionada que depende de como isso é implementado. Estou tentando sobrepor o texto e as setas de forma que apontem para componentes de IU específicos no plano de fundo. Ao usar um PNG com texto e setas, é provável que ele não seja dimensionado corretamente em dispositivos diferentes. Ou seja, as setas podem não necessariamente apontar para o componente de IU correto no plano de fundo. Existe uma maneira de resolver esse problema também?

Obrigado!

Este é meu código para a primeira tentativa:

DemoActivity.java

public class DemoActivity extends FragmentActivity {
    DemoFragmentAdapter mAdapter;
    ViewPager mPager;
    PageIndicator mIndicator;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.demo_activity);

        mAdapter = new DemoFragmentAdapter(getSupportFragmentManager());

        mPager = (ViewPager)findViewById(R.id.pager);
        mPager.setAdapter(mAdapter);
        //mPager.setAlpha(0);

        UnderlinePageIndicator indicator = (UnderlinePageIndicator)findViewById(R.id.indicator);
        indicator.setViewPager(mPager);
        indicator.setFades(false);
        mIndicator = indicator;
    }

}

DemoFragmentAdapter.java

class DemoFragmentAdapter extends FragmentPagerAdapter {
    protected static final int[] CONTENT = new int[] { R.drawable.demo1, R.drawable.demo2, R.drawable.demo3, R.drawable.demo4};

    private int mCount = CONTENT.length;

    public DemoFragmentAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        return DemoFragment.newInstance(CONTENT[position % CONTENT.length]);
    }

    @Override
    public int getCount() {
        return mCount;
    }

    public void setCount(int count) {
        if (count > 0 && count <= 10) {
            mCount = count;
            notifyDataSetChanged();
        }
    } }

DemoFragment.java

public final class DemoFragment extends Fragment {
    private static final String KEY_CONTENT = "TestFragment:Content";

    public static DemoFragment newInstance(int content) {
        DemoFragment fragment = new DemoFragment();
        fragment.mContent = content;
        return fragment;
    }

    private int mContent;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if ((savedInstanceState != null) && savedInstanceState.containsKey(KEY_CONTENT)) {
            mContent = savedInstanceState.getInt(KEY_CONTENT);
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        ImageView image = new ImageView(getActivity());
        image.setBackgroundResource(mContent);

        LinearLayout layout = new LinearLayout(getActivity());
        layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        layout.setGravity(Gravity.CENTER);
        layout.addView(image);

        return layout;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(KEY_CONTENT, mContent);
    }
}
Gautam
fonte
Sem olhar para o seu código, é difícil sugerir qualquer coisa. Se você pudesse colocar seu código de atividade, isso poderia ajudar.
Sayyam
11
Esta é uma boa pergunta.
con_9

Respostas:

79

Coloque suas informações de demonstração em uma atividade diferente e dê a ela o seguinte tema.

<style name="Transparent" parent="@android:style/Theme.NoTitleBar">
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowNoTitle">true</item>      
    <item name="android:backgroundDimEnabled">false</item>
</style>

Se você estiver usando ActionBarSherlock, mude parentpara @style/Theme.Sherlock.

Isso lhe dará uma atividade transparente, para que você possa ver a atividade abaixo dela.

Agora, suponho que você também queira um fundo translúcido.

No layout xml (de sua atividade transparente), adicione:

android:background="#aa000000" 

Os últimos 6 dígitos definem a cor: 000000 é preto.

Os 2 primeiros definem a opacidade: 00 é 100% transparente, ff é 100% opaco. Portanto, escolha algo intermediário.

Benito Bertoli
fonte
1
Obrigado pela resposta! Foi basicamente isso que acabei fazendo, depois de muitas tentativas e erros . Ainda estou curioso para saber como a tela de demonstração do Pulse é capaz de 'reposicionar' o conteúdo sobreposto nos lugares certos, mesmo em tamanhos de tela diferentes - veja as imagens atualizadas. Alguma ideia?
Gautam
2
Em sua primeira atividade, encontre a vista para a qual deseja apontar ( findViewById). Em seguida, obtenha sua posição em relação ao layout raiz usando este método . Envie a posição para a atividade de sobreposição na intent. Faça o alinhamento adequado.
Benito Bertoli
2
Ou use View.getLocationOnScreen(int[] location)ou View.getLocationInWindow(int[] location). Não tenho certeza de qual é o melhor.
Benito Bertoli
@Gautam: "Alguma ideia?" - para o Pulse, é uma questão de colocar uma imagem no canto superior esquerdo, outra imagem centralizada e uma terceira imagem no canto inferior direito. Uma dúzia ou mais de linhas de XML, com base em um RelativeLayout, seriam suficientes.
CommonsWare
1
Isso funcionou para mim, mas tive problemas em minhas atividades fazendo atividades estendidas. Portanto, para usar AppCompatActivity, defini o estilo assim: <style name = "Transparent" parent = "Theme.AppCompat"> <item name = "android: windowContentOverlay"> @ null </item> <item name = "android : windowIsTranslucent "> true </item> <item name =" android: windowBackground "> @ android: color / transparent </item> <item name =" android: windowNoTitle "> true </item> <item name =" android : backgroundDimEnabled "> false </item> </style>
Jose Q
65

Você já deu uma olhada no ShowcaseView? https://github.com/Espiandev/ShowcaseView .

Usando isto:

View showcasedView = findViewById(R.id.view_to_showcase);
ViewTarget target = new ViewTarget(showcasedView);
ShowcaseView.insertShowcaseView(target, this, R.string.showcase_title, R.string.showcase_details);
Nik
fonte
1
Obrigado, isso é exatamente o que eu estava procurando.
Snicolas
Impressionante! Você conhece algo semelhante para iOS?
KVISH
Ainda obsoleto ... Desenvolvedor significava que o design da API básica não era bom o suficiente (o que era parcialmente verdadeiro).
Laurent Meyer
Tentei fazer isso e descobri que não há tag para alterar imagens.
Anshul Tyagi
11

O Pulse está usando um RelativeLayout com quatro ImageViews e quatro TextViews. O texto na captura de tela é todo TextView com sua própria fonte personalizada.

Em seu Manifesto, adicione o seguinte à sua Atividade:

android: theme = "@ style / Theme.Transparent">

Em seu RelativeLayout externo, adicione:

android: background = "# aa000000"

Para seu arquivo styles.xml:

<style name="Theme.Transparent" parent="android:Theme">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowIsFloating">false</item>
    <item name="android:backgroundDimEnabled">false</item>
</style>    

Um exemplo de como programar a fonte personalizada pode ser encontrado em:

https://github.com/commonsguy/cw-android/tree/master/Fonts/FontSampler/

O layout do Hierarchy Viewer é assim (a caixa vermelha é o contêiner RelativeLayout):

insira a descrição da imagem aqui

pó 366
fonte
6
setContentView(R.layout.sample_main);
showOverLay();

private void showOverLay(){

    final Dialog dialog = new Dialog(context, android.R.style.Theme_Translucent_NoTitleBar);

    dialog.setContentView(R.layout.transparent);

    RelativeLayout layout = (RelativeLayout) dialog.findViewById(R.id.transparent);

    layout.setOnClickListener(new View.OnClickListener() {

        @Override

        public void onClick(View arg0) {

            dialog.dismiss();

        }

    });

    dialog.show();

}
Ravikiran
fonte
exatamente o que eu procuro simples e direto, e facilmente chamada de método sem controlar ou empilhar atividades. obrigado
Abhishek Garg
5

Para isso, você precisa criar um layout de ajuda na parte inferior de seu layout principal, ex: (estrutura)

<Parent layout>

<Layout 1>(Linear,Relative,....)
  Main layout
  your view...
</Layout 1>

<Layout help>
  set #70000000 as background of this layout 
  #70(transparent range can change) 000000(black)
  and height and width as fillparent
</Layout help>

</Parent layout>
Surendar D
fonte
2

Envolva seu layout principal em um e RelativeLayout, em seguida, adicione um segundo layout a ele, algo como:

<RelativeLayout
    .... >

    <LinearLayout
        .... >

        <!-- Contents of your main layout -->

    </LinearLayout>

    <LinearLayout
        ....
        android:background="#44000000" > <!-- This is alpha 68/255, black -->

        <!-- Contents of your overlay layout -->

    </LinearLayout>

</RelativeLayout>

Eu acredito que o layout de sobreposição fica abaixo do layout principal no arquivo XML (se a memória não for suficiente). Você pode então fazer seu próprio layout ViewFlipper, o que quiser dentro deste segundo layout.

Eric
fonte
1
Obrigado pela sua resposta! Eu tentei isso e parece funcionar. No entanto, há um problema - o conteúdo no layout de sobreposição não cobre a ActionBar ou as guias da ActionBar que tenho em minha atividade.
Gautam
Você adicionou o RelativeLayoutao demo_activity.xmlarquivo? E é o DemoActivityseu principal (primeiro) Activity?
Eric
Bem, 'DemoActivity' foi minha tentativa de criar uma atividade transparente que faria a mesma coisa. 'MainActivity' é a atividade que desejo em segundo plano. Então eu envolvi o layout para 'MainActivity', ou seja, 'main_activity.xml' com o 'RelativeLayout' como você mencionou e também inseri o 'LinearLayout' transparente. O problema é que todo o conteúdo em 'main_activity.xml' é mostrado abaixo da 'ActionBar' e qualquer uma de suas guias de navegação.
Gautam
1

Faça uma nova atividade (digamos Tutorial).

Vá para o arquivo xml de layout de sua atividade (activity_tutorial). No layout pai, adicione "android: background = # 000" e "android: alpha =" 0,5 "

<RelativeLayout 
    
    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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
                
                
    tools:context=".Tutorial_Activity" 
    android:background="#000"
    android:alpha="0.5">
  ..................................................
  ....................................................
  .............................................
  ...............................................
  
  </RelativeLayout>

Agora, vá para o arquivo de manifesto do aplicativo e, em sua atividade de tutorial, adicione o atributo android: theme = "@ android: style / Theme.Translucent.NoTitleBar">

<application>
 .........................................
..........................................
....................................
..........................................

<activity
            android:name="com.aird.airdictionary.Tutorial_Activity"
            android:label="@string/title_activity_tutorial"
            
          android:theme="@android:style/Theme.Translucent.NoTitleBar">
  
        </activity>
    </application>

</manifest>

É isso, agora execute esta atividade em cima de qualquer outra atividade e você pode obter os resultados desejados. Personalize, adicione texto, visualizações de imagens e outras coisas para obter a tela do tutorial desejada. Certeza de que você pode fazer um visualizador trabalhar com essa técnica.

Ankush Wadhwa
fonte
0

Você pode simplesmente verificar o código do iniciador Android, enquanto eles fazem isso. Não sei lá implementação.

Se fosse comigo, eu faria (se apenas uma simples sobreposição) para que você não estrague o layout do seu aplicativo, apenas crie seu layout de sobreposição e anexe-o ao layout do aplicativo adicionando-o diretamente com suas atividades WindowManager. Pode ser tão simples como adicionar um ImageViewao WindowManager, ouvir toques no ImageViewou solicitar um tempo limite para remover o ImageViewde seu Window.

Jug6ernaut
fonte