实现新闻频道管理
Posted 天耀106
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现新闻频道管理相关的知识,希望对你有一定的参考价值。
第四节
主activity
package com.tian.yao.four.channel
import android.util.Log
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.listener.OnItemClickListener
import com.tian.yao.BR
import com.tian.yao.R
import com.tian.yao.databinding.ActivityChannelBinding
import com.tian.yao.four.BaseActivity
import com.tian.yao.two.ToastUtils
class ChannelActivity : BaseActivity<ChannelViewModel, ActivityChannelBinding>(),OnItemClickListener
/**
* 动画时长
*/
private val animDuration: Long = 300
override fun layoutId(): Int
return R.layout.activity_channel
override fun initVariableId(): Int
return BR.channelViewModel
override fun initSetup()
mViewModel.initData()
mBinding.apply
channelAction = mViewModel.channelAction
gvUser.layoutManager= GridLayoutManager(this@ChannelActivity,4)
gvUser.adapter = mViewModel.mUserAdapter
mViewModel.mUserAdapter.setOnItemClickListener(this@ChannelActivity)
gvOther.layoutManager= GridLayoutManager(this@ChannelActivity,4)
gvOther.adapter = mViewModel.mOtherAdapter
mViewModel.mOtherAdapter.setOnItemClickListener(this@ChannelActivity)
mViewModel.moreFlag.observe(this@ChannelActivity,
tvMore.visibility = if(it) View.VISIBLE else View.GONE
gvOther.visibility = if(it) View.VISIBLE else View.GONE
ivEdit.setImageResource(if(it) R.drawable.svg_ok else R.drawable.svg_edit)
)
override fun onItemClick(adapter: BaseQuickAdapter<*, *>, view: View, position: Int)
//判断是否是编辑态
//如果是编辑态则点击的时候处理增加/删除操作
//如果不是编辑态则弹出Toast提示,实际使用中可以换成频道详情页的跳转
if (ChannelAdapter.isEdit())
var currentView: RecyclerView //currentView表示当前被点击的对象
var anotherView: RecyclerView //anotherView表示另一个对象
if (adapter == mBinding.gvUser.adapter)
currentView = mBinding.gvUser
anotherView = mBinding.gvOther
else
currentView = mBinding.gvOther
anotherView = mBinding.gvUser
//计算起点,获取点击View的坐标
var startPos = IntArray(2)
var endPos = IntArray(2)
view.getLocationInWindow(startPos)
var currentAdapter = currentView.adapter as ChannelAdapter
var anotherAdapter = anotherView.adapter as ChannelAdapter
//标记点击的item待删除,并添加到anotherView中
Log.i("wltest", "onItemClick: "+currentAdapter.getItem(position))
anotherAdapter.setTranslating(true)
anotherAdapter.add(currentAdapter.setRemove(position))
var cloneView = mViewModel.getCloneView(view)
currentView.post(Runnable
(window.decorView as ViewGroup).addView(cloneView,ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT)
var lastView = anotherView.getChildAt(anotherView.childCount - 1)
lastView.getLocationInWindow(endPos)
mViewModel.moveAnimation(cloneView, startPos, endPos, animDuration)
)
else
ToastUtils.showShortText(mViewModel.mUserList[position])
viewModel层:
package com.tian.yao.four.channel
import android.app.Application
import android.graphics.Bitmap
import android.graphics.Canvas
import android.view.View
import android.view.ViewGroup
import android.view.animation.Animation
import android.view.animation.TranslateAnimation
import android.widget.ImageView
import androidx.lifecycle.MutableLiveData
import com.tian.yao.four.BaseViewModel
import org.json.JSONObject
import java.nio.charset.Charset
class ChannelViewModel(application: Application) : BaseViewModel(application)
private val fileName="channel.json"
var mUserList = ArrayList<String>()
var mOtherList = ArrayList<String>()
lateinit var mUserAdapter: ChannelAdapter
lateinit var mOtherAdapter: ChannelAdapter
var moreFlag = MutableLiveData<Boolean>()
fun initData()
initJsonData()
initAdapter()
private fun initJsonData()
var inputStream = resources.assets.open(fileName)
val length = inputStream.available()
val buffer = ByteArray(length)
inputStream.read(buffer)
val result = String(buffer, Charset.defaultCharset())
val jsonObject = JSONObject(result)
val userArray = jsonObject.optJSONArray("user")
val otherArray = jsonObject.optJSONArray("other")
for (index in 1..userArray.length())
mUserList.add( userArray.getString(index-1))
for (index in 1..otherArray.length())
mOtherList.add( otherArray.getString(index-1))
private fun initAdapter()
mUserAdapter = ChannelAdapter(true)
mUserAdapter.setNewInstance(mUserList)
mOtherAdapter = ChannelAdapter(false)
mOtherAdapter.setNewInstance(mOtherList)
val channelAction=object :ChannelAction
override fun edit()
toggleEditState()
private fun toggleEditState()
val isEdit = ChannelAdapter.isEdit()
ChannelAdapter.setEdit(!isEdit)
moreFlag.value= !isEdit
mUserAdapter.notifyDataSetChanged()
mOtherAdapter.notifyDataSetChanged()
/**
* 移动动画
* @param moveView View 移动的目标View
* @param startPos FloatArray 起点坐标
* @param endPos FloatArray 终点坐标
* @param duration Long 动画时长
*/
fun moveAnimation(moveView: View, startPos: IntArray, endPos: IntArray, duration: Long)
//1、创建动画,设置起点和终点的坐标
var animation = TranslateAnimation(startPos[0].toFloat(), endPos[0].toFloat(),
startPos[1].toFloat(), endPos[1].toFloat()
)
//2、设置动画时长
animation.duration = duration
//3、设置不停留
animation.fillAfter = false
//4、设置监听器
animation.setAnimationListener(object : Animation.AnimationListener
override fun onAnimationStart(animation: Animation?)
override fun onAnimationEnd(animation: Animation?)
(moveView.parent as ViewGroup).removeView(moveView)
resetAdapter()
override fun onAnimationRepeat(animation: Animation?)
)
//5、启动动画
moveView.startAnimation(animation)
private fun resetAdapter()
mUserAdapter.setTranslating(false)
mOtherAdapter.setTranslating(false)
mUserAdapter.remove()
mOtherAdapter.remove()
fun getCloneView(view: View): ImageView
val bitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
view.draw(canvas)
var imageView = ImageView(view.context)
imageView.setImageBitmap(bitmap)
return imageView
适配器:
package com.tian.yao.four.channel
import android.widget.TextView
import androidx.core.content.ContextCompat
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.tian.yao.R
class ChannelAdapter : BaseQuickAdapter<String, BaseViewHolder>
private var mReadyToRemove: Int = -1 //标记预备删除的元素序号
private var mIsUser: Boolean = true
private var mAnimState = AnimState.IDEL
constructor(isUser: Boolean) : super(R.layout.adapter_channel_item)
mIsUser = isUser
/**
* 动画状态枚举,用于对不通的动画状态进行处理,当前只支持空闲和移动
* 目前看也可以用boolean,enum是为了后续扩展
*/
enum class AnimState
IDEL,
TRANSLATING
companion object
private var mIsEditState: Boolean = false
fun setEdit(isEdit: Boolean)
mIsEditState = isEdit
fun isEdit(): Boolean
return mIsEditState
fun add(channelName: String)
data.add(channelName)
notifyDataSetChanged()
/**
* 添加删除标记
* @param index Int 待删除的序号
*/
fun setRemove(index: Int): String
mReadyToRemove = index
notifyDataSetChanged()
return data[index]
fun setTranslating(translating: Boolean)
mAnimState = if (translating) AnimState.TRANSLATING else AnimState.IDEL
fun remove()
if (mReadyToRemove > 0 && mReadyToRemove < data.size)
removeAt(mReadyToRemove)
mReadyToRemove = -1
notifyDataSetChanged()
override fun convert(holder: BaseViewHolder, item: String)
var tvItem = holder.getView<TextView>(R.id.tv_item)
tvItem.text = item
if (mIsEditState)
holder.setVisible(R.id.iv_icon, true)
holder.setImageDrawable(
R.id.iv_icon,
if (mIsUser)
ContextCompat.getDrawable(context, R.drawable.svg_subtraction)
else
ContextCompat.getDrawable(context, R.drawable.svg_add)
)
else
holder.setVisible(R.id.iv_icon, false)
// 1、第一个条件处理currentView的状态
// 2、第二个条件处理anotherView的状态
if (mReadyToRemove == getItemPosition(item) || (mAnimState == AnimState.TRANSLATING && getItemPosition(item) == itemCount - 1))
tvItem.text = ""
holder.setVisible(R.id.iv_icon, false)
else
tvItem.text = item
点击Action接口:
package com.tian.yao.four.channel
interface ChannelAction
fun edit()
主布局:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="channelViewModel"
type="com.tian.yao.four.channel.ChannelViewModel" />
<variable
name="channelAction"
type="com.tian.yao.four.channel.ChannelAction" />
<import type="android.view.View"/>
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="15dp"
android:layout_marginEnd="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="我的频道"
android:textSize="18sp" />
<ImageView
android:id="@+id/iv_edit"
android:layout_width="22dp"
android:layout_height="22dp"
android:layout_alignParentEnd="true"
android:onClick="@v->channelAction.edit()"
android:padding="2dp"
app:srcCompat="@drawable/svg_edit" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="15dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/gv_user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:layout_marginEnd="14dp"
android:gravity="center"
android:horizontalSpacing="14dp"
android:numColumns="4"
android:scrollbars="vertical"
android:stretchMode="columnWidth"
android:verticalSpacing="14dp" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="10dp" />
<TextView
android:id="@+id/tv_more"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="15dp"
android:text="更多频道"
android:visibility="gone"
android:textSize="18sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/gv_other"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:layout_marginEnd="14dp"
android:gravity="center"
android:visibility="gone"
android:horizontalSpacing="14dp"
android:numColumns="4"
android:scrollbars="vertical"
android:stretchMode="columnWidth" />
</LinearLayout>
</layout>
效果图:
此外:我还对 BaseActivity做了自己的初步封装,可以一步步学习~
package com.tian.yao.four
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.ViewModelProvider
import kotlin.reflect.KClass
abstract class BaseActivity<VM : BaseViewModel, DB : ViewDataBinding> : AppCompatActivity()
lateinit var mBinding: DB
protected val mViewModel: VM by lazy
val kclazz = (GenericUtil.getClassType(this, BaseViewModel::class) as KClass<VM>).java
val viewModel = ViewModelProvider(this,ViewModelFactory(application)).get(kclazz)
if (initVariableId() > 0)
mBinding.setVariable(initVariableId(), viewModel)
viewModel
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
mBinding = DataBindingUtil.setContentView(this, layoutId())
mBinding.lifecycleOwner = this
initSetup()
abstract fun layoutId(): Int
abstract fun initVariableId(): Int
abstract fun initSetup()
BaseViewModel层
package com.tian.yao.four
import android.app.Application
import android.content.res.Resources
import androidx.lifecycle.AndroidViewModel
open class BaseViewModel(application: Application) : AndroidViewModel(application)
protected val resources: Resources = application.resources
ViewModelFactory
package com.tian.yao.four
import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import java.lang.reflect.InvocationTargetException
class ViewModelFactory(private val application: Application) : ViewModelProvider.Factory
override fun <T : ViewModel?> create(modelClass: Class<T>): T
if (modelClass.isAssignableFrom(BaseViewModel::class.java))
return BaseViewModel(application) as T
//反射动态实例化ViewModel
return try
val className = modelClass.canonicalName
val classViewModel = Class.forName(className)
val cons = classViewModel.getConstructor(Application::class.java)
val viewModel = cons.newInstance(application) as ViewModel
viewModel as T
catch (e: ClassNotFoundException)
e.printStackTrace()
throw java.lang.IllegalArgumentException("Unknown ViewModel class: " + modelClass.name)
catch (e: IllegalAccessException)
e.printStackTrace()
throw java.lang.IllegalArgumentException("Unknown ViewModel class: " + modelClass.name)
catch (e: InstantiationException)
e.printStackTrace()
throw java.lang.IllegalArgumentException("Unknown ViewModel class: " + modelClass.name)
catch (e: NoSuchMethodException)
e.printStackTrace()
throw java.lang.IllegalArgumentException("Unknown ViewModel class: " + modelClass.name)
catch (e: InvocationTargetException)
e.printStackTrace()
throw java.lang.IllegalArgumentException("Unknown ViewModel class: " + modelClass.name)
工具类
package com.tian.yao.four
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
import kotlin.reflect.KClass
object GenericUtil
fun getClassType(obj: Any, destClz: KClass<*>) = getClassType(obj::class.java, destClz.java)
private fun getClassType(clz: Class<*>, destClz: Class<*>): KClass<*>?
var c = clz
var genType: Type?
while (c.superclass != null)
genType = c.genericSuperclass
if (genType !is ParameterizedType)
c = c.superclass as Class<*>
continue
else
val types = genType.actualTypeArguments
for (type in types)
val tClz = type as Class<*>
return if (destClz.isAssignableFrom(tClz))
type.kotlin
else
continue
break
return null
代码链接:
链接: https://pan.baidu.com/s/1aqpcuhVgIkCr2rfnDV_6ng 提取码: rrea
赞赏码,哈哈哈
以上是关于实现新闻频道管理的主要内容,如果未能解决你的问题,请参考以下文章
iOS 利用UICollectionView拖拽排序 实现的仿照腾讯新闻频道管理功能 XLChannelControl