Curso Android – Fragmentos

Neste tutorial vai ser explicada a utilização de fragmentos na aplicação. Mais uma vez, iremos recorrer a ficheiros .xml para nos facilitar a vida. Iremos introduzir o conceito de permissões, visto que iremos precisar para aceder à net. O objetivo deste tutorial é criar uma aplicação de raiz (para isso o leitor pode já começar a criar um novo projeto com uma empty activity) e, ter uma lista dos três clubes grandes de Portugal (Porto, Sporting e Benfica), clicar em um deles e transitar para outro fragmento que me irá dar uma página da wikipédia na minha aplicação.

Ficheiros .xml

O primeiro passo será criar um ficheiro .xml com um array de strings. Para isso, basta criar um novo .xml dentro da pasta “values” com o nome “equipas.xml” como podemos ver a seguir:

ficheiroxml

e, o conteúdo do ficheiro deverá então ser 2 arrays de strings. Um com o nome dos 3 clubes e o outro com os links de onde queremos ir buscar a informação dos mesmos:

<resources>
    <string-array name="equipas">
        <item>FCPorto</item>
        <item>SportingCP</item>
        <item>SLBenfica</item>
    </string-array>
    <string-array name="paginas">
        <item>https://pt.wikipedia.org/wiki/Futebol_Clube_do_Porto</item>
        <item>https://pt.wikipedia.org/wiki/Sport_Lisboa_e_Benfica</item>
        <item>https://pt.wikipedia.org/wiki/Sporting_Clube_de_Portugal</item>
    </string-array>
</resources>

Para mais informação sobre os passos realizados neste capitulo, rever o tutorial anterior aqui.

Fragmentos

Para podermos proceder à criação dos layouts sem erros, teremos de adicionar fragmentos na nossa pasta de código java. Para isso, basta procedermos da seguinte forma (dois passos):

  • Note-se que deverá utilizar os mesmos nomes que no tutorial para evitar erros

Em cima iremos criar um fragment list. Este será um fragmento que terá uma lista. A geração da classe irá gerar código que, todo ele será inútil. A classe deverá ter o seguinte código:

public class ListFragmentLinks extends ListFragment {
    boolean dualFrame;
    int curPosition = 0;

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

        // Creates the list from the array defined in the XML file, using an ArrayAdapter
        setListAdapter(ArrayAdapter.createFromResource(getActivity(),
                R.array.equipas, android.R.layout.simple_list_item_activated_1));

        // Is a frame for details available ?
        View detailsFrame = getActivity().findViewById(R.id.details);

        //Are we in dual frame mode ?
        dualFrame = detailsFrame != null && detailsFrame.getVisibility()
                == View.VISIBLE;
        if (savedInstanceState != null) {
            // Restore the last state for the chosen position
            curPosition = savedInstanceState.getInt("curPosition", 0);
        }
        if (dualFrame) {
            getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
            showDetails(curPosition);
        }
    }
    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("curPosition", curPosition);
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id){
        showDetails(position);
    }

    //Show details for the selected item
    private void showDetails(int index) {
        curPosition = index;

        if (dualFrame) {
            getListView().setItemChecked(index, true);
            // Check which fragment is being shown and modify it if necessary
            ClubesFragment details = (ClubesFragment)
                    getFragmentManager().findFragmentById(R.id.details);
            if (details == null || details.getShownIndex() != index) {
                // Create a new fragment
                details = ClubesFragment.newInstance(index);
                // Replacement transaction
                FragmentTransaction ft =
                        getFragmentManager().beginTransaction();
                ft.replace(R.id.details, details);
                ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
                ft.commit();
            }
        } else {
            // Replace existing fragment with the one instantiated using a factory method
            ClubesFragment details = ClubesFragment.newInstance(index);
            FragmentTransaction ft=getFragmentManager().beginTransaction();

            ft.replace(R.id.links, details);
            ft.addToBackStack("MAIN");
            ft.commit();
        }
    }
}

O leitor deve dar especial atenção às seguintes situações no código:

  • getFragmentManager()
    • Gestor de fragmentos da aplicação
  • FragmentTransaction ft = getFragmentManager().beginTransaction();
    • Prepara transação na aplicação
  • ft.replace(…)
    • irá fazer a substituição de um fragmento por outro
  • ft.setTransition(…)
    • Animação para a transição a ocorrer
  • ft.commit()
    • Faz um commit da transação, passando assim de um fragmento para outro

Para terminar com o capitulo de fragmentos, o utilizador deverá criar agora outro fragment mas, um “Fragment (Blank)” e não um “Fragment (List)” uma vez que não precisamos de uma lista mas sim apenas de um fragmento:

O código da classe terá como objetivo criar uma WebView na nossa aplicação de acordo com o que colocámos no array de strings com o nome “páginas”. Ele irá buscar a página com a informação, neste caso da wikipédia, assim que escolhermos qual a informação do clube que queremos aceder. O código é:

public class ClubesFragment extends Fragment {
    // Create a new Detail Fragment instance
    public static ClubesFragment newInstance(int index) {
        ClubesFragment cdf = new ClubesFragment();
        Bundle args = new Bundle();
        args.putInt("index", index);
        cdf.setArguments(args);
        return cdf;
    }

    public int getShownIndex() {
        return getArguments().getInt("index", 0);
    }

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

        final String[] links = getResources().getStringArray(R.array.paginas);
        ScrollView scroller = new ScrollView(getActivity());
        WebView webview = new WebView(getActivity());
        webview.setWebViewClient(new SwAWebClient());

        int padding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                4, getActivity().getResources().getDisplayMetrics());
        webview.setPadding(padding, padding, padding, padding);
        scroller.addView(webview);
        webview.loadUrl(links[getShownIndex()]);
        return scroller;
    }

    private class SwAWebClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            return false;
        }
    }
}

Layouts

Com a nossa MainActivity criada de forma “limpa”, chega então a parte mais complicada do trabalho. A criação dos layouts. Ao contrário do que temos feito anteriormente, neste tutorial os layouts serão criados manualmente. Ou seja, dentro da pasta layout, realizar o passo que se demonstrou na imagem em cima mas, dentro da pasta “values” e criar um .xml novo com o nome “lands.xml” com o seguinte conteúdo:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent" android:layout_height="match_parent">
    <fragment class="org.blowstuff.fragmentstestetutorial.ListFragmentLinks"
        android:id="@+id/links" android:layout_weight="1"
        android:layout_width="0px" android:layout_height="match_parent" />
    <FrameLayout android:id="@+id/details" android:layout_weight="1"
        android:layout_width="0px" android:layout_height="match_parent" />
</LinearLayout>

Vendo no formato “design”, poderemos ver que foi adicionado um fragmento (que será onde iremos ter links) e, um layout da frame.

No que toca a activity_main.xml, como não poderia deixar de ser, terá de ser alterada. O código é o seguinte:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">
    <fragment class="PACKAGE_NAME.ListFragmentsLinks"
        android:id="@+id/links"
        android:layout_width="match_parent" android:layout_height="match_parent" />
</FrameLayout>

O leitor não deve esquecer de por o nome da package em PACKAGE_NAME.

A aplicação está pronta a correr, ou não?

Permissões

Caso o leitor tenha corrido a aplicação, certamente deverá ter tido um erro no pedido da página web. Isto porque para desenvolver em android é preciso permissões para quase tudo. É necessário o programador especificar no seu android manifest a permissão de que a aplicação pode aceder à internet da seguinte forma (poderá colocar antes da tag “application”):

<uses-permission android:name="android.permission.INTERNET"/>

Fonte das imagens