diff --git a/Library/build.gradle b/Library/build.gradle index f492988..8d0c4ce 100644 --- a/Library/build.gradle +++ b/Library/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' android { compileSdkVersion 29 diff --git a/Library/src/main/java/com/sunzn/banner/library/Banner.java b/Library/src/main/java/com/sunzn/banner/library/Banner.java deleted file mode 100644 index d7990f4..0000000 --- a/Library/src/main/java/com/sunzn/banner/library/Banner.java +++ /dev/null @@ -1,477 +0,0 @@ -package com.sunzn.banner.library; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.GradientDrawable; -import android.os.Handler; -import android.util.AttributeSet; -import android.util.Log; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; - -import androidx.annotation.NonNull; -import androidx.appcompat.widget.AppCompatImageView; -import androidx.core.view.GravityCompat; -import androidx.lifecycle.LifecycleOwner; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.PagerSnapHelper; -import androidx.recyclerview.widget.RecyclerView; - -import java.util.ArrayList; -import java.util.List; - -/** - * Created by sunzn on 2017/3/31. - */ - -public class Banner extends BannerBaseView { - - private final String TAG = "Banner"; - - public interface OnItemClickListener { - - void onItemClick(int position, T item); - - } - - public interface OnItemPickListener { - - void onItemPick(int position, T item); - - } - - public interface OnItemBindListener { - - void onItemBind(int position, T item, ImageView view); - - } - - private static final int DEFAULT_GAIN_COLOR = 0xffffffff; - private static final int DEFAULT_MISS_COLOR = 0x50ffffff; - - private final Object mLock = new Object(); - - private boolean mAttached; - - private int mIndicatorMargin; - private int mIndicatorGravity; - - private RecyclerView mRecyclerView; - private LinearLayout mLinearLayout; - - private BannerAdapter mBannerAdapter; - - private Handler mHandler = new Handler(); - - private boolean isPlaying, mIsIndicatorShow, mNestedEnabled; - - IntentFilter mFilter = new IntentFilter(); - - private List mData = new ArrayList<>(); - - private OnItemPickListener mOnItemPickListener; - - private OnItemBindListener mOnItemBindListener; - - private OnItemClickListener mOnItemClickListener; - - private Drawable mIndicatorGainDrawable, mIndicatorMissDrawable; - - private int mInterval, mCurrentIndex, mIndicatorSize, mIndicatorSpace; - - private Runnable mBannerTask = new Runnable() { - - @Override - public void run() { - if (isPlaying) { - int firstPos = ((BannerLayoutManager) mRecyclerView.getLayoutManager()).findFirstVisibleItemPosition(); - if (firstPos >= mCurrentIndex) { - mRecyclerView.smoothScrollToPosition(++mCurrentIndex); - switchIndicator(); - mHandler.postDelayed(this, mInterval); - } else { - mHandler.postDelayed(this, mInterval * 2); - } - } - } - - }; - - public Banner(Context context) { - this(context, null); - } - - public Banner(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public Banner(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context, attrs); - } - - private void init(Context context, AttributeSet attrs) { - TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.Banner); - Drawable GainDrawable = attributes.getDrawable(R.styleable.Banner_indicator_gain); - Drawable MissDrawable = attributes.getDrawable(R.styleable.Banner_indicator_miss); - mIndicatorGravity = attributes.getInt(R.styleable.Banner_indicator_gravity, 1); - mIsIndicatorShow = attributes.getBoolean(R.styleable.Banner_indicator_show, true); - mNestedEnabled = attributes.getBoolean(R.styleable.Banner_nested_enabled, true); - float mInch = attributes.getFloat(R.styleable.Banner_banner_inch, 100f); - mInterval = attributes.getInt(R.styleable.Banner_banner_interval, 3000); - mIndicatorSize = attributes.getDimensionPixelSize(R.styleable.Banner_indicator_size, 0); - mIndicatorSpace = attributes.getDimensionPixelSize(R.styleable.Banner_indicator_space, dp2px(4)); - mIndicatorMargin = attributes.getDimensionPixelSize(R.styleable.Banner_indicator_margin, dp2px(8)); - - if (GainDrawable == null) { - mIndicatorGainDrawable = getDefaultDrawable(DEFAULT_GAIN_COLOR); - } else { - if (GainDrawable instanceof ColorDrawable) { - mIndicatorGainDrawable = getDefaultDrawable(GainDrawable); - } else { - mIndicatorGainDrawable = GainDrawable; - } - } - - if (MissDrawable == null) { - mIndicatorMissDrawable = getDefaultDrawable(DEFAULT_MISS_COLOR); - } else { - if (MissDrawable instanceof ColorDrawable) { - mIndicatorMissDrawable = getDefaultDrawable(MissDrawable); - } else { - mIndicatorMissDrawable = MissDrawable; - } - } - - switch (mIndicatorGravity) { - case 0: - mIndicatorGravity = GravityCompat.START; - break; - case 1: - mIndicatorGravity = Gravity.CENTER; - break; - case 2: - mIndicatorGravity = GravityCompat.END; - break; - } - - attributes.recycle(); - - mRecyclerView = new RecyclerView(context); - mLinearLayout = new LinearLayout(context); - - mFilter.addAction(Intent.ACTION_SCREEN_ON); - mFilter.addAction(Intent.ACTION_SCREEN_OFF); - mFilter.addAction(Intent.ACTION_USER_PRESENT); - - new PagerSnapHelper().attachToRecyclerView(mRecyclerView); - mBannerAdapter = new BannerAdapter(); - mRecyclerView.setAdapter(mBannerAdapter); - mRecyclerView.setOverScrollMode(OVER_SCROLL_NEVER); - mRecyclerView.setNestedScrollingEnabled(mNestedEnabled); - mRecyclerView.setLayoutManager(new BannerLayoutManager(context, LinearLayoutManager.HORIZONTAL, false, mInch)); - mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { - super.onScrollStateChanged(recyclerView, newState); - if (newState == RecyclerView.SCROLL_STATE_IDLE) { - int sPos = ((BannerLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition(); - int ePos = ((BannerLayoutManager) recyclerView.getLayoutManager()).findLastVisibleItemPosition(); - if (sPos == ePos && mCurrentIndex != ePos) { - mCurrentIndex = ePos; - switchIndicator(); - } - } - } - }); - - LayoutParams recyclerViewParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); - LayoutParams linearLayoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - linearLayoutParams.gravity = Gravity.BOTTOM | mIndicatorGravity; - linearLayoutParams.setMargins(mIndicatorMargin, mIndicatorMargin, mIndicatorMargin, mIndicatorMargin); - mLinearLayout.setOrientation(LinearLayout.HORIZONTAL); - mLinearLayout.setGravity(Gravity.CENTER); - - addView(mRecyclerView, recyclerViewParams); - addView(mLinearLayout, linearLayoutParams); - } - - private Drawable getDefaultDrawable(Drawable drawable) { - return getDefaultDrawable(((ColorDrawable) drawable).getColor()); - } - - private Drawable getDefaultDrawable(int color) { - GradientDrawable gradient = new GradientDrawable(); - gradient.setSize(dp2px(6), dp2px(6)); - gradient.setCornerRadius(dp2px(6)); - gradient.setColor(color); - return gradient; - } - - public void setDefaultGainColor(int color) { - mIndicatorGainDrawable = getDefaultDrawable(color); - } - - public void setDefaultMissColor(int color) { - mIndicatorMissDrawable = getDefaultDrawable(color); - } - - public void setIndicatorGravity(int gravity) { - mIndicatorGravity = gravity; - LayoutParams params = (LayoutParams) mLinearLayout.getLayoutParams(); - params.gravity = Gravity.BOTTOM | mIndicatorGravity; - mLinearLayout.setLayoutParams(params); - } - - public void setIndicatorMargin(int margin) { - mIndicatorMargin = dp2px(margin); - LayoutParams params = (LayoutParams) mLinearLayout.getLayoutParams(); - params.setMargins(mIndicatorMargin, mIndicatorMargin, mIndicatorMargin, mIndicatorMargin); - mLinearLayout.setLayoutParams(params); - } - - private void createIndicators() { - if (mLinearLayout != null) { - if (mIsIndicatorShow) { - mLinearLayout.removeAllViews(); - mLinearLayout.setVisibility(VISIBLE); - for (int i = 0; i < (mData == null ? 0 : mData.size()); i++) { - AppCompatImageView img = new AppCompatImageView(getContext()); - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - lp.leftMargin = mIndicatorSpace / 2; - lp.rightMargin = mIndicatorSpace / 2; - if (mIndicatorSize >= dp2px(4)) { - lp.width = lp.height = mIndicatorSize; - } else { - img.setMinimumWidth(dp2px(2)); - img.setMinimumHeight(dp2px(2)); - } - img.setImageDrawable(i == 0 ? mIndicatorGainDrawable : mIndicatorMissDrawable); - mLinearLayout.addView(img, lp); - } - } else { - mLinearLayout.removeAllViews(); - mLinearLayout.setVisibility(GONE); - } - } - } - - private void switchIndicator() { - if (mData != null && mData.size() > 0) { - int position = mCurrentIndex % mData.size(); - - if (mIsIndicatorShow && mLinearLayout != null && mLinearLayout.getChildCount() > 0) { - for (int i = 0; i < mLinearLayout.getChildCount(); i++) { - ((AppCompatImageView) mLinearLayout.getChildAt(i)).setImageDrawable(i == position ? mIndicatorGainDrawable : mIndicatorMissDrawable); - } - } - - if (mOnItemPickListener != null) { - mOnItemPickListener.onItemPick(position, mData.get(position)); - } - } - } - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - switch (ev.getAction()) { - case MotionEvent.ACTION_DOWN: - setPlaying(false); - break; - case MotionEvent.ACTION_MOVE: - break; - case MotionEvent.ACTION_UP: - setPlaying(true); - break; - case MotionEvent.ACTION_CANCEL: - setPlaying(true); - break; - } - return super.dispatchTouchEvent(ev); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - Log.e(TAG, "Banner onAttachedToWindow"); - setPlaying(true); - regReceiver(); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - Log.e(TAG, "Banner onDetachedFromWindow"); - setPlaying(false); - unrReceiver(); - } - - @Override - public void onResume(@NonNull LifecycleOwner owner) { - super.onResume(owner); - setPlaying(true); - } - - @Override - public void onPause(@NonNull LifecycleOwner owner) { - super.onPause(owner); - setPlaying(false); - } - - public void setBannerData(List data) { - setPlaying(false); - if (data != null && data.size() > 0) { - if (data.size() > 1) { - mData.clear(); - mData.addAll(data); - mIsIndicatorShow = true; - mCurrentIndex = mData.size() * 100000; - mBannerAdapter.notifyDataSetChanged(); - mRecyclerView.scrollToPosition(mCurrentIndex); - createIndicators(); - setPlaying(true); - } else { - mData.clear(); - mCurrentIndex = 0; - mData.addAll(data); - mIsIndicatorShow = false; - mBannerAdapter.notifyDataSetChanged(); - createIndicators(); - } - } - } - - public void scrollToCurrentPosition() { - if (mRecyclerView != null) { - mRecyclerView.scrollToPosition(mCurrentIndex); - switchIndicator(); - } - } - - private class BannerAdapter extends RecyclerView.Adapter { - - @NonNull - @Override - public BannerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - ImageView imageView = new ImageView(parent.getContext()); - RecyclerView.LayoutParams params = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); - imageView.setScaleType(AppCompatImageView.ScaleType.CENTER_CROP); - imageView.setId(R.id.banner_image_view_id); - imageView.setLayoutParams(params); - imageView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (mOnItemClickListener != null) - mOnItemClickListener.onItemClick(mCurrentIndex % mData.size(), mData.get(mCurrentIndex % mData.size())); - } - }); - return new BannerViewHolder(imageView); - } - - @Override - public void onBindViewHolder(@NonNull BannerViewHolder holder, int position) { - if (mOnItemBindListener != null) - mOnItemBindListener.onItemBind(position % mData.size(), mData.get(position % mData.size()), holder.mImageView); - } - - @Override - public int getItemCount() { - return mData == null ? 0 : mData.size() < 2 ? mData.size() : Integer.MAX_VALUE; - } - - } - - private static class BannerViewHolder extends RecyclerView.ViewHolder { - - ImageView mImageView; - - BannerViewHolder(View itemView) { - super(itemView); - mImageView = itemView.findViewById(R.id.banner_image_view_id); - } - - } - - public void setPlaying(boolean playing) { - synchronized (mLock) { - if (playing) { - playBanner(); - } else { - stopBanner(); - } - } - } - - public void playBanner() { - if (mHandler != null && !isPlaying && mBannerAdapter.getItemCount() > 1) { - isPlaying = true; - mHandler.removeCallbacks(mBannerTask); - mHandler.postDelayed(mBannerTask, mInterval); - Log.e(TAG, "Play Banner"); - } - } - - public void stopBanner() { - if (mHandler != null) { - isPlaying = false; - mHandler.removeCallbacks(mBannerTask); - Log.e(TAG, "Stop Banner"); - } - } - - public void setOnItemClickListener(OnItemClickListener listener) { - mOnItemClickListener = listener; - } - - public void setOnItemPickListener(OnItemPickListener listener) { - mOnItemPickListener = listener; - } - - public void setOnItemBindListener(OnItemBindListener listener) { - mOnItemBindListener = listener; - } - - private int dp2px(int dp) { - return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics()); - } - - private final BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_USER_PRESENT.equals(action)) { - setPlaying(true); - } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { - setPlaying(false); - } else if (Intent.ACTION_SCREEN_ON.equals(action)) { - setPlaying(true); - } - } - }; - - private void regReceiver() { - if (!mAttached) { - mAttached = true; - getContext().registerReceiver(mReceiver, mFilter); - } - } - - private void unrReceiver() { - if (mAttached) { - getContext().unregisterReceiver(mReceiver); - mAttached = false; - } - } - -} diff --git a/Library/src/main/java/com/sunzn/banner/library/Banner.kt b/Library/src/main/java/com/sunzn/banner/library/Banner.kt new file mode 100644 index 0000000..8dd4424 --- /dev/null +++ b/Library/src/main/java/com/sunzn/banner/library/Banner.kt @@ -0,0 +1,435 @@ +package com.sunzn.banner.library + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import android.content.res.Resources +import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.Drawable +import android.graphics.drawable.GradientDrawable +import android.os.Handler +import android.util.AttributeSet +import android.util.Log +import android.util.TypedValue +import android.view.Gravity +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.ImageView +import android.widget.LinearLayout +import androidx.appcompat.widget.AppCompatImageView +import androidx.core.view.GravityCompat +import androidx.lifecycle.LifecycleOwner +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.PagerSnapHelper +import androidx.recyclerview.widget.RecyclerView +import java.util.* + +class Banner @JvmOverloads constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int = 0) : BannerBaseView(context, attrs, defStyleAttr) { + + private val TAG = "Banner" + + private val mLock = Any() + + private var mAttached: Boolean = false + + private var mIndicatorMargin: Int = 0 + private var mIndicatorGravity: Int = 0 + + private var mRecyclerView: RecyclerView? = null + private var mLinearLayout: LinearLayout? = null + + private var mBannerAdapter: BannerAdapter? = null + + private val mHandler = Handler() + + private var isPlaying: Boolean = false + private var mIsIndicatorShow: Boolean = false + private var mNestedEnabled: Boolean = false + + internal var mFilter = IntentFilter() + + private val mData = ArrayList() + + private var mOnItemPickListener: OnItemPickListener? = null + + private var mOnItemBindListener: OnItemBindListener? = null + + private var mOnItemClickListener: OnItemClickListener? = null + + private var mIndicatorGainDrawable: Drawable? = null + private var mIndicatorMissDrawable: Drawable? = null + + private var mInterval: Int = 0 + private var mCurrentIndex: Int = 0 + private var mIndicatorSize: Int = 0 + private var mIndicatorSpace: Int = 0 + + private val mBannerTask = object : Runnable { + + override fun run() { + if (isPlaying) { + val firstPos = (mRecyclerView!!.layoutManager as BannerLayoutManager).findFirstVisibleItemPosition() + if (firstPos >= mCurrentIndex) { + mRecyclerView!!.smoothScrollToPosition(++mCurrentIndex) + switchIndicator() + mHandler.postDelayed(this, mInterval.toLong()) + } else { + mHandler.postDelayed(this, (mInterval * 2).toLong()) + } + } + } + + } + + private val mReceiver = object : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + val action = intent.action + if (Intent.ACTION_USER_PRESENT == action) { + setPlaying(true) + } else if (Intent.ACTION_SCREEN_OFF == action) { + setPlaying(false) + } else if (Intent.ACTION_SCREEN_ON == action) { + setPlaying(true) + } + } + } + + interface OnItemClickListener { + + fun onItemClick(position: Int, item: T) + + } + + interface OnItemPickListener { + + fun onItemPick(position: Int, item: T) + + } + + interface OnItemBindListener { + + fun onItemBind(position: Int, item: T, view: ImageView) + + } + + init { + init(context, attrs) + } + + private fun init(context: Context, attrs: AttributeSet?) { + val attributes = context.obtainStyledAttributes(attrs, R.styleable.Banner) + val gainDrawable = attributes.getDrawable(R.styleable.Banner_indicator_gain) + val missDrawable = attributes.getDrawable(R.styleable.Banner_indicator_miss) + mIndicatorGravity = attributes.getInt(R.styleable.Banner_indicator_gravity, 1) + mIsIndicatorShow = attributes.getBoolean(R.styleable.Banner_indicator_show, true) + mNestedEnabled = attributes.getBoolean(R.styleable.Banner_nested_enabled, true) + val mInch = attributes.getFloat(R.styleable.Banner_banner_inch, 100f) + mInterval = attributes.getInt(R.styleable.Banner_banner_interval, 3000) + mIndicatorSize = attributes.getDimensionPixelSize(R.styleable.Banner_indicator_size, 0) + mIndicatorSpace = attributes.getDimensionPixelSize(R.styleable.Banner_indicator_space, dp2px(4)) + mIndicatorMargin = attributes.getDimensionPixelSize(R.styleable.Banner_indicator_margin, dp2px(8)) + + mIndicatorGainDrawable = if (gainDrawable == null) { + getDefaultDrawable(DEFAULT_GAIN_COLOR) + } else { + if (gainDrawable is ColorDrawable) { + getDefaultDrawable(gainDrawable) + } else { + gainDrawable + } + } + + mIndicatorMissDrawable = if (missDrawable == null) { + getDefaultDrawable(DEFAULT_MISS_COLOR) + } else { + if (missDrawable is ColorDrawable) { + getDefaultDrawable(missDrawable) + } else { + missDrawable + } + } + + when (mIndicatorGravity) { + 0 -> mIndicatorGravity = GravityCompat.START + 1 -> mIndicatorGravity = Gravity.CENTER + 2 -> mIndicatorGravity = GravityCompat.END + } + + attributes.recycle() + + mRecyclerView = RecyclerView(context) + mLinearLayout = LinearLayout(context) + + mFilter.addAction(Intent.ACTION_SCREEN_ON) + mFilter.addAction(Intent.ACTION_SCREEN_OFF) + mFilter.addAction(Intent.ACTION_USER_PRESENT) + + PagerSnapHelper().attachToRecyclerView(mRecyclerView) + mBannerAdapter = BannerAdapter() + mRecyclerView!!.adapter = mBannerAdapter + mRecyclerView!!.overScrollMode = View.OVER_SCROLL_NEVER + mRecyclerView!!.isNestedScrollingEnabled = mNestedEnabled + mRecyclerView!!.layoutManager = BannerLayoutManager(context, LinearLayoutManager.HORIZONTAL, false, mInch) + mRecyclerView!!.addOnScrollListener(object : RecyclerView.OnScrollListener() { + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + super.onScrollStateChanged(recyclerView, newState) + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + val sPos = (recyclerView.layoutManager as BannerLayoutManager).findFirstVisibleItemPosition() + val ePos = (recyclerView.layoutManager as BannerLayoutManager).findLastVisibleItemPosition() + if (sPos == ePos && mCurrentIndex != ePos) { + mCurrentIndex = ePos + switchIndicator() + } + } + } + }) + + val recyclerViewParams = LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + val linearLayoutParams = LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) + linearLayoutParams.gravity = Gravity.BOTTOM or mIndicatorGravity + linearLayoutParams.setMargins(mIndicatorMargin, mIndicatorMargin, mIndicatorMargin, mIndicatorMargin) + mLinearLayout!!.orientation = LinearLayout.HORIZONTAL + mLinearLayout!!.gravity = Gravity.CENTER + + addView(mRecyclerView, recyclerViewParams) + addView(mLinearLayout, linearLayoutParams) + } + + private fun getDefaultDrawable(drawable: Drawable): Drawable { + return getDefaultDrawable((drawable as ColorDrawable).color) + } + + private fun getDefaultDrawable(color: Int): Drawable { + val gradient = GradientDrawable() + gradient.setSize(dp2px(6), dp2px(6)) + gradient.cornerRadius = dp2px(6).toFloat() + gradient.setColor(color) + return gradient + } + + fun setDefaultGainColor(color: Int) { + mIndicatorGainDrawable = getDefaultDrawable(color) + } + + fun setDefaultMissColor(color: Int) { + mIndicatorMissDrawable = getDefaultDrawable(color) + } + + fun setIndicatorGravity(gravity: Int) { + mIndicatorGravity = gravity + val params = mLinearLayout!!.layoutParams as FrameLayout.LayoutParams + params.gravity = Gravity.BOTTOM or mIndicatorGravity + mLinearLayout!!.layoutParams = params + } + + fun setIndicatorMargin(margin: Int) { + mIndicatorMargin = dp2px(margin) + val params = mLinearLayout!!.layoutParams as FrameLayout.LayoutParams + params.setMargins(mIndicatorMargin, mIndicatorMargin, mIndicatorMargin, mIndicatorMargin) + mLinearLayout!!.layoutParams = params + } + + private fun createIndicators() { + if (mLinearLayout != null) { + if (mIsIndicatorShow) { + mLinearLayout!!.removeAllViews() + mLinearLayout!!.visibility = View.VISIBLE + for (i: Int in 0 until mData.size) { + val img = AppCompatImageView(context) + val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT) + lp.leftMargin = mIndicatorSpace / 2 + lp.rightMargin = mIndicatorSpace / 2 + if (mIndicatorSize >= dp2px(4)) { + lp.height = mIndicatorSize + lp.width = lp.height + } else { + img.minimumWidth = dp2px(2) + img.minimumHeight = dp2px(2) + } + img.setImageDrawable(if (i == 0) mIndicatorGainDrawable else mIndicatorMissDrawable) + mLinearLayout!!.addView(img, lp) + } + } else { + mLinearLayout!!.removeAllViews() + mLinearLayout!!.visibility = View.GONE + } + } + } + + private fun switchIndicator() { + if (mData.size > 0) { + val position = mCurrentIndex % mData.size + + if (mIsIndicatorShow && mLinearLayout != null && mLinearLayout!!.childCount > 0) { + for (i in 0 until mLinearLayout!!.childCount) { + (mLinearLayout!!.getChildAt(i) as AppCompatImageView).setImageDrawable(if (i == position) mIndicatorGainDrawable else mIndicatorMissDrawable) + } + } + + if (mOnItemPickListener != null) { + mOnItemPickListener!!.onItemPick(position, mData[position]) + } + } + } + + override fun dispatchTouchEvent(ev: MotionEvent): Boolean { + when (ev.action) { + MotionEvent.ACTION_DOWN -> setPlaying(false) + MotionEvent.ACTION_MOVE -> { + } + MotionEvent.ACTION_UP -> setPlaying(true) + MotionEvent.ACTION_CANCEL -> setPlaying(true) + } + return super.dispatchTouchEvent(ev) + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + Log.e(TAG, "Banner onAttachedToWindow") + setPlaying(true) + regReceiver() + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + Log.e(TAG, "Banner onDetachedFromWindow") + setPlaying(false) + unrReceiver() + } + + override fun onResume(owner: LifecycleOwner) { + super.onResume(owner) + setPlaying(true) + } + + override fun onPause(owner: LifecycleOwner) { + super.onPause(owner) + setPlaying(false) + } + + fun setBannerData(data: List?) { + setPlaying(false) + if (!data.isNullOrEmpty()) { + if (data.size > 1) { + mData.clear() + mData.addAll(data) + mIsIndicatorShow = true + mCurrentIndex = mData.size * 100000 + mBannerAdapter!!.notifyDataSetChanged() + mRecyclerView!!.scrollToPosition(mCurrentIndex) + createIndicators() + setPlaying(true) + } else { + mData.clear() + mCurrentIndex = 0 + mData.addAll(data) + mIsIndicatorShow = false + mBannerAdapter!!.notifyDataSetChanged() + createIndicators() + } + } + } + + fun scrollToCurrentPosition() { + if (mRecyclerView != null) { + mRecyclerView!!.scrollToPosition(mCurrentIndex) + switchIndicator() + } + } + + private inner class BannerAdapter : RecyclerView.Adapter() { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BannerViewHolder { + val imageView = ImageView(parent.context) + val params = RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + imageView.scaleType = ImageView.ScaleType.CENTER_CROP + imageView.id = R.id.banner_image_view_id + imageView.layoutParams = params + imageView.setOnClickListener { + if (mOnItemClickListener != null) + mOnItemClickListener!!.onItemClick(mCurrentIndex % mData.size, mData[mCurrentIndex % mData.size]) + } + return BannerViewHolder(imageView) + } + + override fun onBindViewHolder(holder: BannerViewHolder, position: Int) { + if (mOnItemBindListener != null) + mOnItemBindListener!!.onItemBind(position % mData.size, mData[position % mData.size], holder.mImageView) + } + + override fun getItemCount(): Int { + return if (mData.size < 2) mData.size else Integer.MAX_VALUE + } + + } + + private class BannerViewHolder internal constructor(itemView: View) : RecyclerView.ViewHolder(itemView) { + + internal var mImageView: ImageView = itemView.findViewById(R.id.banner_image_view_id) + + } + + fun setPlaying(playing: Boolean) { + synchronized(mLock) { + if (playing) { + playBanner() + } else { + stopBanner() + } + } + } + + fun playBanner() { + if (!isPlaying && mBannerAdapter!!.itemCount > 1) { + isPlaying = true + mHandler.removeCallbacks(mBannerTask) + mHandler.postDelayed(mBannerTask, mInterval.toLong()) + Log.e(TAG, "Play Banner") + } + } + + fun stopBanner() { + isPlaying = false + mHandler.removeCallbacks(mBannerTask) + Log.e(TAG, "Stop Banner") + } + + fun setOnItemClickListener(listener: OnItemClickListener) { + mOnItemClickListener = listener + } + + fun setOnItemPickListener(listener: OnItemPickListener) { + mOnItemPickListener = listener + } + + fun setOnItemBindListener(listener: OnItemBindListener) { + mOnItemBindListener = listener + } + + private fun dp2px(dp: Int): Int { + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), Resources.getSystem().displayMetrics).toInt() + } + + private fun regReceiver() { + if (!mAttached) { + mAttached = true + context.registerReceiver(mReceiver, mFilter) + } + } + + private fun unrReceiver() { + if (mAttached) { + context.unregisterReceiver(mReceiver) + mAttached = false + } + } + + companion object { + private const val DEFAULT_GAIN_COLOR = -0x1 + private const val DEFAULT_MISS_COLOR = 0x50ffffff + } + +} diff --git a/Library/src/main/java/com/sunzn/banner/library/BannerBaseView.java b/Library/src/main/java/com/sunzn/banner/library/BannerBaseView.java deleted file mode 100644 index 2cc5144..0000000 --- a/Library/src/main/java/com/sunzn/banner/library/BannerBaseView.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.sunzn.banner.library; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.Log; -import android.widget.FrameLayout; - -import androidx.annotation.NonNull; -import androidx.lifecycle.DefaultLifecycleObserver; -import androidx.lifecycle.LifecycleOwner; - -public abstract class BannerBaseView extends FrameLayout implements DefaultLifecycleObserver { - - private final String TAG = "BannerBaseView"; - - public BannerBaseView(Context context) { - super(context); - } - - public BannerBaseView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public BannerBaseView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @Override - public void onCreate(@NonNull LifecycleOwner owner) { - Log.d(TAG, "onCreate"); - } - - @Override - public void onStart(@NonNull LifecycleOwner owner) { - Log.d(TAG, "onStart"); - } - - @Override - public void onResume(@NonNull LifecycleOwner owner) { - Log.d(TAG, "onResume"); - } - - @Override - public void onPause(@NonNull LifecycleOwner owner) { - Log.d(TAG, "onPause"); - } - - @Override - public void onStop(@NonNull LifecycleOwner owner) { - Log.d(TAG, "onStop"); - } - - @Override - public void onDestroy(@NonNull LifecycleOwner owner) { - Log.d(TAG, "onDestroy"); - } - -} diff --git a/Library/src/main/java/com/sunzn/banner/library/BannerBaseView.kt b/Library/src/main/java/com/sunzn/banner/library/BannerBaseView.kt new file mode 100644 index 0000000..f2c1c81 --- /dev/null +++ b/Library/src/main/java/com/sunzn/banner/library/BannerBaseView.kt @@ -0,0 +1,44 @@ +package com.sunzn.banner.library + +import android.content.Context +import android.util.AttributeSet +import android.util.Log +import android.widget.FrameLayout +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner + +abstract class BannerBaseView : FrameLayout, DefaultLifecycleObserver { + + private val TAG = "BannerBaseView" + + constructor(context: Context) : super(context) + + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + + override fun onCreate(owner: LifecycleOwner) { + Log.d(TAG, "onCreate") + } + + override fun onStart(owner: LifecycleOwner) { + Log.d(TAG, "onStart") + } + + override fun onResume(owner: LifecycleOwner) { + Log.d(TAG, "onResume") + } + + override fun onPause(owner: LifecycleOwner) { + Log.d(TAG, "onPause") + } + + override fun onStop(owner: LifecycleOwner) { + Log.d(TAG, "onStop") + } + + override fun onDestroy(owner: LifecycleOwner) { + Log.d(TAG, "onDestroy") + } + +} diff --git a/Library/src/main/java/com/sunzn/banner/library/BannerLayoutManager.java b/Library/src/main/java/com/sunzn/banner/library/BannerLayoutManager.java deleted file mode 100644 index 6473f22..0000000 --- a/Library/src/main/java/com/sunzn/banner/library/BannerLayoutManager.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.sunzn.banner.library; - -import android.content.Context; -import android.util.AttributeSet; -import android.util.DisplayMetrics; - -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.LinearSmoothScroller; -import androidx.recyclerview.widget.RecyclerView; - -/** - * Created by sunzn on 2017/3/31. - */ - -class BannerLayoutManager extends LinearLayoutManager { - - private static float MILLISECONDS_PER_INCH = 100f; - - private Context mContext; - - public BannerLayoutManager(Context context) { - super(context); - mContext = context; - } - - public BannerLayoutManager(Context context, int orientation, boolean reverseLayout) { - super(context, orientation, reverseLayout); - mContext = context; - } - - BannerLayoutManager(Context context, int orientation, boolean reverseLayout, float inch) { - super(context, orientation, reverseLayout); - MILLISECONDS_PER_INCH = inch; - mContext = context; - } - - public BannerLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - mContext = context; - } - - @Override - public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { - - LinearSmoothScroller mScroller = new LinearSmoothScroller(mContext) { - - @Override - protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { - return MILLISECONDS_PER_INCH / displayMetrics.densityDpi; - } - - }; - - mScroller.setTargetPosition(position); - - startSmoothScroll(mScroller); - - } -} diff --git a/Library/src/main/java/com/sunzn/banner/library/BannerLayoutManager.kt b/Library/src/main/java/com/sunzn/banner/library/BannerLayoutManager.kt new file mode 100644 index 0000000..e74ce77 --- /dev/null +++ b/Library/src/main/java/com/sunzn/banner/library/BannerLayoutManager.kt @@ -0,0 +1,52 @@ +package com.sunzn.banner.library + +import android.content.Context +import android.util.AttributeSet +import android.util.DisplayMetrics + +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.LinearSmoothScroller +import androidx.recyclerview.widget.RecyclerView + +internal class BannerLayoutManager : LinearLayoutManager { + + companion object { + private var MILLISECONDS_PER_INCH = 100f + } + + private var mContext: Context? = null + + constructor(context: Context) : super(context) { + mContext = context + } + + constructor(context: Context, orientation: Int, reverseLayout: Boolean) : super(context, orientation, reverseLayout) { + mContext = context + } + + constructor(context: Context, orientation: Int, reverseLayout: Boolean, inch: Float) : super(context, orientation, reverseLayout) { + MILLISECONDS_PER_INCH = inch + mContext = context + } + + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) { + mContext = context + } + + override fun smoothScrollToPosition(recyclerView: RecyclerView, state: RecyclerView.State?, position: Int) { + + val mScroller = object : LinearSmoothScroller(mContext!!) { + + override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float { + return MILLISECONDS_PER_INCH / displayMetrics.densityDpi + } + + } + + mScroller.targetPosition = position + + startSmoothScroll(mScroller) + + } + +} diff --git a/Sample/build.gradle b/Sample/build.gradle index 6c5f744..8a95400 100644 --- a/Sample/build.gradle +++ b/Sample/build.gradle @@ -1,4 +1,6 @@ apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' android { compileSdkVersion 29 diff --git a/Sample/src/main/java/com/sunzn/banner/sample/MainActivity.java b/Sample/src/main/java/com/sunzn/banner/sample/MainActivity.java deleted file mode 100644 index e8e3373..0000000 --- a/Sample/src/main/java/com/sunzn/banner/sample/MainActivity.java +++ /dev/null @@ -1,89 +0,0 @@ -package com.sunzn.banner.sample; - -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.view.GravityCompat; - -import android.graphics.Color; -import android.os.Bundle; -import android.util.Log; -import android.widget.ImageView; -import android.widget.Toast; - -import com.bumptech.glide.Glide; -import com.sunzn.banner.library.Banner; - -import java.util.ArrayList; -import java.util.List; - -public class MainActivity extends AppCompatActivity { - - private Banner banner; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - -// String s = "R2008060360000003"; -// -// String c = s.substring(10); -// -// int x = Integer.parseInt("R2008060360000003".substring(10)); - - Log.e("BBB",String.format("%07d", Integer.parseInt("R2008060360000109".substring(10)) + 1)); - - banner = findViewById(R.id.banner); - getLifecycle().addObserver(banner); - - banner.setDefaultGainColor(Color.RED); - banner.setIndicatorGravity(GravityCompat.END); - banner.setIndicatorMargin(15); - - final List packs = new ArrayList<>(); - packs.add(new Bean("http://desk.fd.zol-img.com.cn/t_s1024x768c5/g5/M00/0D/01/ChMkJ1gq00WIXw_GAA47r_8gjqgAAXxJAH8qOMADjvH566.jpg")); - packs.add(new Bean("http://desk.fd.zol-img.com.cn/t_s1024x768c5/g5/M00/0B/0D/ChMkJ1e9jHqIWT4CAA2dKPU9Js8AAUsZgMf8mkADZ1A116.jpg")); - packs.add(new Bean("http://desk.fd.zol-img.com.cn/t_s1024x768c5/g5/M00/0B/0D/ChMkJle9jIGIMgtdAAYnBOEz3LAAAUsZwPgFgYABicc437.jpg")); - packs.add(new Bean("http://desk.fd.zol-img.com.cn/t_s1024x768c5/g5/M00/0F/0A/ChMkJleZ8-iIBbFBAAVrdxItOlQAAT76QAFx7oABWuP846.jpg")); - packs.add(new Bean("http://desk.fd.zol-img.com.cn/t_s1024x768c5/g5/M00/0B/04/ChMkJ1bG5kyIcwkXAAsM0s9DJzoAAKsAwJB9ncACwzq207.jpg")); - - banner.setBannerData(packs); - banner.setOnItemClickListener(new Banner.OnItemClickListener() { - @Override - public void onItemClick(int position, Bean item) { - Toast.makeText(MainActivity.this, "position = " + position, Toast.LENGTH_SHORT).show(); - } - }); - banner.setOnItemBindListener(new Banner.OnItemBindListener() { - @Override - public void onItemBind(int position, Bean item, ImageView view) { - Glide.with(getApplicationContext()).load(item.getUrl()).into(view); - } - }); - } - - private class Bean { - - String url; - - Bean(String url) { - this.url = url; - } - - String getUrl() { - return url; - } - } - - @Override - protected void onResume() { - super.onResume(); - banner.setPlaying(true); - } - - @Override - protected void onPause() { - super.onPause(); - banner.setPlaying(false); - } - -} diff --git a/Sample/src/main/java/com/sunzn/banner/sample/MainActivity.kt b/Sample/src/main/java/com/sunzn/banner/sample/MainActivity.kt new file mode 100644 index 0000000..c8f41e7 --- /dev/null +++ b/Sample/src/main/java/com/sunzn/banner/sample/MainActivity.kt @@ -0,0 +1,60 @@ +package com.sunzn.banner.sample + +import android.graphics.Color +import android.os.Bundle +import android.widget.ImageView +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.GravityCompat +import com.bumptech.glide.Glide +import com.sunzn.banner.library.Banner +import java.util.* + +class MainActivity : AppCompatActivity() { + + private var banner: Banner? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + + banner = findViewById(R.id.banner) + lifecycle.addObserver(banner!!) + + banner!!.setDefaultGainColor(Color.RED) + banner!!.setIndicatorGravity(GravityCompat.END) + banner!!.setIndicatorMargin(15) + + val packs = ArrayList() + packs.add(Bean("http://desk.fd.zol-img.com.cn/t_s1024x768c5/g5/M00/0D/01/ChMkJ1gq00WIXw_GAA47r_8gjqgAAXxJAH8qOMADjvH566.jpg")) + packs.add(Bean("http://desk.fd.zol-img.com.cn/t_s1024x768c5/g5/M00/0B/0D/ChMkJ1e9jHqIWT4CAA2dKPU9Js8AAUsZgMf8mkADZ1A116.jpg")) + packs.add(Bean("http://desk.fd.zol-img.com.cn/t_s1024x768c5/g5/M00/0B/0D/ChMkJle9jIGIMgtdAAYnBOEz3LAAAUsZwPgFgYABicc437.jpg")) + packs.add(Bean("http://desk.fd.zol-img.com.cn/t_s1024x768c5/g5/M00/0F/0A/ChMkJleZ8-iIBbFBAAVrdxItOlQAAT76QAFx7oABWuP846.jpg")) + packs.add(Bean("http://desk.fd.zol-img.com.cn/t_s1024x768c5/g5/M00/0B/04/ChMkJ1bG5kyIcwkXAAsM0s9DJzoAAKsAwJB9ncACwzq207.jpg")) + + banner!!.setBannerData(packs) + banner!!.setOnItemClickListener(object : Banner.OnItemClickListener { + override fun onItemClick(position: Int, item: Bean) { + Toast.makeText(this@MainActivity, "position = $position", Toast.LENGTH_SHORT).show() + } + }) + banner!!.setOnItemBindListener(object : Banner.OnItemBindListener { + override fun onItemBind(position: Int, item: Bean, view: ImageView) { + Glide.with(applicationContext).load(item.url).into(view) + } + }) + } + + private inner class Bean internal constructor(internal var url: String) + + override fun onResume() { + super.onResume() + banner!!.setPlaying(true) + } + + override fun onPause() { + super.onPause() + banner!!.setPlaying(false) + } + +} diff --git a/build.gradle b/build.gradle index 48947c3..e3245e7 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext.kotlin_version = '1.3.50' repositories { google() jcenter() @@ -8,7 +9,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:3.5.1' - + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files }