Skip to content
This repository has been archived by the owner on Nov 4, 2022. It is now read-only.

Commit

Permalink
Merge pull request #62 from zeoflow/material-viewpager
Browse files Browse the repository at this point in the history
Material ViewPager
  • Loading branch information
teogor authored Mar 13, 2021
2 parents 15116c0 + 069bad5 commit 1139992
Show file tree
Hide file tree
Showing 20 changed files with 3,865 additions and 20 deletions.
11 changes: 5 additions & 6 deletions local.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Sun Aug 23 11:27:32 EEST 2020
sdk.dir=E\:\\Data\\Android\\Sdk

signing.keyId=7ACB2D2A
#Sun Mar 14 00:24:19 EET 2021
ossrhPassword=yourSonatypePassword
signing.secretKeyRingFile=C\:\\Users\\teo\\ZeoFlow_MaterialElements.gpg
sdk.dir=E\:\\software\\Android\\Sdk
signing.password=signingPass123
signing.secretKeyRingFile=C:\\Users\\teo\\ZeoFlow_MaterialElements.gpg
ossrhUsername=yourSonatypeUser
ossrhPassword=yourSonatypePassword
signing.keyId=7ACB2D2A
1 change: 1 addition & 0 deletions material-elements/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ def srcDirs = [
'com/zeoflow/material/elements/transition',
'com/zeoflow/material/elements/transformation',
'com/zeoflow/material/elements/typography',
'com/zeoflow/material/elements/viewpager',
]

