Merge pull request #2 from stefan-niedermann/RecyclerView

Recycler view
This commit is contained in:
HeaDBanGer 2016-01-21 10:08:36 +01:00
commit 795be4889a
17 changed files with 278 additions and 128 deletions

View file

@ -73,8 +73,11 @@
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/design/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/gridlayout-v7/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.commit451/bypasses/1.0.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-appindexing/8.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-basement/8.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
@ -87,6 +90,9 @@
</content>
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="play-services-basement-8.1.0" level="project" />
<orderEntry type="library" exported="" name="recyclerview-v7-23.0.1" level="project" />
<orderEntry type="library" exported="" name="play-services-appindexing-8.1.0" level="project" />
<orderEntry type="library" exported="" name="gridlayout-v7-23.0.1" level="project" />
<orderEntry type="library" exported="" name="bypasses-1.0.1" level="project" />
<orderEntry type="library" exported="" name="support-v4-23.0.1" level="project" />

View file

@ -25,5 +25,7 @@ dependencies {
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:gridlayout-v7:23.0.1'
compile 'com.android.support:design:23.0.1'
compile 'com.android.support:recyclerview-v7:23.0.1'
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.google.android.gms:play-services-appindexing:8.1.0'
}

View file

@ -93,5 +93,10 @@
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<!-- ATTENTION: This was auto-generated to add Google Play services to your project for
App Indexing. See https://g.co/AppIndexing/AndroidStudio for more information. -->
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"/>
</application>
</manifest>

View file

