Tecnologías Móviles
clase 11
Ejercicio de la clase anterior
Menu Principal
Menú Contextual
Búsqueda
Ejercicio de la clase anterior
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.agustin.ej6.MainActivity">
<item
android:id="@+id/action_search"
android:orderInCategory="1"
android:title="@string/search"
android:icon="@android:drawable/ic_menu_search"
app:showAsAction="ifRoom"
/>
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
app:showAsAction="never" />
</menu>
/res/menu/menu_main.xml
Ejercicio de la clase anterior
MainActivity
public class MainActivity extends AppCompatActivity {
...
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
...
} else if(id == R.id.action_search) {
SearchFragment search = new SearchFragment();
if(isPort) {
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.container, search);
transaction.addToBackStack("search");
transaction.commit();
} else {
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.listContainer, search);
transaction.replace(R.id.formContainer, null);
transaction.addToBackStack("search");
transaction.commit();
}
}
return super.onOptionsItemSelected(item);
}
}
Ejercicio de la clase anterior
SearchFragment
public class SearchFragment extends Fragment {
...
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final UserDBHelper udb = UserDBHelper.getInstance(getActivity());
View root = inflater.inflate(R.layout.fragment_search, container, false);
EditText search = (EditText) root.findViewById(R.id.search);
ListView list = (ListView) root.findViewById(R.id.searchList);
list.setAdapter(SearchAdapter.getInstance().setContext(getActivity()));
search.addTextChangedListener(new TextWatcher() {
...
public void afterTextChanged(Editable s) {
if (s.length() > 0) {
JSONArray searchResult = udb.search(s.toString());
SearchAdapter.getInstance().setData(searchResult);
} else {
SearchAdapter.getInstance().setData(new JSONArray());
}
}
});
return root;
}
}
Ejercicio de la clase anterior
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.agustin.ej6.MainActivity">
<item
android:id="@+id/menu_delete"
android:icon="@android:drawable/ic_menu_delete"
android:title="@string/delete"
app:showAsAction="always"/>
</menu>
/res/menu/context.xml
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
...
<item name="windowActionModeOverlay">true</item>
</style>
...
</resources>
/res/values/styles.xml
Ejercicio de la clase anterior
ListFragment
public class ListFragment extends Fragment {
...
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
list.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
public void onItemCheckedStateChanged(ActionMode mode, int position,
long id, boolean checked) {
int c = list.getCheckedItemCount();
mode.setTitle(c > 1 ? c + " Seleccionados" : c + " Seleccionado");
}
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_delete:
SparseBooleanArray checked = list.getCheckedItemPositions();
UserDBHelper.getInstance(getActivity()).deleteItems(checked);
mode.finish(); // Action picked, so close the CAB
return true;
default:
return false;
}
}
...
});
return root;
}
}
Ejercicio de la clase anterior
ListFragment
public class ListFragment extends Fragment {
...
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
list.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
list.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
...
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.context, menu);
return true;
}
public void onDestroyActionMode(ActionMode mode) {}
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
});
return root;
}
}
Ejercicio de la clase anterior
UserDBHelper
public class UserDBHelper extends SQLiteOpenHelper {
...
public void deleteItems(SparseBooleanArray checked) {
ArrayList<JSONObject> items = new ArrayList<JSONObject>();
for (int i = 0; i < checked.size(); i++) {
int position = checked.keyAt(i);
items.add(read(position));
}
for(JSONObject item:items) {
doDelete(item);
}
UserAdapter.getInstance().notifyDataSetChanged();
}
private void doDelete(JSONObject user) {
SQLiteDatabase db = this.getWritableDatabase();
String selection = UserContract.UserTable._ID+" = ?";
String[] args = {user.optString("_id")};
db.delete(UserContract.UserTable.TABLE_NAME, selection, args);
if(mService != null) {
try {
user.put("_id", user.getString(UserContract.UserTable.MONGO_ID));
user.remove("mongo_id");
mService.mBinder.rmUser(user);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
...
}
ViewPager
Es un Layout que permite a los usuarios pasar páginas en dirección horizontal
Para generar las páginas, se debe proveer una clase que extienda a PagerAdapter
Generalmente se utiliza en conjunto con Fragments, por eso existen clases estanda de adapters:
- FragmentPagerAdapter: Generalmente utilizado para un número finito de Fragments.
- FragmentStatePagerAdapter: Generalmente utilizado para cuando la cantidad de fragments se determina en runtime.
Proveer Swipe Navigation
1. Agregar un ViewPager dentro del Layout
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
2. Incluir un TabLayout en el Layout
<android.support.design.widget.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tab"/>
Proveer Swipe Navigation
3. Crear una clase que extienda a PagerAdapter
public class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {
public DemoCollectionPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int i) {
...
return fragment;
}
@Override
public int getCount() {
return 100;
}
@Override
public CharSequence getPageTitle(int position) {
return "OBJECT " + (position + 1);
}
}
Proveer Swipe Navigation
4. Asignar el Adapter al ViewPager y asociar el ViewPager con el TabLayout
public void onCreate(Bundle savedInstanceState) {
...
mDemoCollectionPagerAdapter =
new DemoCollectionPagerAdapter(
getSupportFragmentManager());
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mDemoCollectionPagerAdapter);
TabLayout tab = (TabLayout) findViewById(R.id.tab);
tab.setupWithViewPager(mViewPager);
}
Ejercicio
Basado en el ejercicio de la clase anterior, realizar los siguientes puntos teniendo en cuenta la base a donde apunta la api (http://tm5-agmoyano.rhcloud.com/):
- Agregar en las preferencias de la aplicación un mail con el cual se va a hacer login (POST /login con {"mail": "<mail usuario>"} como body)
- Agregar un tab donde se van a mostrar los chats del usuario logueado (GET /chat)
- Cuando se hace click en una persona, en vez de editar, se debería abrir un fragment con mensajes del chat (GET /chat/<id chat>/message).
- Si no existe un chat con dicha persona, se debe crear uno (POST /chat con {"to": "<id de usuario a chatear>"} como body), para luego mostrar mensajes.
Ejercicio
- El fragment del chat debería contener un EditText en donde agrego el mensaje, y un botón "enviar" para agregar mensajes al chat (POST /chat/<id de chat>/message con {"message": "<texto del mensaje>"} como body)
Tecnologías Móviles - Clase 11
By Agustin Moyano
Tecnologías Móviles - Clase 11
- 681