From 5ed06554cd3241bc1400378815de679adb42299d Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Wed, 11 Jan 2017 23:55:50 +0100 Subject: [PATCH] Change ListPickerYearView as RecyclerView --- .../switchdatetimesample/Sample.java | 2 +- switchdatetime/build.gradle | 1 + .../SwitchDateTimeDialogFragment.java | 4 +- .../date/widget/ListPickerYearView.java | 98 +++++----- .../date/widget/YearPickerAdapter.java | 173 +++++++++++------- 5 files changed, 154 insertions(+), 124 deletions(-) diff --git a/sample/src/main/java/com/kunzisoft/switchdatetimesample/Sample.java b/sample/src/main/java/com/kunzisoft/switchdatetimesample/Sample.java index baf18a9..6f45212 100644 --- a/sample/src/main/java/com/kunzisoft/switchdatetimesample/Sample.java +++ b/sample/src/main/java/com/kunzisoft/switchdatetimesample/Sample.java @@ -57,7 +57,7 @@ protected void onCreate(Bundle savedInstanceState) { dateTimeFragment.set24HoursMode(true); // WARNING 0 <= MONTH <= 11 dateTimeFragment.setMinimumDateTime(new GregorianCalendar(2015, Calendar.JANUARY, 1).getTime()); - dateTimeFragment.setMaximumDateTime(new GregorianCalendar(2030, Calendar.DECEMBER, 31).getTime()); + dateTimeFragment.setMaximumDateTime(new GregorianCalendar(2025, Calendar.DECEMBER, 31).getTime()); dateTimeFragment.setDefaultDateTime(new GregorianCalendar(2017, Calendar.MARCH, 4, 15, 20).getTime()); // Or assign each element, default element is the current moment // dateTimeFragment.setDefaultHourOfDay(15); diff --git a/switchdatetime/build.gradle b/switchdatetime/build.gradle index 05368cd..b0d3eab 100644 --- a/switchdatetime/build.gradle +++ b/switchdatetime/build.gradle @@ -27,6 +27,7 @@ dependencies { exclude group: 'com.android.support', module: 'support-annotations' }) compile 'com.android.support:appcompat-v7:25.1.0' + compile 'com.android.support:recyclerview-v7:25.1.0' compile 'com.prolificinteractive:material-calendarview:1.4.2' testCompile 'junit:junit:4.12' } diff --git a/switchdatetime/src/main/java/com/kunzisoft/switchdatetime/SwitchDateTimeDialogFragment.java b/switchdatetime/src/main/java/com/kunzisoft/switchdatetime/SwitchDateTimeDialogFragment.java index 6a9f46e..fbd412e 100644 --- a/switchdatetime/src/main/java/com/kunzisoft/switchdatetime/SwitchDateTimeDialogFragment.java +++ b/switchdatetime/src/main/java/com/kunzisoft/switchdatetime/SwitchDateTimeDialogFragment.java @@ -289,14 +289,14 @@ public void onYearSelected(View view, int yearPicker) { year = yearPicker; dateTimeCalendar.set(Calendar.YEAR, year); + yearHeaderValues.setText(String.valueOf(year)); + // Unfortunately, we have lags here and thread isn't a solution :/ materialCalendarView.setCurrentDate(dateTimeCalendar.getTime()); materialCalendarView.setDateSelected(dateTimeCalendar, true); // For resolve bug of switch year materialCalendarView.goToNext(); materialCalendarView.goToPrevious(); - - yearHeaderValues.setText(String.valueOf(year)); } }); diff --git a/switchdatetime/src/main/java/com/kunzisoft/switchdatetime/date/widget/ListPickerYearView.java b/switchdatetime/src/main/java/com/kunzisoft/switchdatetime/date/widget/ListPickerYearView.java index 0269359..b940e8d 100644 --- a/switchdatetime/src/main/java/com/kunzisoft/switchdatetime/date/widget/ListPickerYearView.java +++ b/switchdatetime/src/main/java/com/kunzisoft/switchdatetime/date/widget/ListPickerYearView.java @@ -3,15 +3,12 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; -import android.graphics.drawable.StateListDrawable; -import android.os.Build; -import android.support.annotation.RequiresApi; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; +import android.util.Log; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ListView; -import android.widget.TextView; import com.kunzisoft.switchdatetime.R; import com.kunzisoft.switchdatetime.date.OnYearSelectedListener; @@ -24,15 +21,17 @@ * @see com.kunzisoft.switchdatetime.date.OnYearSelectedListener#onYearSelected(View, int) * @author JJamet */ -public class ListPickerYearView extends ListView implements AdapterView.OnItemClickListener { +public class ListPickerYearView extends RecyclerView implements YearPickerAdapter.OnClickYearListener{ + + private final static String TAG = "ListPickerYearView"; private int minYear = 1970; private int maxYear = 2100; private int currentYear; private YearPickerAdapter mAdapter; - private int mChildSize; private OnYearSelectedListener yearChangeListener; + private int mChildSize; private int mViewSize; public ListPickerYearView(Context context) { @@ -48,18 +47,14 @@ public ListPickerYearView(Context context, AttributeSet attrs, int defStyleAttr) init(context, attrs); } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - public ListPickerYearView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - init(context, attrs); - } - private void init(Context context, AttributeSet attrs) { + setLayoutManager(new LinearLayoutManager(context)); + if(attrs != null) { TypedArray yearTypedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ListPickerYearView); setMinYear(yearTypedArray.getInt(R.styleable.ListPickerYearView_minYear, minYear)); setMaxYear(yearTypedArray.getInt(R.styleable.ListPickerYearView_maxYear, minYear)); - currentYear = yearTypedArray.getInt(R.styleable.ListPickerYearView_defaultYear, 2000); + currentYear = yearTypedArray.getInt(R.styleable.ListPickerYearView_defaultYear, YearPickerAdapter.UNDEFINED); yearTypedArray.recycle(); } @@ -72,12 +67,10 @@ private void init(Context context, AttributeSet attrs) { setVerticalFadingEdgeEnabled(true); setFadingEdgeLength(mChildSize / 3); - mAdapter = new YearPickerAdapter(getContext(), currentYear); + mAdapter = new YearPickerAdapter(); setAdapter(mAdapter); - setOnItemClickListener(this); - setSelector(new StateListDrawable()); - setDividerHeight(0); + mAdapter.setOnClickYearListener(this); refreshAndCenter(); } @@ -91,7 +84,7 @@ private void injectYearsInAdapter() { for (int year = minYear; year <= maxYear; year++) { years.add(year); } - mAdapter.replaceYearsBy(years); + mAdapter.setListYears(years); mAdapter.notifyDataSetChanged(); } } @@ -105,51 +98,37 @@ public void refreshAndCenter() { } @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { + public void onItemYearClick(View view, Integer year, int position) { + int positionOldYear = mAdapter.getPositionSelectedYear(); + currentYear = year; + // TODO Vibrate //mController.tryVibrate(); - TextView clickedView = (TextView) view.findViewById(R.id.year_textView); - if (clickedView != null) { - currentYear = getYearFromTextView(clickedView); - if(yearChangeListener != null) { - yearChangeListener.onYearSelected(clickedView, getYearFromTextView(clickedView)); - } + if(yearChangeListener != null) { + yearChangeListener.onYearSelected(view, year); + } + + try { mAdapter.setSelectedYear(currentYear); - mAdapter.notifyDataSetChanged(); + } catch (YearPickerAdapter.SelectYearException e) { + Log.e(TAG, e.getMessage()); } + mAdapter.notifyDataSetChanged(); + mAdapter.notifyItemChanged(positionOldYear); + mAdapter.notifyItemChanged(position); } /** * Center list on the selected year * @param position of year in the list */ - public void centerListOn(int position) { - centerListOnWithTop(position, mViewSize / 2 - mChildSize / 2); - } - - /** - * Center list on the selected year and add y at the top - * @param position of year in the list - * @param y pixels from top - */ - public void centerListOnWithTop(final int position, final int y) { - post(new Runnable() { - public void run() { - setSelectionFromTop(position, y); - requestLayout(); - } - }); - } - - /** - * Get year integer from TextView - * @param view of text - * @return - */ - private static int getYearFromTextView(TextView view) { - if(view == null) - return 0; - return Integer.valueOf(view.getText().toString()); + public void centerListOn(final int position) { + getLayoutManager().scrollToPosition(position); + try { + getLayoutManager().scrollVerticallyBy(mViewSize / 2 - mChildSize / 2, null, null); + } catch(Exception e){ + Log.w(TAG, "Can't scroll more"); + } } /** @@ -208,8 +187,13 @@ public int getYearSelected() { */ public void assignCurrentYear(int year) { currentYear = year; - if(mAdapter != null) - mAdapter.setSelectedYear(currentYear); + if(mAdapter != null) { + try { + mAdapter.setSelectedYear(currentYear); + } catch (YearPickerAdapter.SelectYearException e) { + Log.e(TAG, e.getMessage()); + } + } refreshAndCenter(); } } \ No newline at end of file diff --git a/switchdatetime/src/main/java/com/kunzisoft/switchdatetime/date/widget/YearPickerAdapter.java b/switchdatetime/src/main/java/com/kunzisoft/switchdatetime/date/widget/YearPickerAdapter.java index 9d67b2b..bf973c9 100644 --- a/switchdatetime/src/main/java/com/kunzisoft/switchdatetime/date/widget/YearPickerAdapter.java +++ b/switchdatetime/src/main/java/com/kunzisoft/switchdatetime/date/widget/YearPickerAdapter.java @@ -1,11 +1,9 @@ package com.kunzisoft.switchdatetime.date.widget; -import android.content.Context; -import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.BaseAdapter; import android.widget.TextView; import com.kunzisoft.switchdatetime.R; @@ -17,92 +15,67 @@ * Adapter for manage elements of ListPickerYearView * @author JJamet */ -class YearPickerAdapter extends BaseAdapter { +class YearPickerAdapter extends RecyclerView.Adapter { private static final int LIST_ITEM_TYPE_STANDARD = 0; private static final int LIST_ITEM_TYPE_INDICATOR = 1; - private static final int LIST_ITEM_TYPE_COUNT = 2; + + public static final int UNDEFINED = -1; private List listYears; - private int selectedYear; + private Integer selectedYear; + private int positionSelectedYear; - private LayoutInflater layoutInflater; + private OnClickYearListener onClickYearListener; /** * Initialize adapter with list of years and element selected - * @param context of adapter for layout - * @param selectedYear default year selected */ - YearPickerAdapter(Context context, int selectedYear) { + YearPickerAdapter() { this.listYears = new ArrayList<>(); - this.selectedYear = selectedYear; - this.layoutInflater = LayoutInflater.from(context); + this.selectedYear = UNDEFINED; } - /** - * Replace current list of years by list in parameter - * @param listYears New years - */ - public void replaceYearsBy(List listYears) { - this.listYears.clear(); - this.listYears.addAll(listYears); + @Override + public long getItemId(int i) { + return listYears.get(i); } @Override - public int getCount() { + public int getItemCount() { return listYears.size(); } @Override - public Object getItem(int i) { - return listYears.get(i); + public TextIndicatorViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + switch (viewType) { + default: + case LIST_ITEM_TYPE_STANDARD: + return new TextIndicatorViewHolder( + LayoutInflater.from(parent.getContext()).inflate(R.layout.year_text, parent, false)); + case LIST_ITEM_TYPE_INDICATOR: + return new TextIndicatorViewHolder( + LayoutInflater.from(parent.getContext()).inflate(R.layout.year_text_indicator, parent, false)); + } } @Override - public long getItemId(int i) { - return listYears.get(i); + public void onBindViewHolder(TextIndicatorViewHolder holder, int position) { + Integer currentYear = listYears.get(position); + holder.textView.setText(String.valueOf(currentYear)); + + if(onClickYearListener != null) + holder.container.setOnClickListener(new BufferYearClickListener(currentYear, position)); } @Override public int getItemViewType(int position) { - if(listYears.get(position) == selectedYear) + if(listYears.get(position).equals(selectedYear)) return LIST_ITEM_TYPE_INDICATOR; else return LIST_ITEM_TYPE_STANDARD; } - @Override - public int getViewTypeCount() { - return LIST_ITEM_TYPE_COUNT; - } - - @Override - @NonNull - public View getView(int position, View convertView, @NonNull ViewGroup parent) { - - int type = getItemViewType(position); - TextIndicatorViewHolder holder; - if (convertView == null) { - holder = new TextIndicatorViewHolder(); - switch(type) { - case LIST_ITEM_TYPE_STANDARD: - convertView = layoutInflater.inflate(R.layout.year_text, parent, false); - break; - case LIST_ITEM_TYPE_INDICATOR: - convertView = layoutInflater.inflate(R.layout.year_text_indicator, parent, false); - break; - } - assert convertView != null; - convertView.setTag(holder); - } else { - holder = (TextIndicatorViewHolder) convertView.getTag(); - } - - holder.textView = (TextView) convertView.findViewById(R.id.year_textView); - holder.textView.setText(String.valueOf(listYears.get(position))); - return convertView; - } - /** * Get the list of years * @return years @@ -112,7 +85,7 @@ public List getListYears() { } /** - * Assign tle list of years, replace current list + * Assign the list of years, replace current list * @param listYears */ public void setListYears(List listYears) { @@ -120,7 +93,7 @@ public void setListYears(List listYears) { } /** - * Get the current selected year + * Get the current selected year or value of UNDEFINED if undefined * @return */ public int getSelectedYear() { @@ -129,19 +102,91 @@ public int getSelectedYear() { /** * Assign the current selected year - * @param selectedYear + * @param selectedYear year selected */ - public void setSelectedYear(int selectedYear) { + public void setSelectedYear(int selectedYear) throws SelectYearException { + if(!listYears.contains(selectedYear)) + throw new SelectYearException(selectedYear, listYears); this.selectedYear = selectedYear; + this.positionSelectedYear = listYears.indexOf(selectedYear); + } + + /** + * Get position of selected year or value of UNDEFINED if undefined + * @return + */ + public int getPositionSelectedYear() { + return positionSelectedYear; + } + + /** + * Get the listener called when the year is clicked + * @return + */ + public OnClickYearListener getOnClickYearListener() { + return onClickYearListener; + } + + /** + * Set the listener called when the year is clicked + * @param onClickYearListener + */ + public void setOnClickYearListener(OnClickYearListener onClickYearListener) { + this.onClickYearListener = onClickYearListener; + } + + /** + * Listener when a click on Year item is performed + */ + public interface OnClickYearListener { + /** + * Called on click + * @param view Current view clicked + * @param year Year of current item clicked + * @param position Position of item clicked + */ + void onItemYearClick(View view, Integer year, int position); + } + + private class BufferYearClickListener implements View.OnClickListener { + + private Integer year; + private int position; + + public BufferYearClickListener(Integer yearClicked, int position) { + this.year = yearClicked; + this.position = position; + } + + @Override + public void onClick(View view) { + onClickYearListener.onItemYearClick(view, year, position); + } } /** * Holder for TextIndicatorView */ - private class TextIndicatorViewHolder { + class TextIndicatorViewHolder extends RecyclerView.ViewHolder { /** - * View of year + * Views of year */ - TextView textView; + private ViewGroup container; + private TextView textView; + + TextIndicatorViewHolder(View itemView) { + super(itemView); + container = (ViewGroup) itemView.findViewById(R.id.year_element_container); + textView = (TextView) itemView.findViewById(R.id.year_textView); + } + } + + /** + * Exception class for year selected + */ + public class SelectYearException extends Exception { + SelectYearException(Integer yearSelected, List listYears) { + super("Year selected " + yearSelected + " must be in list of years : " + listYears); + } } }