diff --git a/app/src/main/java/com/yalantis/kolodaandroid/MainActivity.kt b/app/src/main/java/com/yalantis/kolodaandroid/MainActivity.kt
index 410e422..7f80d2b 100644
--- a/app/src/main/java/com/yalantis/kolodaandroid/MainActivity.kt
+++ b/app/src/main/java/com/yalantis/kolodaandroid/MainActivity.kt
@@ -2,11 +2,13 @@ package com.yalantis.kolodaandroid
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
-import android.widget.Toast
import com.yalantis.library.KolodaListener
import kotlinx.android.synthetic.main.activity_main.*
import android.annotation.SuppressLint
+import android.view.Menu
+import android.view.MenuItem
import android.view.ViewTreeObserver
+import com.yalantis.kolodaandroid.R.id.actionReload
class MainActivity : AppCompatActivity() {
@@ -27,8 +29,6 @@ class MainActivity : AppCompatActivity() {
@SuppressLint("NewApi")
override fun onGlobalLayout() {
//now we can retrieve the width and height
- val width = activityMain.width
- val height = activityMain.height
//...
//do whatever you want with them
//...
@@ -55,19 +55,19 @@ class MainActivity : AppCompatActivity() {
internal var cardsSwiped = 0
override fun onNewTopCard(position: Int) {
- Toast.makeText(this@MainActivity, "On new top card", Toast.LENGTH_LONG).show()
+ //todo realize your logic
}
override fun onCardSwipedLeft(position: Int) {
- Toast.makeText(this@MainActivity, "On card swiped left", Toast.LENGTH_LONG).show()
+ //todo realize your logic
}
override fun onCardSwipedRight(position: Int) {
- Toast.makeText(this@MainActivity, "On card swiped right", Toast.LENGTH_LONG).show()
+ //todo realize your logic
}
override fun onEmptyDeck() {
- Toast.makeText(this@MainActivity, "On empty deck", Toast.LENGTH_LONG).show()
+ //todo realize your logic
}
}
}
@@ -77,18 +77,18 @@ class MainActivity : AppCompatActivity() {
*/
private fun fillData() {
val data = arrayOf(R.drawable.cupcacke,
- R.drawable.donut,
- R.drawable.eclair,
- R.drawable.froyo,
- R.drawable.gingerbread,
- R.drawable.honeycomb,
- R.drawable.ice_cream_sandwich,
- R.drawable.jelly_bean,
- R.drawable.kitkat,
- R.drawable.lollipop,
- R.drawable.marshmallow,
- R.drawable.nougat,
- R.drawable.oreo)
+ R.drawable.donut,
+ R.drawable.eclair,
+ R.drawable.froyo,
+ R.drawable.gingerbread,
+ R.drawable.honeycomb,
+ R.drawable.ice_cream_sandwich,
+ R.drawable.jelly_bean,
+ R.drawable.kitkat,
+ R.drawable.lollipop,
+ R.drawable.marshmallow,
+ R.drawable.nougat,
+ R.drawable.oreo)
adapter = KolodaSampleAdapter(this, data.toList())
koloda.adapter = adapter
koloda.isNeedCircleLoading = true
@@ -98,4 +98,16 @@ class MainActivity : AppCompatActivity() {
dislike.setOnClickListener { koloda.onClickLeft() }
like.setOnClickListener { koloda.onClickRight() }
}
+
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.menu_reload, menu)
+ return true
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ actionReload -> { koloda.reloadPreviousCard() }
+ }
+ return super.onOptionsItemSelected(item)
+ }
}
diff --git a/app/src/main/res/drawable/ic_reload.xml b/app/src/main/res/drawable/ic_reload.xml
new file mode 100644
index 0000000..1fb4ac7
--- /dev/null
+++ b/app/src/main/res/drawable/ic_reload.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 8827bd9..0ba1b85 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -2,24 +2,23 @@
+ android:layout_height="match_parent"
+ android:background="@color/colorPrimary"
+ android:clipToPadding="false">
@@ -27,19 +26,19 @@
android:id="@+id/dislike"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:src="@drawable/ic_dislike"
android:layout_weight="1"
- android:background="@android:color/transparent"/>
+ android:background="@android:color/transparent"
+ android:src="@drawable/ic_dislike" />
+ android:layout_weight="0.5"
+ android:background="@android:color/transparent"
+ android:src="@drawable/ic_like" />
diff --git a/app/src/main/res/menu/menu_reload.xml b/app/src/main/res/menu/menu_reload.xml
new file mode 100644
index 0000000..0bc346b
--- /dev/null
+++ b/app/src/main/res/menu/menu_reload.xml
@@ -0,0 +1,11 @@
+
+
\ No newline at end of file
diff --git a/library/src/main/java/com/yalantis/library/CardLayout.kt b/library/src/main/java/com/yalantis/library/CardLayout.kt
new file mode 100644
index 0000000..d6f99e8
--- /dev/null
+++ b/library/src/main/java/com/yalantis/library/CardLayout.kt
@@ -0,0 +1,106 @@
+package com.yalantis.library
+
+import android.content.Context
+import android.os.Build
+import android.support.annotation.DrawableRes
+import android.support.v4.content.ContextCompat
+import android.util.AttributeSet
+import android.view.View
+import android.widget.FrameLayout
+import android.widget.ImageView
+
+/**
+ * Created by anna on 1/2/18.
+ */
+class CardLayout
+@JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0, var cardParams: CardParams) : FrameLayout(context, attrs, defStyleAttr) {
+
+ private var rightImageView: ImageView? = null
+ private var leftImageView: ImageView? = null
+ private var cardView: View? = null
+ var layoutAlpha = 1f
+ set(value) {
+ field = value
+ cardView?.alpha = value
+ }
+
+
+ fun addOverlays(cardView: View?, @DrawableRes rightOverlayImage: Int?,
+ @DrawableRes leftOverlayImage: Int?) {
+ this.cardView = cardView
+ addView(cardView)
+
+ leftOverlayImage?.let {
+ leftImageView = ImageView(context)
+ leftImageView?.setImageDrawable(ContextCompat.getDrawable(context, it))
+ leftImageView?.alpha = 0f
+ addView(leftImageView)
+ }
+
+ rightOverlayImage?.let {
+ rightImageView = ImageView(context)
+ rightImageView?.setImageDrawable(ContextCompat.getDrawable(context, it))
+ rightImageView?.alpha = 0f
+ addView(rightImageView)
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ rightImageView?.translationZ = SMALL_ELEVATION
+ leftImageView?.translationZ = SMALL_ELEVATION
+ cardView?.translationZ = NO_ELEVATION
+ }
+ }
+
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ val layoutParamsCardView = cardView?.layoutParams as FrameLayout.LayoutParams
+
+ cardView?.alpha = layoutAlpha
+ cardParams.onParamsMeasure(layoutParamsCardView)
+
+ rightImageView?.layoutParams?.let {
+ (rightImageView?.layoutParams as FrameLayout.LayoutParams).apply {
+ width = layoutParamsCardView.width
+ height = layoutParamsCardView.height
+ gravity = layoutParamsCardView.gravity
+
+ setMargins(layoutParamsCardView.leftMargin, layoutParamsCardView.topMargin,
+ layoutParamsCardView.rightMargin, layoutParamsCardView.bottomMargin)
+ }
+ rightImageView?.setPadding(cardView?.paddingLeft ?: 0, cardView?.paddingTop ?: 0,
+ cardView?.paddingRight ?: 0, cardView?.paddingBottom ?: 0)
+ }
+
+ leftImageView?.layoutParams?.let {
+ (leftImageView?.layoutParams as FrameLayout.LayoutParams).apply {
+ width = layoutParamsCardView.width
+ height = layoutParamsCardView.height
+ gravity = layoutParamsCardView.gravity
+ setMargins(layoutParamsCardView.leftMargin, layoutParamsCardView.topMargin,
+ layoutParamsCardView.rightMargin, layoutParamsCardView.bottomMargin)
+ }
+
+ leftImageView?.setPadding(cardView?.paddingLeft ?: 0, cardView?.paddingTop ?: 0,
+ cardView?.paddingRight ?: 0, cardView?.paddingBottom ?: 0)
+ }
+ }
+
+ internal fun changeRightOverlayAlpha(progress: Float) {
+ rightImageView?.alpha = progress
+ }
+
+ internal fun changeLeftOverlayAlpha(progress: Float) {
+ leftImageView?.alpha = Math.abs(progress)
+ }
+
+ interface CardParams {
+ fun onParamsMeasure(layoutParamsCardView: LayoutParams)
+ }
+
+ companion object {
+ private const val NO_ELEVATION = 0F
+ private const val SMALL_ELEVATION = 10F
+ }
+
+}
\ No newline at end of file
diff --git a/library/src/main/java/com/yalantis/library/CardOperator.kt b/library/src/main/java/com/yalantis/library/CardOperator.kt
index b40d490..570bec4 100644
--- a/library/src/main/java/com/yalantis/library/CardOperator.kt
+++ b/library/src/main/java/com/yalantis/library/CardOperator.kt
@@ -1,26 +1,33 @@
package com.yalantis.library
import android.animation.*
-import android.support.v4.view.VelocityTrackerCompat
import android.view.GestureDetector
import android.view.MotionEvent
-import android.view.View
import android.view.VelocityTracker
+import android.view.View
/**
* Created by anna on 11/10/17.
*/
-class CardOperator(val koloda: Koloda, val cardView: View, val adapterPosition: Int, val cardCallback: CardCallback) {
+class CardOperator(
+ val koloda: Koloda,
+ val cardView: CardLayout,
+ val adapterPosition: Int,
+ val cardCallback: CardCallback
+) {
- companion object {
- private const val DEFAULT_OFF_SCREEN_ANIMATION_DURATION = 600
- private val DEFAULT_OFF_SCREEN_FLING_ANIMATION_DURATION = 150
- private val DEFAULT_RESET_ANIMATION_DURATION = 600
+ init {
+ cardView.setOnTouchListener { view, event -> onTouchView(view, event) }
}
private val cardGestureListener = object : GestureDetector.SimpleOnGestureListener() {
- override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {
+ override fun onFling(
+ e1: MotionEvent?,
+ e2: MotionEvent?,
+ velocityX: Float,
+ velocityY: Float
+ ): Boolean {
if (e1?.x ?: 0f > e2?.x ?: 0f && cardBeyondLeftBorder()) {
cardCallback.onCardActionUp(adapterPosition, cardView, true)
animateOffScreenLeft(DEFAULT_OFF_SCREEN_FLING_ANIMATION_DURATION, true, false)
@@ -59,37 +66,35 @@ class CardOperator(val koloda: Koloda, val cardView: View, val adapterPosition:
private var initialCardPositionX: Float = 0.toFloat()
private var initialCardPositionY: Float = 0.toFloat()
private var animationCycle: AnimationCycle = AnimationCycle.NO_ANIMATION
- private var velocityTrecker: VelocityTracker? = null
-
- init {
- cardView.setOnTouchListener { view, event -> onTouchView(view, event) }
- }
+ private var velocityTracker: VelocityTracker? = null
fun animateOffScreenLeft(duration: Int, notify: Boolean, isClicked: Boolean) {
- var targetY = cardView.y
- if (initialCardPositionY > cardView.y) {
- targetY -= initialCardPositionY - cardView.y
+ val pvhX = PropertyValuesHolder.ofFloat("x", cardView.x, cardView.x - calculateTransition())
+ val pvhY = PropertyValuesHolder.ofFloat("y", cardView.y, cardView.y * 2)
+ animateCardOffScreen(duration, pvhX, pvhY)
+
+ if (!isClicked) {
+ cardCallback.onCardSwipedLeft(adapterPosition, cardView, notify)
} else {
- targetY += (cardView.y - initialCardPositionY) * 3
+ cardCallback.onCardMovedOnClickLeft(adapterPosition, cardView, notify)
}
+ }
- val maxCardWidth = koloda.getMaxCardWidth(cardView)
- val transitionX = (koloda.parentWidth / 2 + cardView.width / 2) +
- cardView.x + Math.abs(maxCardWidth / 2)
+ fun animateOffScreenRight(duration: Int, notify: Boolean, isClicked: Boolean) {
- val pvhX = PropertyValuesHolder.ofFloat("x", cardView.x, cardView.x - transitionX)
+ val pvhX = PropertyValuesHolder.ofFloat("x", cardView.x, cardView.x + calculateTransition())
val pvhY = PropertyValuesHolder.ofFloat("y", cardView.y, cardView.y * 2)
animateCardOffScreen(duration, pvhX, pvhY)
if (!isClicked) {
- cardCallback.onCardSwipedLeft(adapterPosition, cardView, notify)
+ cardCallback.onCardSwipedRight(adapterPosition, cardView, notify)
} else {
- cardCallback.onCardMovedOnClickLeft(adapterPosition, cardView, notify)
+ cardCallback.onCardMovedOnClickRight(adapterPosition, cardView, notify)
}
}
- fun animateOffScreenRight(duration: Int, notify: Boolean, isClicked: Boolean) {
+ private fun calculateTransition(): Float {
var targetY = cardView.y
if (initialCardPositionY > cardView.y) {
@@ -99,21 +104,15 @@ class CardOperator(val koloda: Koloda, val cardView: View, val adapterPosition:
}
val maxCardWidth = koloda.getMaxCardWidth(cardView)
- val transitionX = koloda.parentWidth - (koloda.parentWidth / 2 - cardView.width / 2) +
+ return koloda.parentWidth - (koloda.parentWidth / 2 - cardView.width / 2) +
cardView.x + Math.abs(maxCardWidth / 2)
-
- val pvhX = PropertyValuesHolder.ofFloat("x", cardView.x, cardView.x + transitionX)
- val pvhY = PropertyValuesHolder.ofFloat("y", cardView.y, cardView.y * 2)
- animateCardOffScreen(duration, pvhX, pvhY)
-
- if (!isClicked) {
- cardCallback.onCardSwipedRight(adapterPosition, cardView, notify)
- } else {
- cardCallback.onCardMovedOnClickRight(adapterPosition, cardView, notify)
- }
}
- private fun animateCardOffScreen(duration: Int, pvhX: PropertyValuesHolder, pvhY: PropertyValuesHolder) {
+ private fun animateCardOffScreen(
+ duration: Int,
+ pvhX: PropertyValuesHolder,
+ pvhY: PropertyValuesHolder
+ ) {
swipedCardOffScreen()
val valueAnimator = ValueAnimator()
@@ -134,18 +133,28 @@ class CardOperator(val koloda: Koloda, val cardView: View, val adapterPosition:
private fun checkCardPosition() {
when {
- cardBeyondLeftBorder() -> animateOffScreenLeft(DEFAULT_OFF_SCREEN_ANIMATION_DURATION, true, false)
- cardBeyondRightBorder() -> animateOffScreenRight(DEFAULT_OFF_SCREEN_ANIMATION_DURATION, true, false)
+ cardBeyondLeftBorder() -> animateOffScreenLeft(
+ DEFAULT_OFF_SCREEN_ANIMATION_DURATION,
+ true,
+ false
+ )
+ cardBeyondRightBorder() -> animateOffScreenRight(
+ DEFAULT_OFF_SCREEN_ANIMATION_DURATION,
+ true,
+ false
+ )
else -> resetCardPosition(DEFAULT_RESET_ANIMATION_DURATION)
}
}
private fun resetCardPosition(duration: Int) {
- currentCardAnimator = ObjectAnimator.ofPropertyValuesHolder(cardView,
- PropertyValuesHolder.ofFloat(View.X, initialCardPositionX),
- PropertyValuesHolder.ofFloat(View.Y, initialCardPositionY),
- PropertyValuesHolder.ofFloat(View.ROTATION, 0f))
- .setDuration(duration.toLong())
+ currentCardAnimator = ObjectAnimator.ofPropertyValuesHolder(
+ cardView,
+ PropertyValuesHolder.ofFloat(View.X, initialCardPositionX),
+ PropertyValuesHolder.ofFloat(View.Y, initialCardPositionY),
+ PropertyValuesHolder.ofFloat(View.ROTATION, 0f)
+ )
+ .setDuration(duration.toLong())
currentCardAnimator?.duration = 200
currentCardAnimator?.addUpdateListener { updateCardProgress() }
currentCardAnimator?.addListener(object : AnimatorListenerAdapter() {
@@ -169,7 +178,8 @@ class CardOperator(val koloda: Koloda, val cardView: View, val adapterPosition:
}
private fun updateCardProgress() {
- var sideProgress = ((cardView.x + (cardView.width / 2)) - (koloda.parentWidth / 2)) / (koloda.parentWidth / 2)
+ var sideProgress =
+ ((cardView.x + (cardView.width / 2)) - (koloda.parentWidth / 2)) / (koloda.parentWidth / 2)
if (sideProgress > 1f) {
sideProgress = 1f
} else if (sideProgress < -1f) {
@@ -181,8 +191,17 @@ class CardOperator(val koloda: Koloda, val cardView: View, val adapterPosition:
private fun updateCardProgress(sideProgress: Float) {
cardCallback.onCardDrag(adapterPosition, cardView, sideProgress)
- val cardOffsetProgress = Math.max(Math.abs(cardView.x / cardView.width),
- Math.abs(cardView.y / cardView.height))
+ val cardOffsetProgress = Math.max(
+ Math.abs(cardView.x / cardView.width),
+ Math.abs(cardView.y / cardView.height)
+ )
+
+ if (sideProgress > 0) {
+ cardView.changeRightOverlayAlpha(sideProgress)
+ } else {
+ cardView.changeLeftOverlayAlpha(sideProgress)
+ }
+
if (!(isSwipedOffScreen && cardOffsetProgress > 1)) {
cardCallback.onCardOffset(adapterPosition, cardView, sideProgress)
}
@@ -207,10 +226,10 @@ class CardOperator(val koloda: Koloda, val cardView: View, val adapterPosition:
val action = event.actionMasked
when (action) {
MotionEvent.ACTION_DOWN -> {
- if (velocityTrecker == null) {
- velocityTrecker = VelocityTracker.obtain()
+ if (velocityTracker == null) {
+ velocityTracker = VelocityTracker.obtain()
} else {
- velocityTrecker?.clear()
+ velocityTracker?.clear()
}
if (animationCycle == AnimationCycle.NO_ANIMATION && !isBeingDragged) {
isBeingDragged = true
@@ -228,10 +247,10 @@ class CardOperator(val koloda: Koloda, val cardView: View, val adapterPosition:
}
MotionEvent.ACTION_MOVE -> {
- velocityTrecker?.addMovement(event)
+ velocityTracker?.addMovement(event)
val pointerId = event.getPointerId(event.actionIndex)
- velocityTrecker?.computeCurrentVelocity(pointerId, 40f)
+ velocityTracker?.computeCurrentVelocity(pointerId, 40f)
val pointerIndex = event.findPointerIndex(activePointerId)
@@ -239,11 +258,13 @@ class CardOperator(val koloda: Koloda, val cardView: View, val adapterPosition:
val dx = event.getX(pointerIndex) - initialTouchX
val dy = event.getY(pointerIndex) - initialTouchY
- val posX = (cardView.x + dx) + Math.abs((VelocityTrackerCompat.getXVelocity(velocityTrecker, pointerId)))
- val posY = (cardView.y + dy) + Math.abs((VelocityTrackerCompat.getYVelocity(velocityTrecker, pointerId)))
+ velocityTracker?.let {
+ val posX = (cardView.x + dx) + Math.abs(it.getXVelocity(pointerId))
+ val posY = (cardView.y + dy) + Math.abs(it.getYVelocity(pointerId))
- cardView.x = posX
- cardView.y = posY
+ cardView.x = posX
+ cardView.y = posY
+ }
updateCardProgress()
}
@@ -252,7 +273,11 @@ class CardOperator(val koloda: Koloda, val cardView: View, val adapterPosition:
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
activePointerId = MotionEvent.INVALID_POINTER_ID
checkCardPosition()
- cardCallback.onCardActionUp(adapterPosition, cardView, (cardBeyondLeftBorder() || cardBeyondRightBorder()))
+ cardCallback.onCardActionUp(
+ adapterPosition,
+ cardView,
+ (cardBeyondLeftBorder() || cardBeyondRightBorder())
+ )
}
MotionEvent.ACTION_POINTER_UP -> {
@@ -282,4 +307,10 @@ class CardOperator(val koloda: Koloda, val cardView: View, val adapterPosition:
animateOffScreenLeft(DEFAULT_OFF_SCREEN_ANIMATION_DURATION, true, true)
}
+ companion object {
+ private const val DEFAULT_OFF_SCREEN_ANIMATION_DURATION = 600
+ private const val DEFAULT_OFF_SCREEN_FLING_ANIMATION_DURATION = 150
+ private const val DEFAULT_RESET_ANIMATION_DURATION = 600
+ }
+
}
diff --git a/library/src/main/java/com/yalantis/library/Koloda.kt b/library/src/main/java/com/yalantis/library/Koloda.kt
index 733f2bb..4864b47 100644
--- a/library/src/main/java/com/yalantis/library/Koloda.kt
+++ b/library/src/main/java/com/yalantis/library/Koloda.kt
@@ -1,36 +1,47 @@
package com.yalantis.library
-import android.animation.ValueAnimator
+import android.annotation.TargetApi
import android.content.Context
import android.database.DataSetObserver
+import android.graphics.Color
+import android.os.Build
+import android.support.annotation.DrawableRes
import android.util.AttributeSet
-import android.widget.FrameLayout
+import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.widget.Adapter
-import android.os.Build
-import android.annotation.TargetApi
-import android.util.Log
+import android.widget.FrameLayout
/**
* Created by anna on 11/10/17.
*/
-class Koloda : FrameLayout {
+class Koloda
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null,
+ defStyleAttr: Int = 0) : FrameLayout(context, attrs, defStyleAttr), CardLayout.CardParams {
- companion object {
- private const val DEFAULT_MAX_VISIBLE_CARDS = 3
- private const val DEFAULT_ROTATION_ANGLE = 30f
- private const val DEFAULT_SCALE_DIFF = 0.04f
+ init {
+ init(attrs)
}
private var maxVisibleCards = DEFAULT_MAX_VISIBLE_CARDS
- private var cardPositionOffsetX = resources.getDimensionPixelSize(R.dimen.default_card_spacing)
private var cardPositionOffsetY = resources.getDimensionPixelSize(R.dimen.default_card_spacing)
private var cardRotationDegrees = DEFAULT_ROTATION_ANGLE
+ private var scaleDiff = DEFAULT_SCALE_DIFF
private var dyingViews = hashSetOf()
private var activeViews = linkedSetOf()
private var dataSetObservable: DataSetObserver? = null
var isNeedCircleLoading = false
+ @DrawableRes
+ var rightOverlay: Int? = null
+ @DrawableRes
+ var leftOverlay: Int? = null
+ var cardXPos = 0
+ var cardYPos = 0
+ var cardWidth = 0
+ var cardHeight = 0
+ private var alphaAnimation = false
var adapter: Adapter? = null
set(value) {
@@ -40,28 +51,21 @@ class Koloda : FrameLayout {
field?.registerDataSetObserver(createDataSetObserver())
dataSetObservable?.onChanged()
}
- private var adapterPosition = 0
+
+ private var adapterPosition = -1
private var deckMap = hashMapOf()
var kolodaListener: KolodaListener? = null
internal var parentWidth = 0
private var swipeEnabled = true
- constructor(context: Context) : this(context, null)
-
- constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
-
- constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
- init(attrs)
- }
-
private fun init(attrs: AttributeSet?) {
val a = context.obtainStyledAttributes(attrs, R.styleable.Koloda)
val cardLayoutId = a.getResourceId(R.styleable.Koloda_koloda_card_layout, -1)
maxVisibleCards = a.getInt(R.styleable.Koloda_koloda_max_visible_cards, DEFAULT_MAX_VISIBLE_CARDS)
- cardPositionOffsetX = a.getDimensionPixelSize(R.styleable.Koloda_koloda_card_offsetX, resources.getDimensionPixelSize(R.dimen.default_card_spacing))
cardPositionOffsetY = a.getDimensionPixelSize(R.styleable.Koloda_koloda_card_offsetY, resources.getDimensionPixelSize(R.dimen.default_card_spacing))
cardRotationDegrees = a.getFloat(R.styleable.Koloda_koloda_card_rotate_angle, DEFAULT_ROTATION_ANGLE)
-
+ scaleDiff = a.getFloat(R.styleable.Koloda_koloda_card_scale_diff, DEFAULT_SCALE_DIFF)
+ alphaAnimation = a.getBoolean(R.styleable.Koloda_koloda_card_animation_alpha, false)
a.recycle()
if (isInEditMode) {
@@ -74,16 +78,20 @@ class Koloda : FrameLayout {
*/
private fun addCardToDeck() {
- if (adapterPosition < adapter?.count ?: 0) {
- val newCard = adapter?.getView(adapterPosition, null, this)
- initializeCardPosition(newCard)
- newCard?.let {
+ if (adapterPosition < adapter?.count?.minus(1) ?: 0) {
+
+ val cardLayout = CardLayout(context, cardParams = this)
+
+ initializeCardPosition(cardLayout)
+ cardLayout.let {
addView(it, 0)
- deckMap.put(it, CardOperator(this, it, adapterPosition++, cardCallback))
+ deckMap[it] = CardOperator(this, it, adapterPosition++, cardCallback)
+ val newCard = adapter?.getView(adapterPosition, null, it)
+ it.addOverlays(newCard, rightOverlay, leftOverlay)
}
} else if (isNeedCircleLoading) {
- adapterPosition = 0
- addCardToDeck()
+ adapterPosition = -1
+ dataSetObservable?.onChanged()
}
}
@@ -94,10 +102,8 @@ class Koloda : FrameLayout {
private fun initializeCardPosition(view: View?) {
val childCount = childCount - dyingViews.size
- scaleView(view, 0f, childCount)
+ scaleView(view, childCount = childCount)
view?.translationY = (cardPositionOffsetY * childCount).toFloat()
- Log.i("----> elem init", childCount.toString())
- Log.i("----> translation init", view?.translationY.toString())
setZTranslations(childCount)
}
@@ -123,25 +129,26 @@ class Koloda : FrameLayout {
}
}
- fun getMaxCardWidth(cardView: View): Float = cardView.height * Math.tan(Math.toRadians(cardRotationDegrees.toDouble())).toFloat()
+ fun getMaxCardWidth(cardView: View): Float = cardView.height * Math.tan(Math
+ .toRadians(cardRotationDegrees.toDouble())).toFloat()
+ /**
+ * Checks capability of card view swiping
+ *
+ * @param - card of Desk
+ */
fun canSwipe(card: View): Boolean {
- Log.e("====>Swipe ", swipeEnabled.toString())
- Log.e("====>Active viewsempty ", activeViews.isEmpty().toString())
- Log.e("====>Or contains ", (activeViews.contains(card)).toString())
- Log.e("====>Index ", (indexOfChild(card) >= childCount - 2).toString())
return (swipeEnabled && (activeViews.isEmpty() || activeViews.contains(card))
&& indexOfChild(card) >= childCount - 2)
}
private fun updateDeckCardsPosition(progress: Float) {
- val visibleChildCount = Math.min(childCount, maxVisibleCards + 1)
- var childCount = Math.min(childCount, maxVisibleCards)
+ val childCount = Math.min(childCount, maxVisibleCards)
var cardsWillBeMoved = 0
var cardView: View
- (0 until visibleChildCount).map {
+ (0 until childCount).map {
cardView = getChildAt(it)
if (deckMap.containsKey(cardView) && deckMap[cardView]?.isBeingDragged != true) {
cardsWillBeMoved++
@@ -151,18 +158,23 @@ class Koloda : FrameLayout {
if (progress != 0.0f) {
for (i in 0 until cardsWillBeMoved) {
cardView = getChildAt(i)
- cardView.translationY = (cardPositionOffsetY * Math.min(cardsWillBeMoved, visibleChildCount - i - 1) - cardPositionOffsetY * Math.abs(progress))
+ cardView.translationY = (cardPositionOffsetY * Math
+ .min(cardsWillBeMoved, maxVisibleCards - i - 1) - cardPositionOffsetY * Math.abs(progress))
}
}
}
- private fun scaleView(view: View?, progress: Float, childCount: Int) {
- val currentScale = 1f - (childCount * DEFAULT_SCALE_DIFF)
- val nextScale = 1f - ((childCount - 1) * DEFAULT_SCALE_DIFF)
+ private fun scaleView(view: View?, progress: Float = 0f, childCount: Int) {
+ val currentScale = 1f - (childCount * scaleDiff)
+ val nextScale = 1f - ((childCount - 1) * scaleDiff)
val scale = currentScale + (nextScale - currentScale) * Math.abs(progress)
if (scale <= 1f) {
view?.scaleX = scale
view?.scaleY = scale
+ if (alphaAnimation) {
+ (view as CardLayout).layoutAlpha = scale
+ }
+
}
}
@@ -171,6 +183,13 @@ class Koloda : FrameLayout {
card.rotation = rotation
}
+ override fun onParamsMeasure(layoutParamsCardView: LayoutParams) {
+ cardXPos = layoutParamsCardView.leftMargin
+ cardYPos = layoutParamsCardView.topMargin + cardPositionOffsetY + cardPositionOffsetY
+ cardWidth = layoutParamsCardView.width
+ cardHeight = layoutParamsCardView.height
+ }
+
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
if (changed) {
@@ -198,6 +217,7 @@ class Koloda : FrameLayout {
private fun createDataSetObserver(): DataSetObserver {
dataSetObservable = object : DataSetObserver() {
+
override fun onChanged() {
super.onChanged()
addCards()
@@ -211,6 +231,7 @@ class Koloda : FrameLayout {
}
private fun addCards() {
+
val childCount = childCount - dyingViews.size
for (i in childCount until maxVisibleCards) {
addCardToDeck()
@@ -222,6 +243,7 @@ class Koloda : FrameLayout {
}
private var cardCallback: CardCallback = object : CardCallback {
+
override fun onCardActionDown(adapterPosition: Int, card: View) {
activeViews.add(card)
}
@@ -235,8 +257,8 @@ class Koloda : FrameLayout {
updateDeckCardsPosition(offsetProgress)
}
- override fun onCardActionUp(adapterPosition: Int, card: View, isCardNeedRemove: Boolean) {
- if (isCardNeedRemove) {
+ override fun onCardActionUp(adapterPosition: Int, card: View, isCardRemove: Boolean) {
+ if (isCardRemove) {
activeViews.remove(card)
}
}
@@ -297,29 +319,36 @@ class Koloda : FrameLayout {
}
fun onClickRight() {
- val childCount = childCount
- val topCard = getChildAt(childCount - 1 - dyingViews.size)
- topCard?.let {
- activeViews.add(it)
- val cardOperator: CardOperator? = deckMap[it]
- cardOperator?.onClickRight()
- it.rotation = 10f
- }
+ onButtonClick(true)
}
fun onClickLeft() {
+ onButtonClick(false)
+ }
+
+ /**
+ * Button right or left click remove card from desk
+ * @param isSwipeCardToRight - true for right click remove aimation false for left click
+ * remove animation
+ */
+ fun onButtonClick(isSwipeCardToRight: Boolean) {
val childCount = childCount
val topCard = getChildAt(childCount - 1 - dyingViews.size)
topCard?.let {
activeViews.add(it)
val cardOperator: CardOperator? = deckMap[it]
- cardOperator?.onClickLeft()
- it.rotation = -10f
+ if (isSwipeCardToRight) {
+ cardOperator?.onClickRight()
+ it.rotation = 10f
+ } else {
+ cardOperator?.onClickLeft()
+ it.rotation = -10f
+ }
}
}
private fun findPositionAfterClick() {
- var childCount = Math.min(childCount, maxVisibleCards)
+ val childCount = Math.min(childCount, maxVisibleCards)
(0 until childCount).map {
val view = getChildAt(it)
scaleView(view, 0f, childCount - it - 1)
@@ -327,4 +356,69 @@ class Koloda : FrameLayout {
}
}
+ /**
+ * Reload all data. Start show data from the beginning
+ */
+ fun reloadAdapterData() {
+ removeAllViews()
+ adapterPosition = 0
+ dataSetObservable?.onChanged()
+ }
+
+ /**
+ * Reload previous card after every call. If current card position in adapter == 0 this method do nothing
+ */
+ fun reloadPreviousCard() {
+ if (isNeedCircleLoading) {
+ var pos = adapterPosition - (DEFAULT_MAX_VISIBLE_CARDS)
+ if (pos < 0)
+ pos = adapter?.count?.plus(pos) ?: 0
+
+ addCardOnTop(pos)
+
+ } else {
+ addCardOnTop(adapterPosition - (DEFAULT_MAX_VISIBLE_CARDS))
+ }
+ }
+
+ private fun addCardOnTop(position: Int) {
+ removeView(getChildAt(0))
+ activeViews.clear()
+ adapterPosition = position + 2
+ adapter?.let {
+ if (adapterPosition >= it.count) {
+ adapterPosition -= it.count
+ }
+ }
+
+ val cardLayout = CardLayout(context, cardParams = this)
+
+ cardLayout.let {
+ addView(it, Math.min(childCount, maxVisibleCards + 1))
+ val newCard = adapter?.getView(position, null, it)
+ deckMap[it] = CardOperator(this, it, position, cardCallback)
+ it.addOverlays(newCard, rightOverlay, leftOverlay)
+ animateWhenAddOnTop()
+ dataSetObservable?.onChanged()
+ }
+ }
+
+ private fun animateWhenAddOnTop() {
+ val visibleChildCount = Math.min(childCount, maxVisibleCards + 1)
+ val childCount = Math.min(childCount, maxVisibleCards)
+
+ (0 until visibleChildCount).map {
+ val view = getChildAt(it)
+ val count = childCount - it - 1
+ scaleView(view, childCount = count)
+ view?.translationY = (cardPositionOffsetY * count).toFloat()
+ }
+ }
+
+ companion object {
+ private const val DEFAULT_MAX_VISIBLE_CARDS = 3
+ private const val DEFAULT_ROTATION_ANGLE = 30f
+ private const val DEFAULT_SCALE_DIFF = 0.04f
+ }
+
}
\ No newline at end of file
diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml
index bf953be..23359bd 100644
--- a/library/src/main/res/values/attrs.xml
+++ b/library/src/main/res/values/attrs.xml
@@ -4,9 +4,10 @@
-
+
+
\ No newline at end of file