mirror of https://github.com/ThmmyNoLife/mTHMMY
Thodoris Tyrovouzis
5 years ago
12 changed files with 390 additions and 311 deletions
@ -0,0 +1,263 @@ |
|||
package gr.thmmy.mthmmy.pagination; |
|||
|
|||
import android.annotation.SuppressLint; |
|||
import android.content.Context; |
|||
import android.graphics.Rect; |
|||
import android.os.Handler; |
|||
import android.util.AttributeSet; |
|||
import android.view.LayoutInflater; |
|||
import android.view.MotionEvent; |
|||
import android.view.View; |
|||
import android.widget.ImageButton; |
|||
import android.widget.LinearLayout; |
|||
import android.widget.TextView; |
|||
|
|||
import androidx.annotation.Nullable; |
|||
|
|||
import gr.thmmy.mthmmy.R; |
|||
|
|||
public class BottomPaginationView extends LinearLayout { |
|||
|
|||
/** |
|||
* Holds the initial time delay before a click on bottom navigation bar is considered long |
|||
*/ |
|||
private final long INITIAL_DELAY = 500; |
|||
private boolean autoIncrement = false; |
|||
private boolean autoDecrement = false; |
|||
/** |
|||
* Holds the number of pages to be added or subtracted from current page on each step while a |
|||
* long click is held in either next or previous buttons |
|||
*/ |
|||
private static final int SMALL_STEP = 1; |
|||
/** |
|||
* Holds the number of pages to be added or subtracted from current page on each step while a |
|||
* long click is held in either first or last buttons |
|||
*/ |
|||
private static final int LARGE_STEP = 10; |
|||
/** |
|||
* Used for handling bottom navigation bar's buttons long click user interactions |
|||
*/ |
|||
private final Handler repeatUpdateHandler = new Handler(); |
|||
|
|||
private ImageButton firstPage, previousPage, nextPage, lastPage; |
|||
private TextView pageIndicator; |
|||
|
|||
private int onDownPageIndex, indicatorPageIndex, totalPageCount; |
|||
|
|||
private OnPageRequestedListener onPageRequestedListener; |
|||
|
|||
public interface OnPageRequestedListener { |
|||
void onPageRequested(int index); |
|||
} |
|||
|
|||
public BottomPaginationView(Context context) { |
|||
this(context, null); |
|||
} |
|||
|
|||
public BottomPaginationView(Context context, @Nullable AttributeSet attrs) { |
|||
super(context, attrs); |
|||
|
|||
LayoutInflater inflater = LayoutInflater.from(context); |
|||
inflater.inflate(R.layout.pagination, this, true); |
|||
|
|||
firstPage = findViewById(R.id.page_first_button); |
|||
previousPage = findViewById(R.id.page_previous_button); |
|||
pageIndicator = findViewById(R.id.page_indicator); |
|||
nextPage = findViewById(R.id.page_next_button); |
|||
lastPage = findViewById(R.id.page_last_button); |
|||
|
|||
initDecrementButton(firstPage, LARGE_STEP); |
|||
initDecrementButton(previousPage, SMALL_STEP); |
|||
initIncrementButton(nextPage, SMALL_STEP); |
|||
initIncrementButton(lastPage, LARGE_STEP); |
|||
} |
|||
|
|||
public void setOnPageRequestedListener(OnPageRequestedListener onPageRequestedListener) { |
|||
this.onPageRequestedListener = onPageRequestedListener; |
|||
} |
|||
|
|||
public boolean setIndicatedPageIndex(int index) { |
|||
if (index != indicatorPageIndex) { |
|||
this.indicatorPageIndex = index; |
|||
updateUI(); |
|||
return true; |
|||
} else return false; |
|||
} |
|||
|
|||
public void setTotalPageCount(int totalPageCount) { |
|||
this.totalPageCount = totalPageCount; |
|||
updateUI(); |
|||
} |
|||
|
|||
public void updateUI() { |
|||
pageIndicator.setText(indicatorPageIndex + "/" + totalPageCount); |
|||
} |
|||
|
|||
/** |
|||
* This class is used to implement the repetitive incrementPageRequestValue/decrementPageRequestValue |
|||
* of page value when long pressing one of the page navigation buttons. |
|||
*/ |
|||
private class RepetitiveUpdater implements Runnable { |
|||
private final int step; |
|||
|
|||
/** |
|||
* @param step number of pages to add/subtract on each repetition |
|||
*/ |
|||
RepetitiveUpdater(int step) { |
|||
this.step = step; |
|||
} |
|||
|
|||
public void run() { |
|||
long REPEAT_DELAY = 250; |
|||
if (autoIncrement) { |
|||
setIndicatedPageIndex(indicatorPageIndex+step); |
|||
repeatUpdateHandler.postDelayed(new BottomPaginationView.RepetitiveUpdater(step), REPEAT_DELAY); |
|||
} else if (autoDecrement) { |
|||
setIndicatedPageIndex(indicatorPageIndex-step); |
|||
repeatUpdateHandler.postDelayed(new BottomPaginationView.RepetitiveUpdater(step), REPEAT_DELAY); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public boolean incrementPageIndicator(int step) { |
|||
int oldIndicatorIndex = indicatorPageIndex; |
|||
if (oldIndicatorIndex <= totalPageCount - step) |
|||
setIndicatedPageIndex(indicatorPageIndex + step); |
|||
else |
|||
setIndicatedPageIndex(totalPageCount); |
|||
return oldIndicatorIndex != indicatorPageIndex; |
|||
} |
|||
|
|||
public boolean decrementPageIndicator(int step) { |
|||
int oldIndicatorIndex = indicatorPageIndex; |
|||
if (oldIndicatorIndex > step) |
|||
setIndicatedPageIndex(indicatorPageIndex - step); |
|||
else |
|||
setIndicatedPageIndex(1); |
|||
return oldIndicatorIndex != indicatorPageIndex; |
|||
} |
|||
|
|||
@SuppressLint("ClickableViewAccessibility") |
|||
private void initIncrementButton(ImageButton increment, final int step) { |
|||
// Increment once for a click
|
|||
increment.setOnClickListener(v -> { |
|||
if (!autoIncrement && step == LARGE_STEP) { |
|||
boolean indicatorChanged = setIndicatedPageIndex(totalPageCount); |
|||
if (indicatorChanged) onPageRequestedListener.onPageRequested(indicatorPageIndex); |
|||
} else if (!autoIncrement) { |
|||
boolean indicatorChanged = incrementPageIndicator(1); |
|||
if (indicatorChanged) onPageRequestedListener.onPageRequested(indicatorPageIndex); |
|||
} |
|||
}); |
|||
|
|||
// Auto increment for a long click
|
|||
increment.setOnLongClickListener( |
|||
arg0 -> { |
|||
paginationDisable(arg0); |
|||
autoIncrement = true; |
|||
repeatUpdateHandler.postDelayed(new BottomPaginationView.RepetitiveUpdater(step), INITIAL_DELAY); |
|||
return false; |
|||
} |
|||
); |
|||
|
|||
// When the button is released
|
|||
increment.setOnTouchListener(new View.OnTouchListener() { |
|||
private Rect rect; |
|||
|
|||
public boolean onTouch(View v, MotionEvent event) { |
|||
if (event.getAction() == MotionEvent.ACTION_DOWN) { |
|||
onDownPageIndex = indicatorPageIndex; |
|||
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom()); |
|||
} else if (rect != null && event.getAction() == MotionEvent.ACTION_UP && autoIncrement) { |
|||
autoIncrement = false; |
|||
paginationEnabled(true); |
|||
onPageRequestedListener.onPageRequested(indicatorPageIndex); |
|||
} else if (rect != null && event.getAction() == MotionEvent.ACTION_MOVE) { |
|||
if (!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) { |
|||
autoIncrement = false; |
|||
setIndicatedPageIndex(onDownPageIndex); |
|||
paginationEnabled(true); |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
@SuppressLint("ClickableViewAccessibility") |
|||
private void initDecrementButton(ImageButton decrement, final int step) { |
|||
// Decrement once for a click
|
|||
decrement.setOnClickListener(v -> { |
|||
if (!autoDecrement && step == LARGE_STEP) { |
|||
boolean indicatorChanged = setIndicatedPageIndex(1); |
|||
if (indicatorChanged) onPageRequestedListener.onPageRequested(indicatorPageIndex); |
|||
} else if (!autoDecrement) { |
|||
boolean indicatorChanged = decrementPageIndicator(1); |
|||
if (indicatorChanged) onPageRequestedListener.onPageRequested(indicatorPageIndex); |
|||
} |
|||
}); |
|||
|
|||
// Auto decrement for a long click
|
|||
decrement.setOnLongClickListener( |
|||
arg0 -> { |
|||
paginationDisable(arg0); |
|||
autoDecrement = true; |
|||
repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), INITIAL_DELAY); |
|||
return false; |
|||
} |
|||
); |
|||
|
|||
// When the button is released
|
|||
decrement.setOnTouchListener(new View.OnTouchListener() { |
|||
private Rect rect; |
|||
|
|||
public boolean onTouch(View v, MotionEvent event) { |
|||
if (event.getAction() == MotionEvent.ACTION_DOWN) { |
|||
onDownPageIndex = indicatorPageIndex; |
|||
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom()); |
|||
} else if (event.getAction() == MotionEvent.ACTION_UP && autoDecrement) { |
|||
autoDecrement = false; |
|||
paginationEnabled(true); |
|||
onPageRequestedListener.onPageRequested(indicatorPageIndex); |
|||
} else if (event.getAction() == MotionEvent.ACTION_MOVE) { |
|||
if (rect != null && |
|||
!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) { |
|||
autoIncrement = false; |
|||
setIndicatedPageIndex(onDownPageIndex); |
|||
paginationEnabled(true); |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public void paginationDisable(View exception) { |
|||
if (exception == firstPage) { |
|||
previousPage.setEnabled(false); |
|||
nextPage.setEnabled(false); |
|||
lastPage.setEnabled(false); |
|||
} else if (exception == previousPage) { |
|||
firstPage.setEnabled(false); |
|||
nextPage.setEnabled(false); |
|||
lastPage.setEnabled(false); |
|||
} else if (exception == nextPage) { |
|||
firstPage.setEnabled(false); |
|||
previousPage.setEnabled(false); |
|||
lastPage.setEnabled(false); |
|||
} else if (exception == lastPage) { |
|||
firstPage.setEnabled(false); |
|||
previousPage.setEnabled(false); |
|||
nextPage.setEnabled(false); |
|||
} else { |
|||
paginationEnabled(false); |
|||
} |
|||
} |
|||
|
|||
public void paginationEnabled(boolean enabled) { |
|||
firstPage.setEnabled(enabled); |
|||
previousPage.setEnabled(enabled); |
|||
nextPage.setEnabled(enabled); |
|||
lastPage.setEnabled(enabled); |
|||
} |
|||
} |
@ -0,0 +1,54 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<merge xmlns:android="http://schemas.android.com/apk/res/android" |
|||
xmlns:app="http://schemas.android.com/apk/res-auto" |
|||
android:background="@color/primary" |
|||
app:elevation="8dp" |
|||
app:layout_behavior="gr.thmmy.mthmmy.utils.ScrollAwareLinearBehavior"> |
|||
<ImageButton |
|||
android:id="@+id/page_first_button" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="match_parent" |
|||
android:layout_weight="0.8" |
|||
android:background="?attr/selectableItemBackgroundBorderless" |
|||
android:contentDescription="@string/button_first" |
|||
app:srcCompat="@drawable/page_first" /> |
|||
|
|||
<ImageButton |
|||
android:id="@+id/page_previous_button" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="match_parent" |
|||
android:layout_weight="0.8" |
|||
android:background="?attr/selectableItemBackgroundBorderless" |
|||
android:contentDescription="@string/button_previous" |
|||
app:srcCompat="@drawable/page_previous" /> |
|||
|
|||
<TextView |
|||
android:id="@+id/page_indicator" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="match_parent" |
|||
android:layout_gravity="center" |
|||
android:layout_weight="1" |
|||
android:gravity="center" |
|||
android:hint="@string/button_page" |
|||
android:maxLines="1" |
|||
android:textColor="@color/white" |
|||
android:textSize="22sp" /> |
|||
|
|||
<ImageButton |
|||
android:id="@+id/page_next_button" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="match_parent" |
|||
android:layout_weight="0.8" |
|||
android:background="?attr/selectableItemBackgroundBorderless" |
|||
android:contentDescription="@string/button_next" |
|||
app:srcCompat="@drawable/page_next" /> |
|||
|
|||
<ImageButton |
|||
android:id="@+id/page_last_button" |
|||
android:layout_width="wrap_content" |
|||
android:layout_height="match_parent" |
|||
android:layout_weight="0.8" |
|||
android:background="?attr/selectableItemBackgroundBorderless" |
|||
android:contentDescription="@string/button_last" |
|||
app:srcCompat="@drawable/page_last" /> |
|||
</merge> |
@ -1,6 +1,6 @@ |
|||
#Tue Sep 17 12:32:34 EEST 2019 |
|||
#Mon Mar 30 15:17:37 EEST 2020 |
|||
distributionBase=GRADLE_USER_HOME |
|||
distributionPath=wrapper/dists |
|||
zipStoreBase=GRADLE_USER_HOME |
|||
zipStorePath=wrapper/dists |
|||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip |
|||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip |
|||
|
Loading…
Reference in new issue