android {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
/*
* Copyright 2021 ZeoFlow SRL
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.zeoflow.material.elements.pagerindicator;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import com.zeoflow.material.elements.viewpager.MaterialViewPager;

@SuppressWarnings("UnusedDeclaration")
public class ViewPager2Attacher extends AbstractViewPagerAttacher<ViewPager2>
public class MaterialViewPagerAttacher extends AbstractViewPagerAttacher<MaterialViewPager>
{

private RecyclerView.AdapterDataObserver dataSetObserver;
private RecyclerView.Adapter attachedAdapter;
private ViewPager2.OnPageChangeCallback onPageChangeListener;
private ViewPager2 pager;
private MaterialViewPager.OnPageChangeCallback onPageChangeListener;
private MaterialViewPager pager;

@Override
public void attachToPager(@NonNull final ScrollingPagerIndicator indicator, @NonNull final ViewPager2 pager)
public void attachToPager(@NonNull final ScrollingPagerIndicator indicator, @NonNull final MaterialViewPager pager)
{
attachedAdapter = pager.getAdapter();
if (attachedAdapter == null)
Expand All @@ -36,7 +52,7 @@ public void onChanged()
};
attachedAdapter.registerAdapterDataObserver(dataSetObserver);

onPageChangeListener = new ViewPager2.OnPageChangeCallback()
onPageChangeListener = new MaterialViewPager.OnPageChangeCallback()
{

boolean idleState = true;
Expand All @@ -59,7 +75,7 @@ public void onPageSelected(int position)
@Override
public void onPageScrollStateChanged(int state)
{
idleState = state == ViewPager2.SCROLL_STATE_IDLE;
idleState = state == MaterialViewPager.SCROLL_STATE_IDLE;
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
* Copyright 2021 ZeoFlow SRL
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.zeoflow.material.elements.pagerindicator;

import android.animation.ArgbEvaluator;
Expand All @@ -17,7 +33,7 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.ViewPager;
import androidx.viewpager2.widget.ViewPager2;
import com.zeoflow.material.elements.viewpager.MaterialViewPager;

import com.zeoflow.material.elements.R;

Expand Down Expand Up @@ -257,13 +273,13 @@ public void attachToPager(@NonNull ViewPager pager)
}

/**
* Attaches indicator to ViewPager2
* Attaches indicator to MaterialViewPager
*
* @param pager pager to attach
*/
public void attachToPager(@NonNull ViewPager2 pager)
public void attachToPager(@NonNull MaterialViewPager pager)
{
attachToPager(pager, new ViewPager2Attacher());
attachToPager(pager, new MaterialViewPagerAttacher());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ dependencies {
implementation project(fromPath("material-elements/java/com/zeoflow/material/elements/radiobutton"))
implementation project(fromPath("material-elements/java/com/zeoflow/material/elements/switchmaterial"))
implementation project(fromPath("material-elements/java/com/zeoflow/material/elements/typography"))
implementation project(fromPath("material-elements/java/com/zeoflow/material/elements/viewpager"))
}

android {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013 The Android Open Source Project
* Copyright 2021 ZeoFlow SRL
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright 2021 ZeoFlow SRL
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.zeoflow.material.elements.viewpager;

import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;

import static com.zeoflow.material.elements.viewpager.MaterialViewPager.ORIENTATION_HORIZONTAL;

import android.animation.LayoutTransition;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;

import java.util.Arrays;
import java.util.Comparator;

/**
* Class used to detect if there are gaps between pages and if any of the pages contain a running
* change-transition in case we detected an illegal state in the {@link ScrollEventAdapter}.
*
* This is an approximation of the detection and could potentially lead to misleading advice. If we
* hit problems with it, remove the detection and replace with a suggestive error message instead,
* like "Negative page offset encountered. Did you setAnimateParentHierarchy(false) to all your
* LayoutTransitions?".
*/
final class AnimateLayoutChangeDetector {
private static final ViewGroup.MarginLayoutParams ZERO_MARGIN_LAYOUT_PARAMS;

static {
ZERO_MARGIN_LAYOUT_PARAMS = new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT);
ZERO_MARGIN_LAYOUT_PARAMS.setMargins(0, 0, 0, 0);
}

private LinearLayoutManager mLayoutManager;

AnimateLayoutChangeDetector(@NonNull LinearLayoutManager llm) {
mLayoutManager = llm;
}

boolean mayHaveInterferingAnimations() {
// Two conditions need to be satisfied:
// 1) the pages are not laid out contiguously (i.e., there are gaps between them)
// 2) there is a ViewGroup with a LayoutTransition that isChangingLayout()
return (!arePagesLaidOutContiguously() || mLayoutManager.getChildCount() <= 1)
&& hasRunningChangingLayoutTransition();
}

private boolean arePagesLaidOutContiguously() {
// Collect view positions
int childCount = mLayoutManager.getChildCount();
if (childCount == 0) {
return true;
}

boolean isHorizontal = mLayoutManager.getOrientation() == ORIENTATION_HORIZONTAL;
int[][] bounds = new int[childCount][2];
for (int i = 0; i < childCount; i++) {
View view = mLayoutManager.getChildAt(i);
if (view == null) {
throw new IllegalStateException("null view contained in the view hierarchy");
}
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
ViewGroup.MarginLayoutParams margin;
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
margin = (ViewGroup.MarginLayoutParams) layoutParams;
} else {
margin = ZERO_MARGIN_LAYOUT_PARAMS;
}
bounds[i][0] = isHorizontal
? view.getLeft() - margin.leftMargin
: view.getTop() - margin.topMargin;
bounds[i][1] = isHorizontal
? view.getRight() + margin.rightMargin
: view.getBottom() + margin.bottomMargin;
}

// Sort them
Arrays.sort(bounds, new Comparator<int[]>() {
@Override
public int compare(int[] lhs, int[] rhs) {
return lhs[0] - rhs[0];
}
});

// Check for inconsistencies
for (int i = 1; i < childCount; i++) {
if (bounds[i - 1][1] != bounds[i][0]) {
return false;
}
}

// Check that the pages fill the whole screen
int pageSize = bounds[0][1] - bounds[0][0];
if (bounds[0][0] > 0 || bounds[childCount - 1][1] < pageSize) {
return false;
}
return true;
}

private boolean hasRunningChangingLayoutTransition() {
int childCount = mLayoutManager.getChildCount();
for (int i = 0; i < childCount; i++) {
if (hasRunningChangingLayoutTransition(mLayoutManager.getChildAt(i))) {
return true;
}
}
return false;
}

private static boolean hasRunningChangingLayoutTransition(View view) {
if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
LayoutTransition layoutTransition = viewGroup.getLayoutTransition();
if (layoutTransition != null && layoutTransition.isChangingLayout()) {
return true;
}
int childCount = viewGroup.getChildCount();
for (int i = 0; i < childCount; i++) {
if (hasRunningChangingLayoutTransition(viewGroup.getChildAt(i))) {
return true;
}
}
}
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright 2021 ZeoFlow SRL
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.zeoflow.material.elements.viewpager;

import androidx.annotation.NonNull;
import androidx.annotation.Px;
import com.zeoflow.material.elements.viewpager.MaterialViewPager.OnPageChangeCallback;

import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;

/**
* Dispatches {@link OnPageChangeCallback} events to subscribers.
*/
final class CompositeOnPageChangeCallback extends OnPageChangeCallback {
@NonNull
private final List<OnPageChangeCallback> mCallbacks;

CompositeOnPageChangeCallback(int initialCapacity) {
mCallbacks = new ArrayList<>(initialCapacity);
}

/**
* Adds the given callback to the list of subscribers
*/
void addOnPageChangeCallback(OnPageChangeCallback callback) {
mCallbacks.add(callback);
}

/**
* Removes the given callback from the list of subscribers
*/
void removeOnPageChangeCallback(OnPageChangeCallback callback) {
mCallbacks.remove(callback);
}

/**
* @see OnPageChangeCallback#onPageScrolled(int, float, int)
*/
@Override
public void onPageScrolled(int position, float positionOffset, @Px int positionOffsetPixels) {
try {
for (OnPageChangeCallback callback : mCallbacks) {
callback.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
} catch (ConcurrentModificationException ex) {
throwCallbackListModifiedWhileInUse(ex);
}
}

/**
* @see OnPageChangeCallback#onPageSelected(int)
*/
@Override
public void onPageSelected(int position) {
try {
for (OnPageChangeCallback callback : mCallbacks) {
callback.onPageSelected(position);
}
} catch (ConcurrentModificationException ex) {
throwCallbackListModifiedWhileInUse(ex);
}
}

/**
* @see OnPageChangeCallback#onPageScrollStateChanged(int)
*/
@Override
public void onPageScrollStateChanged(@MaterialViewPager.ScrollState int state) {
try {
for (OnPageChangeCallback callback : mCallbacks) {
callback.onPageScrollStateChanged(state);
}
} catch (ConcurrentModificationException ex) {
throwCallbackListModifiedWhileInUse(ex);
}
}

private void throwCallbackListModifiedWhileInUse(ConcurrentModificationException parent) {
throw new IllegalStateException(
"Adding and removing callbacks during dispatch to callbacks is not supported",
parent
);
}

}
Loading

0 comments on commit 1139992

Please sign in to comment.