├── LICENSE
├── README.md
├── Untitled Document.md.pdf
└── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
├── androidTest
└── java
│ └── com
│ └── example
│ └── zzh
│ └── channelmanagedemo_kotlin
│ └── ExampleInstrumentedTest.kt
├── main
├── AndroidManifest.xml
├── assets
│ └── ezgif-5-d492977e87_kotlin.gif
├── java
│ └── com
│ │ └── example
│ │ └── zzh
│ │ └── channelmanagedemo_kotlin
│ │ ├── ChannelAdapter.kt
│ │ ├── ChannelBean.kt
│ │ ├── Ex.kt
│ │ ├── GridSpacingItemDecoration.kt
│ │ ├── ItemDragCallback.kt
│ │ └── MainActivity.kt
└── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ ├── ic_launcher_background.xml
│ └── icon_close.png
│ ├── layout
│ ├── activity_main.xml
│ ├── adapter_channel.xml
│ ├── adapter_more_channel.xml
│ ├── adapter_tab.xml
│ └── adapter_title.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ └── ic_launcher_round.png
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
└── test
└── java
└── com
└── example
└── zzh
└── channelmanagedemo_kotlin
└── ExampleUnitTest.kt
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 zzh12138
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ChannelManageDemo_Kotlin
2 | https://www.jianshu.com/p/57324eb516df
3 | ###### ChannelManageDemo by kotlin
4 | ### 高仿腾讯新闻频道管理页面
5 | #### 使用kotlin语言编写,用recyclerView+ItemTouchHelper实现
6 | 
7 | ## License
8 | MIT
9 |
--------------------------------------------------------------------------------
/Untitled Document.md.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzh12138/ChannelManageDemo_Kotlin/5019cc796c65b42c7f4fb7b62088135b55e34a48/Untitled Document.md.pdf
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | apply plugin: 'kotlin-android'
4 |
5 | apply plugin: 'kotlin-android-extensions'
6 |
7 | android {
8 | compileSdkVersion 26
9 | defaultConfig {
10 | applicationId "com.example.zzh.channelmanagedemo_kotlin"
11 | minSdkVersion 15
12 | targetSdkVersion 26
13 | versionCode 1
14 | versionName "1.0"
15 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
16 | }
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: 'libs', include: ['*.jar'])
27 | implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
28 | implementation 'com.android.support:appcompat-v7:26.1.0'
29 | compile 'com.android.support:recyclerview-v7:26.1.0'
30 | implementation 'com.android.support.constraint:constraint-layout:1.0.2'
31 | testImplementation 'junit:junit:4.12'
32 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
33 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
34 | }
35 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/zzh/channelmanagedemo_kotlin/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.zzh.channelmanagedemo_kotlin
2 |
3 | import android.support.test.InstrumentationRegistry
4 | import android.support.test.runner.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getTargetContext()
22 | assertEquals("com.example.zzh.channelmanagedemo_kotlin", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/assets/ezgif-5-d492977e87_kotlin.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzh12138/ChannelManageDemo_Kotlin/5019cc796c65b42c7f4fb7b62088135b55e34a48/app/src/main/assets/ezgif-5-d492977e87_kotlin.gif
--------------------------------------------------------------------------------
/app/src/main/java/com/example/zzh/channelmanagedemo_kotlin/ChannelAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.example.zzh.channelmanagedemo_kotlin
2 |
3 | import android.animation.Animator
4 | import android.animation.AnimatorListenerAdapter
5 | import android.animation.AnimatorSet
6 | import android.animation.ObjectAnimator
7 | import android.content.Context
8 | import android.graphics.Typeface
9 | import android.support.v7.widget.RecyclerView
10 | import android.view.LayoutInflater
11 | import android.view.View
12 | import android.view.ViewGroup
13 | import android.view.ViewTreeObserver
14 | import android.widget.ImageView
15 | import android.widget.LinearLayout
16 | import android.widget.TextView
17 | import java.util.*
18 |
19 | /**
20 | * Created by zhangzhihao on 2018/3/6.
21 | */
22 | class ChannelAdapter(var mContext: Context, var mList: ArrayList, var recommendList: ArrayList, var cityList: ArrayList)
23 | : RecyclerView.Adapter() {
24 | var selectedSize: Int = 0 //已选
25 | var fixSize: Int = 0 //固定频道数目
26 | var isRecommend: Boolean = true //当前是否显示推荐频道
27 | var mLeft: Int = -1 //推荐频道蓝色线条距离屏幕左边的距离
28 | var mRight: Int = -1 //城市频道蓝色线条距离屏幕左边的距离
29 | var mTabY: Int = 0 //tab距离parent的Y的距离
30 | var onItemRangeChangeListener: OnItemRangeChangeListener? = null
31 |
32 | override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
33 | val view = LayoutInflater.from(mContext).inflate(viewType, parent, false)
34 | return when (viewType) {
35 | R.layout.adapter_channel -> ChannelHolder(view)
36 | R.layout.adapter_more_channel -> MoreChannelHolder(view)
37 | R.layout.adapter_tab -> TabHolder(view)
38 | else -> TitleHolder(view)
39 | }
40 | }
41 |
42 | override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {
43 | if (holder is ChannelHolder) {
44 | setChannel(holder, position)
45 | } else if (holder is TabHolder) {
46 | setTab(holder)
47 | }
48 |
49 | }
50 |
51 | override fun getItemCount(): Int {
52 | return mList.size
53 | }
54 |
55 | override fun getItemViewType(position: Int): Int {
56 | return mList[position].layoutId
57 | }
58 |
59 | private fun setChannel(holder: ChannelHolder, position: Int) {
60 | holder.name.text = mList[position].name
61 | holder.name.setOnClickListener {
62 | if (holder.layoutPosition < selectedSize + 1) {
63 | //tab上面的 点击移除
64 | if (holder.layoutPosition > fixSize) {
65 | removeFromSelected(holder)
66 | }
67 | } else {
68 | //tab下面的 点击添加到已选频道
69 | selectedSize++
70 | itemMove(holder.layoutPosition, selectedSize)
71 | notifyItemChanged(selectedSize)
72 | //刷新itemDecoration
73 | onItemRangeChangeListener?.let { onItemRangeChangeListener!!.refreshItemDecoration() }
74 | }
75 | }
76 | holder.name.setOnLongClickListener { true }
77 | holder.delete.setOnClickListener { removeFromSelected(holder) }
78 | //tab下面及固定频道不显示删除按钮
79 | if (position - 1 < fixSize || position > selectedSize) {
80 | holder.delete.visibility = View.GONE
81 | } else {
82 | holder.delete.visibility = View.VISIBLE
83 | }
84 | }
85 |
86 | private fun setTab(holder: TabHolder) {
87 | val params = holder.indicator.layoutParams as LinearLayout.LayoutParams
88 | //计算蓝色线条位置
89 | if (mLeft == -1) {
90 | holder.recommend.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
91 | override fun onPreDraw(): Boolean {
92 | val layout = holder.recommend.layout
93 | //textView左边距离+第一个文字绘制位置-padding
94 | mLeft = (holder.recommend.left + layout.getPrimaryHorizontal(0) - mContext.dip2px(10f)).toInt()
95 | params.leftMargin = mLeft;
96 | holder.indicator.layoutParams = params
97 | holder.recommend.viewTreeObserver.removeOnPreDrawListener(this)
98 | return true
99 | }
100 | })
101 | }
102 |
103 | holder.city.setOnClickListener {
104 | if (isRecommend) {
105 | holder.city.typeface = Typeface.DEFAULT_BOLD
106 | holder.recommend.typeface = Typeface.DEFAULT
107 | if (mRight == -1) {
108 | mRight = (mLeft + holder.city.left - mContext.dip2px(10f)).toInt()
109 | }
110 | params.leftMargin = mRight
111 | isRecommend = false
112 | recommendList.clear()
113 | recommendList.addAll(mList.subList(selectedSize + 2, mList.size))
114 | mList.removeAll(recommendList)
115 | mList.addAll(cityList)
116 | notifyDataSetChanged()
117 | }
118 | }
119 |
120 | holder.recommend.setOnClickListener {
121 | if (!isRecommend) {
122 | holder.city.typeface = Typeface.DEFAULT
123 | holder.recommend.typeface = Typeface.DEFAULT_BOLD
124 | params.leftMargin = mLeft
125 | isRecommend = true
126 | cityList.clear()
127 | cityList.addAll(mList.subList(selectedSize + 2, mList.size))
128 | mList.removeAll(cityList)
129 | mList.addAll(recommendList)
130 | notifyDataSetChanged()
131 | }
132 | }
133 | holder.itemView.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
134 | override fun onPreDraw(): Boolean {
135 | mTabY = holder.itemView.top
136 | return true
137 | }
138 |
139 | })
140 |
141 | }
142 |
143 | private fun removeFromSelected(holder: ChannelHolder) {
144 | holder.delete.visibility = View.GONE
145 | val position = holder.layoutPosition
146 | val bean = mList[position]
147 | if ((isRecommend && bean.isRecommend) || (!isRecommend && !bean.isRecommend)) {
148 | //移除的频道属于当前tab显示的频道,直接调用系统方法移除
149 | itemMove(position, selectedSize + 1)
150 | notifyItemRangeChanged(selectedSize + 1, 1)
151 | //刷新itemDecoration
152 | onItemRangeChangeListener?.let { onItemRangeChangeListener!!.refreshItemDecoration() }
153 | } else {
154 | //不属于当前tab显示的频道
155 | removeAnimation(holder.itemView, (if (isRecommend) mRight else mLeft).toFloat(), mTabY.toFloat(), position)
156 | }
157 | selectedSize--
158 | }
159 |
160 | private fun removeAnimation(view: View, x: Float, y: Float, position: Int) {
161 | val fromX = view.left
162 | val fromY = view.top
163 | val animatorX = ObjectAnimator.ofFloat(view, "translationX", 0f, x - fromX)
164 | val animatorY = ObjectAnimator.ofFloat(view, "translationY", 0f, y - fromY)
165 | val alpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f)
166 | val set = AnimatorSet()
167 | set.playTogether(animatorX, animatorY, alpha)
168 | set.duration = 350
169 | set.addListener(object : Animator.AnimatorListener {
170 | override fun onAnimationRepeat(animation: Animator?) {
171 | }
172 |
173 | override fun onAnimationCancel(animation: Animator?) {
174 | }
175 |
176 | override fun onAnimationStart(animation: Animator?) {
177 | }
178 |
179 | override fun onAnimationEnd(animation: Animator?) {
180 | if (isRecommend) {
181 | cityList.add(0, mList[position])
182 | } else {
183 | recommendList.add(0, mList[position])
184 | }
185 | mList.removeAt(position)
186 | notifyItemRemoved(position)
187 | onItemRangeChangeListener?.let { onItemRangeChangeListener!!.refreshItemDecoration() }
188 | //这里需要重置view的属性
189 | resetView(view, x - fromX, y - fromY)
190 | }
191 | })
192 | set.start()
193 | }
194 |
195 | private fun resetView(view: View, toX: Float, toY: Float) {
196 | val animatorX = ObjectAnimator.ofFloat(view, "translationX", -toX, 0f)
197 | val animatorY = ObjectAnimator.ofFloat(view, "translationY", -toY, 0f)
198 | val alpha = ObjectAnimator.ofFloat(view, "alpha", 0f, 1f)
199 | val set = AnimatorSet()
200 | set.playTogether(animatorX, animatorY, alpha)
201 | set.duration = 0
202 | set.startDelay = 5
203 | set.start()
204 | }
205 |
206 | fun itemMove(fromPosition: Int, toPosition: Int) {
207 | if (fromPosition < toPosition) {
208 | for (i in fromPosition until toPosition) {
209 | Collections.swap(mList, i, i + 1)
210 | }
211 | } else {
212 | for (i in fromPosition downTo toPosition + 1) {
213 | Collections.swap(mList, i, i - 1)
214 | }
215 | }
216 | notifyItemMoved(fromPosition, toPosition)
217 | }
218 |
219 | class ChannelHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
220 | val name: TextView = itemView.findViewById(R.id.channel_name)
221 | val delete: ImageView = itemView.findViewById(R.id.channel_delete)
222 | }
223 |
224 | class TabHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
225 | val recommend: TextView = itemView.findViewById(R.id.recommend_channel)
226 | val city: TextView = itemView.findViewById(R.id.city_channel)
227 | val indicator: View = itemView.findViewById(R.id.indicator)
228 | }
229 |
230 | class MoreChannelHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
231 | class TitleHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
232 |
233 | interface OnItemRangeChangeListener {
234 | fun refreshItemDecoration()
235 | }
236 |
237 | }
238 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/zzh/channelmanagedemo_kotlin/ChannelBean.kt:
--------------------------------------------------------------------------------
1 | package com.example.zzh.channelmanagedemo_kotlin
2 |
3 | /**
4 | * Created by zhangzhihao on 2018/3/6.
5 | */
6 | class ChannelBean(var name:String ,var spanSize:Int ,var layoutId: Int,var isRecommend: Boolean){
7 | }
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/zzh/channelmanagedemo_kotlin/Ex.kt:
--------------------------------------------------------------------------------
1 | package com.example.zzh.channelmanagedemo_kotlin
2 |
3 | import android.content.Context
4 |
5 | /**
6 | * Created by zhangzhihao on 2018/3/6.
7 | */
8 | fun Context.dip2px(value:Float): Float {
9 | val scale=this.resources.displayMetrics.density
10 | return value*scale+0.5f
11 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/zzh/channelmanagedemo_kotlin/GridSpacingItemDecoration.kt:
--------------------------------------------------------------------------------
1 | package com.example.zzh.channelmanagedemo_kotlin
2 |
3 | import android.graphics.Rect
4 | import android.support.v7.widget.RecyclerView
5 | import android.view.View
6 |
7 | /**
8 | * Created by zhangzhihao on 2018/3/7.
9 | */
10 | class GridSpacingItemDecoration(var spanCount: Int, var spacing: Int, var includeEdge: Boolean) : RecyclerView.ItemDecoration() {
11 | private var tabPosition = 0
12 | override fun getItemOffsets(outRect: Rect?, view: View?, parent: RecyclerView?, state: RecyclerView.State?) {
13 | var position = parent!!.getChildAdapterPosition(view)
14 | if (position > 0) {
15 | val id = parent.adapter.getItemViewType(position)
16 | if (id == R.layout.adapter_tab) {
17 | tabPosition = position
18 | }
19 | if (id == R.layout.adapter_channel) {
20 | if (position <= tabPosition) {
21 | position--
22 | } else {
23 | position -= (tabPosition + 1)
24 | }
25 | val column = position % spanCount
26 | if (includeEdge) {
27 | outRect!!.left = spacing - column * spacing / spanCount
28 | outRect.right = (column + 1) * spacing / spanCount
29 | if(position=spanCount){
37 | outRect.top=20
38 | }
39 | }
40 | }
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/zzh/channelmanagedemo_kotlin/ItemDragCallback.kt:
--------------------------------------------------------------------------------
1 | package com.example.zzh.channelmanagedemo_kotlin
2 |
3 | import android.graphics.Canvas
4 | import android.graphics.Color
5 | import android.graphics.DashPathEffect
6 | import android.graphics.Paint
7 | import android.support.v7.widget.RecyclerView
8 | import android.support.v7.widget.helper.ItemTouchHelper
9 | import android.support.v7.widget.helper.ItemTouchHelper.ACTION_STATE_DRAG
10 | import android.view.View
11 |
12 | /**
13 | * Created by zhangzhihao on 2018/3/7.
14 | */
15 | class ItemDragCallback(var mAdapter: ChannelAdapter, var mPadding: Int) : ItemTouchHelper.Callback() {
16 | private val mPaint: Paint = Paint()
17 |
18 | init {
19 | mPaint.color = Color.GRAY
20 | mPaint.isAntiAlias = true
21 | mPaint.strokeWidth = 1f
22 | mPaint.style = Paint.Style.STROKE
23 | val pathEffect = DashPathEffect(FloatArray(2, { 5f }), 5f)
24 | mPaint.pathEffect = pathEffect
25 | }
26 |
27 | override fun getMovementFlags(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?): Int {
28 | //固定位置及tab下面的channel不能拖动
29 | val position = viewHolder!!.layoutPosition
30 | if (position < mAdapter.fixSize + 1 || position > mAdapter.selectedSize) {
31 | return makeMovementFlags(0, 0)
32 | }
33 | val dragFlags = ItemTouchHelper.UP or ItemTouchHelper.DOWN or ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
34 | return makeMovementFlags(dragFlags, 0)
35 | }
36 |
37 | override fun onMove(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?, target: RecyclerView.ViewHolder?): Boolean {
38 | val fromPosition = viewHolder!!.layoutPosition //拖动的位置
39 | val toPosition = target!!.layoutPosition //释放的位置
40 | //固定位置及tab下面的channel不能移动
41 | if (toPosition < mAdapter.fixSize + 1 || toPosition > mAdapter.selectedSize) {
42 | return false
43 | }
44 | mAdapter.itemMove(fromPosition, toPosition)
45 | return true
46 | }
47 |
48 | override fun onSwiped(viewHolder: RecyclerView.ViewHolder?, direction: Int) {
49 | //滑动重写这里
50 | }
51 |
52 | override fun onChildDrawOver(c: Canvas?, recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
53 | super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
54 | if (dX != 0f && dY != 0f || isCurrentlyActive) {
55 | //长按拖拽时底部绘制一个虚线矩形
56 | c!!.drawRect(viewHolder!!.itemView.left.toFloat(), (viewHolder.itemView.top - mPadding).toFloat(), viewHolder.itemView.right.toFloat(), viewHolder.itemView.bottom.toFloat(), mPaint)
57 | }
58 | }
59 |
60 | override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
61 | super.onSelectedChanged(viewHolder, actionState)
62 | if (actionState == ACTION_STATE_DRAG) {
63 | //长按时调用 设置颜色 阴影
64 | val holder = viewHolder as ChannelAdapter.ChannelHolder
65 | holder.name.setBackgroundColor(Color.parseColor("#FDFDFE"))
66 | holder.delete.visibility= View.GONE
67 | holder.name.elevation=5f
68 | }
69 | }
70 |
71 | override fun clearView(recyclerView: RecyclerView?, viewHolder: RecyclerView.ViewHolder?) {
72 | super.clearView(recyclerView, viewHolder)
73 | //重置view
74 | val holder=viewHolder as ChannelAdapter.ChannelHolder
75 | holder.name.setBackgroundColor(Color.parseColor("#f0f0f0"))
76 | holder.delete.visibility=View.VISIBLE
77 | holder.name.elevation=0f
78 | }
79 |
80 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/zzh/channelmanagedemo_kotlin/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.example.zzh.channelmanagedemo_kotlin
2 |
3 | import android.content.Context
4 | import android.support.v7.app.AppCompatActivity
5 | import android.os.Bundle
6 | import android.support.v7.widget.DefaultItemAnimator
7 | import android.support.v7.widget.GridLayoutManager
8 | import android.support.v7.widget.helper.ItemTouchHelper
9 | import android.view.WindowManager
10 | import kotlinx.android.synthetic.main.activity_main.*
11 |
12 | class MainActivity : AppCompatActivity(), ChannelAdapter.OnItemRangeChangeListener {
13 |
14 |
15 | private val select = arrayOf("要闻", "体育", "新时代", "汽车", "时尚", "国际", "电影", "财经", "游戏", "科技", "房产", "政务", "图片", "独家")
16 | private val recommend = arrayOf("娱乐", "军事", "文化", "视频", "股票", "动漫", "理财", "电竞", "数码", "星座", "教育", "美容", "旅游")
17 | private val city = arrayOf("重庆", "深圳", "汕头", "东莞", "佛山", "江门", "湛江", "惠州", "中山", "揭阳", "韶关", "茂名", "肇庆", "梅州", "汕尾", "河源", "云浮", "四川")
18 | val mList = arrayListOf()
19 | var mAdapter: ChannelAdapter? = null
20 | override fun onCreate(savedInstanceState: Bundle?) {
21 | super.onCreate(savedInstanceState)
22 | setContentView(R.layout.activity_main)
23 | val manager = GridLayoutManager(this, 4)
24 | manager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
25 | override fun getSpanSize(position: Int): Int {
26 | return mList[position].spanSize
27 | }
28 | }
29 | recyclerView.layoutManager = manager
30 | val animator = DefaultItemAnimator()
31 | animator.moveDuration = 300 //设置动画时间
32 | animator.removeDuration = 0
33 | recyclerView.itemAnimator = animator
34 | createData()
35 | recyclerView.adapter = mAdapter
36 | val m = getSystemService(Context.WINDOW_SERVICE) as WindowManager
37 | val spacing = ((m.defaultDisplay.width - this.dip2px(70f) * 4) / 5).toInt()
38 | recyclerView.addItemDecoration(GridSpacingItemDecoration(4, spacing, true))
39 | val callback = ItemDragCallback(mAdapter!!, 2)
40 | val helper = ItemTouchHelper(callback)
41 | helper.attachToRecyclerView(recyclerView)
42 | }
43 |
44 | private fun createData() {
45 | mList.add(ChannelBean("", 4, R.layout.adapter_title, false))
46 | select.mapTo(mList) { ChannelBean(it, 1, R.layout.adapter_channel, true) }
47 | mList.add(ChannelBean("", 4, R.layout.adapter_tab, false))
48 | val recommendList = arrayListOf()
49 | recommend.mapTo(recommendList) { ChannelBean(it, 1, R.layout.adapter_channel, true) }
50 | val cityList = arrayListOf()
51 | city.mapTo(cityList) { ChannelBean(it, 1, R.layout.adapter_channel, false) }
52 | cityList.add(ChannelBean("", 4, R.layout.adapter_more_channel, false))
53 | mList.addAll(recommendList)
54 | mAdapter = ChannelAdapter(this, mList, recommendList, cityList)
55 | mAdapter!!.fixSize = 1
56 | mAdapter!!.selectedSize = select.size
57 | mAdapter!!.onItemRangeChangeListener = this
58 | }
59 |
60 | override fun refreshItemDecoration() {
61 | recyclerView.invalidateItemDecorations()
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzh12138/ChannelManageDemo_Kotlin/5019cc796c65b42c7f4fb7b62088135b55e34a48/app/src/main/res/drawable/icon_close.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
17 |
18 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/adapter_channel.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
17 |
18 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/adapter_more_channel.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/adapter_tab.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
24 |
25 |
32 |
33 |
34 |
39 |
40 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/adapter_title.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzh12138/ChannelManageDemo_Kotlin/5019cc796c65b42c7f4fb7b62088135b55e34a48/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzh12138/ChannelManageDemo_Kotlin/5019cc796c65b42c7f4fb7b62088135b55e34a48/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzh12138/ChannelManageDemo_Kotlin/5019cc796c65b42c7f4fb7b62088135b55e34a48/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzh12138/ChannelManageDemo_Kotlin/5019cc796c65b42c7f4fb7b62088135b55e34a48/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzh12138/ChannelManageDemo_Kotlin/5019cc796c65b42c7f4fb7b62088135b55e34a48/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzh12138/ChannelManageDemo_Kotlin/5019cc796c65b42c7f4fb7b62088135b55e34a48/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzh12138/ChannelManageDemo_Kotlin/5019cc796c65b42c7f4fb7b62088135b55e34a48/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzh12138/ChannelManageDemo_Kotlin/5019cc796c65b42c7f4fb7b62088135b55e34a48/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzh12138/ChannelManageDemo_Kotlin/5019cc796c65b42c7f4fb7b62088135b55e34a48/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zzh12138/ChannelManageDemo_Kotlin/5019cc796c65b42c7f4fb7b62088135b55e34a48/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ChannelManageDemo_Kotlin
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/zzh/channelmanagedemo_kotlin/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.example.zzh.channelmanagedemo_kotlin
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------