@ -7,14 +7,12 @@ import android.preference.PreferenceManager;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.view.ActionMode;
import android.util.SparseBooleanArray;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.Calendar;
@ -29,7 +27,7 @@ import it.niedermann.owncloud.notes.persistence.NoteSQLiteOpenHelper;
import it.niedermann.owncloud.notes.util.ICallback;
public class NotesListViewActivity extends AppCompatActivity implements
OnItemClickListener, View.OnClickListener {
ItemAdapter.NoteClickListener, View.OnClickListener {
public final static String SELECTED_NOTE = "it.niedermann.owncloud.notes.clicked_note";
public final static String CREATED_NOTE = "it.niedermann.owncloud.notes.created_notes";
@ -41,7 +39,7 @@ public class NotesListViewActivity extends AppCompatActivity implements
private final static int server_settings = 2;
private final static int about = 3;
private ListView listView = null;
private RecyclerView listView = null;
private ItemAdapter adapter = null;
private ActionMode mActionMode;
private SwipeRefreshLayout swipeRefreshLayout = null;
@ -171,44 +169,10 @@ public class NotesListViewActivity extends AppCompatActivity implements
}
adapter = new ItemAdapter(getApplicationContext(), itemList);
listView = (ListView) findViewById(R.id.list_view);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
ItemAdapter.setNoteClickListener(this);
listView = (RecyclerView) findViewById(R.id.list_view);
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
listView.setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
onListItemSelect(position);
return true;
}
});
}
/**
* A short click on one list item. Creates a new instance of NoteActivity.
*/
@Override
public void onItemClick(AdapterView<?> parentView, View childView,
int position, long id) {
Item item = adapter.getItem(position);
if (!item.isSection()) {
listView.setItemChecked(position, !listView.isItemChecked(position));
if (listView.getCheckedItemCount() < 1) {
removeSelection();
Intent intent = new Intent(getApplicationContext(),
NoteActivity.class);
if (!item.isSection()) {
intent.putExtra(SELECTED_NOTE, (Note) item);
intent.putExtra(SELECTED_NOTE_POSITION, position);
startActivityForResult(intent, show_single_note_cmd);
}
} else { // perform long click if already something is selected
onListItemSelect(position);
}
} else {
listView.setItemChecked(position, false);
}
listView.setLayoutManager(new LinearLayoutManager(this));
}
/**
@ -261,7 +225,7 @@ public class NotesListViewActivity extends AppCompatActivity implements
if (resultCode == RESULT_OK) {
Note createdNote = (Note) data.getExtras().getSerializable(
CREATED_NOTE);
adapter.insert(createdNote, 0);
adapter.add(createdNote);
}
} else if (requestCode == show_single_note_cmd) {
if (resultCode == RESULT_OK || resultCode == RESULT_FIRST_USER) {
@ -271,7 +235,7 @@ public class NotesListViewActivity extends AppCompatActivity implements
if (resultCode == RESULT_OK) {
Note editedNote = (Note) data.getExtras().getSerializable(
NoteActivity.EDIT_NOTE);
adapter.insert(editedNote, 0);
adapter.add(editedNote);
}
}
} else if (requestCode == server_settings) {
@ -287,16 +251,18 @@ public class NotesListViewActivity extends AppCompatActivity implements
}
}
/**
* Long click on one item in the list view. It starts the Action Mode and allows selecting more
* items and execute bulk functions (e. g. delete)
*
* @param position int - position of the clicked item
*/
private void onListItemSelect(int position) {
if (!adapter.getItem(position).isSection()) {
listView.setItemChecked(position, !listView.isItemChecked(position));
int checkedItemCount = listView.getCheckedItemCount();
@Override
public void onNoteClick(int position, View v) {
if (mActionMode != null) {
if (!adapter.select(position)) {
v.setSelected(false);
adapter.deselect(position);
} else {
v.setSelected(true);
}
mActionMode.setTitle(String.valueOf(adapter.getSelected().size())
+ " " + getString(R.string.ab_selected));
int checkedItemCount = adapter.getSelected().size();
boolean hasCheckedItems = checkedItemCount > 0;
if (hasCheckedItems && mActionMode == null) {
@ -312,25 +278,34 @@ public class NotesListViewActivity extends AppCompatActivity implements
// there no selected items, finish the actionMode
mActionMode.finish();
}
if (mActionMode != null) {
mActionMode.setTitle(String.valueOf(listView.getCheckedItemCount())
+ " " + getString(R.string.ab_selected));
}
} else {
listView.setItemChecked(position, false);
Intent intent = new Intent(getApplicationContext(),
NoteActivity.class);
Item item = adapter.getItem(position);
intent.putExtra(SELECTED_NOTE, (Note) item);
intent.putExtra(SELECTED_NOTE_POSITION, position);
Log.v("Note",
"notePosition | NotesListViewActivity wurde abgesendet "
+ position);
startActivityForResult(intent, show_single_note_cmd);
}
}
/**
* Removes all selections.
*/
private void removeSelection() {
SparseBooleanArray checkedItemPositions = listView
.getCheckedItemPositions();
for (int i = 0; i < checkedItemPositions.size(); i++) {
listView.setItemChecked(i, false);
@Override
public boolean onNoteLongClick(int position, View v) {
boolean selected = adapter.select(position);
if (selected) {
v.setSelected(selected);
mActionMode = startSupportActionMode(new MultiSelectedActionModeCallback());
int checkedItemCount = adapter.getSelected().size();
mActionMode.setTitle(String.valueOf(checkedItemCount)
+ " " + getString(R.string.ab_selected));
}
return selected;
}
/**
@ -361,15 +336,11 @@ public class NotesListViewActivity extends AppCompatActivity implements
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_delete:
SparseBooleanArray checkedItemPositions = listView
.getCheckedItemPositions();
for (int i = (checkedItemPositions.size() - 1); i >= 0; i--) {
if (checkedItemPositions.valueAt(i)) {
Note note = (Note) adapter.getItem(checkedItemPositions
.keyAt(i));
db.deleteNoteAndSync(note.getId());
adapter.remove(note);
}
List<Integer> selection = adapter.getSelected();
for (Integer i : selection) {
Note note = (Note) adapter.getItem(i);
db.deleteNoteAndSync(note.getId());
adapter.remove(note);
}
mode.finish(); // Action picked, so close the CAB
return true;
@ -380,7 +351,7 @@ public class NotesListViewActivity extends AppCompatActivity implements
@Override
public void onDestroyActionMode(ActionMode mode) {
removeSelection();
adapter.clearSelection();
mActionMode = null;
adapter.notifyDataSetChanged();
}

View file

@ -5,9 +5,10 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.RemoteViews;
import java.util.ArrayList;
@ -28,7 +29,7 @@ public class SelectSingleNoteActivity extends AppCompatActivity implements Adapt
int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
private NoteSQLiteOpenHelper db = null;
private ListView listView = null;
private RecyclerView listView = null;
private ItemAdapter adapter = null;
@Override
@ -65,10 +66,10 @@ public class SelectSingleNoteActivity extends AppCompatActivity implements Adapt
List<Item> itemList = new ArrayList<>();
itemList.addAll(noteList);
adapter = new ItemAdapter(getApplicationContext(), itemList);
listView = (ListView) findViewById(R.id.select_single_note_list_view);
listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
listView = (RecyclerView) findViewById(R.id.select_single_note_list_view);
listView.setAdapter(adapter);
listView.setOnItemClickListener(this);
listView.setLayoutManager(new LinearLayoutManager(this));
//httpslistView.setOnItemClickListener(this);
}
@Override

View file

@ -1,67 +1,169 @@
package it.niedermann.owncloud.notes.model;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import it.niedermann.owncloud.notes.R;
public class ItemAdapter extends ArrayAdapter<Item> {
public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
/**
* Sections and Note-Items
*/
private static final int count_types = 2;
private static final int section_type = 0;
private static final int note_type = 1;
private static NoteClickListener noteClickListener;
private List<Item> itemList = null;
private List<Integer> selected = null;
public ItemAdapter(Context context, List<Item> itemList) {
super(context, android.R.layout.simple_list_item_1, itemList);
//super(context, android.R.layout.simple_list_item_1, itemList);
super();
this.itemList = itemList;
this.selected = new ArrayList<>();
}
public static void setNoteClickListener(NoteClickListener noteClickListener) {
ItemAdapter.noteClickListener = noteClickListener;
}
public void add(Note createdNote) {
//TODO sort createdNote to first position
this.add(createdNote);
itemList.add(createdNote);
}
// Create new views (invoked by the layout manager)
@Override
public View getView(int position, View convertView, ViewGroup parent) {
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent,
int viewType) {
View v;
if (viewType == section_type) {
v = LayoutInflater.from(parent.getContext()).inflate(R.layout.fragment_notes_list_section_item, parent, false);
return new SectionViewHolder(v);
} else {
v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.fragment_notes_list_note_item, parent, false);
// set the view's size, margins, paddings and layout parameters
// ...
//TODO
return new NoteViewHolder(v);
}
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
// - get element from your dataset at this position
// - replace the contents of the view with that element
Item item = itemList.get(position);
if (item.isSection()) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.fragment_notes_list_section_item, null);
}
SectionItem section = (SectionItem) item;
TextView sectionTitle = (TextView) convertView.findViewById(R.id.sectionTitle);
if (sectionTitle != null) {
sectionTitle.setText(section.geTitle());
}
((SectionViewHolder) holder).sectionTitle.setText(section.geTitle());
((SectionViewHolder) holder).setPosition(position);
} else {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.fragment_notes_list_note_item, null);
}
Note note = (Note) item;
((TextView) convertView.findViewById(R.id.noteTitle)).setText(note.getTitle());
((TextView) convertView.findViewById(R.id.noteExcerpt)).setText(note.getExcerpt());
((NoteViewHolder) holder).noteTitle.setText(note.getTitle());
((NoteViewHolder) holder).noteExcerpt.setText(note.getExcerpt());
((NoteViewHolder) holder).setPosition(position);
}
return convertView;
}
/**
* @return count_types
*/
public boolean select(Integer position) {
return !selected.contains(position) && selected.add(position);
}
public void clearSelection() {
selected.clear();
}
public List<Integer> getSelected() {
return selected;
}
public boolean deselect(Integer position) {
for (int i = 0; i < selected.size(); i++) {
if (selected.get(i) == position) {
//position was selected and removed
selected.remove(i);
return true;
}
}
// position was not selected
return false;
}
public Item getItem(int notePosition) {
return itemList.get(notePosition);
}
public void remove(Item item) {
itemList.remove(item);
}
@Override
public int getViewTypeCount() {
return count_types;
public int getItemCount() {
return itemList.size();
}
@Override
public int getItemViewType(int position) {
return getItem(position).isSection() ? section_type : note_type;
}
public interface NoteClickListener {
void onNoteClick(int position, View v);
boolean onNoteLongClick(int position, View v);
}
public static class NoteViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener, View.OnClickListener {
// each data item is just a string in this case
public TextView noteTitle;
public TextView noteExcerpt;
public int position = -1;
private NoteViewHolder(View v) {
super(v);
this.noteTitle = (TextView) v.findViewById(R.id.noteTitle);
this.noteExcerpt = (TextView) v.findViewById(R.id.noteExcerpt);
v.setOnClickListener(this);
v.setOnLongClickListener(this);
}
public void setPosition(int pos) {
position = pos;
}
@Override
public void onClick(View v) {
noteClickListener.onNoteClick(position, v);
}
@Override
public boolean onLongClick(View v) {
return noteClickListener.onNoteLongClick(position, v);
}
}
public static class SectionViewHolder extends RecyclerView.ViewHolder {
public TextView sectionTitle;
public int position = -1;
private SectionViewHolder(View v) {
super(v);
this.sectionTitle = (TextView) v.findViewById(R.id.sectionTitle);
}
public void setPosition(int pos) {
position = pos;
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -2,6 +2,6 @@
<!-- Selector is used for Background Colors in List Items -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- :selected -->
<item android:drawable="@color/bg_highlighted" android:state_activated="true"/>
<item android:drawable="@color/bg_highlighted" android:state_selected="true"/>
<item android:drawable="@color/bg_normal"/>
</selector>

View file

@ -1,24 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout
android:id="@+id/createContentContainer"
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="it.niedermann.owncloud.notes.android.activity.CreateNoteActivity"
android:id="@+id/createContentContainer"
android:weightSum="1">
android:weightSum="1"
tools:context="it.niedermann.owncloud.notes.android.activity.CreateNoteActivity">
<ScrollView
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/scrollView">
android:layout_height="match_parent">
<EditText
android:id="@+id/createContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textMultiLine" />
android:inputType="textMultiLine"
android:padding="16dp"/>
</ScrollView>
</LinearLayout>

View file

@ -13,11 +13,12 @@
tools:context="it.niedermann.owncloud.notes.android.activity.NotesListViewActivity"
tools:ignore="MergeRootFrame">
<ListView
<android.support.v7.widget.RecyclerView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</ListView>
android:layout_height="wrap_content"
android:background="@color/fg_default_high">
</android.support.v7.widget.RecyclerView>
</android.support.v4.widget.SwipeRefreshLayout>
<android.support.design.widget.FloatingActionButton

View file

@ -5,8 +5,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
<android.support.v7.widget.RecyclerView
android:id="@+id/select_single_note_list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
android:layout_height="wrap_content"
android:divider="#00ffffff"
android:dividerHeight="0dp">
</android.support.v7.widget.RecyclerView>
</LinearLayout>

View file

@ -1,9 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/noteItem"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:layout_height="wrap_content"
android:layout_marginTop="1px"
android:background="@drawable/list_item_background_selector"
android:padding="16dp">

View file

@ -3,7 +3,8 @@
android:id="@+id/sectionItem"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:layout_height="wrap_content"
android:layout_marginTop="1px"
android:background="@color/bg_highlighted"
android:padding="8dp">

55
ic_launcher.svg Normal file
View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
enable-background="new 0 0 595.275 311.111"
xml:space="preserve"
height="512"
width="512"
version="1.1"
y="0px"
x="0px"
id="svg2"
viewBox="0 0 512 512"
inkscape:version="0.91 r13725"
sodipodi:docname="favicon-touch.svg"><metadata
id="metadata10"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs8" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1148"
id="namedview6"
showgrid="false"
inkscape:zoom="0.65230601"
inkscape:cx="253.31531"
inkscape:cy="283.89389"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg2" /><rect
rx="70"
ry="70"
height="448"
width="448"
y="32"
x="32"
id="rect4"
style="fill:#1d2d44" /><path
inkscape:connector-curvature="0"
style="fill:#ffffff"
d="M 136.71428,89.002394 C 110.28057,89.002394 89,110.28284 89,136.71635 l 0,238.56968 C 89,401.71959 110.28057,423 136.71428,423 l 238.57144,0 C 401.71944,423 423,401.71959 423,375.28603 l 0,-199.43234 -10.80728,10.81675 -63.00672,-63.00385 34.67634,-34.666586 -247.14806,0 z m 188.61457,58.523546 63.00671,63.00384 -99.16221,99.14953 -104.74478,41.74972 41.75,-104.74403 99.15028,-99.15906 z m -88.343,109.59648 -31.68228,52.55689 20.875,20.87485 52.55728,-31.68206 -41.75,-41.74968 z"
id="path4" /></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB