【项目实战】Unity和Lua 滚动UI

制作流程
1.制作一个滑动预制体,打上标签UICompent
2.挂载AntVerticalScroll或者AntHorizontalScroll滑动组件
3.设置一行或一列滑动的item
4.创建Lua逻辑脚本和View视图脚本
5.在Lua逻辑脚本中require一个列表渲染组件XXXRender.lua
6.在列表渲染组件里在Require一个子项渲染组件XXXItemRender.lua

AntScroll抽象类

using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;
using XLua;

//抽象类
public abstract class AntScroll : ScrollRect
{
	protected RectTransform rtf;
	protected RectTransform _prefabItem;

	#region abstracts
	protected abstract float GetDimension(Vector2 vector); //获取维度
	protected abstract float GetPos(Vector2 vector); //获取位置
    protected abstract Vector2 GetVector(float value); //获取向量
	#endregion

	[HideInInspector]
	public int dataCount;

	private int _startIndex;
	private int _endIndex;

    //对象池~~
	private List<RectTransform> _items;
    private List<RectTransform> _pool;
    private Queue<RectTransform> _poolFree;

    private float _itemSize;
    //private Vector2 _org;
    [CSharpCallLua]
    public delegate void RenderDelegate(int index, RectTransform tf,int tfIndex); //C#调用Lua,渲染委托,映射,三个形参

	public RenderDelegate renderHandler; //渲染事件

	[SerializeField]
	public bool useObjectPool;

    //private float _fixDirect;

    protected override void Awake()
    { 
        base.Awake();
		if (Application.isPlaying == false)
			return;
		rtf = GetComponent<RectTransform>();
        //_fixDirect = horizontal ? 1 : -1;
        Init();
    }

	protected void Init()
	{
		List<RectTransform> listChild = new List<RectTransform>();

		foreach (RectTransform child in content) //子节点content下的内容~
		{
			listChild.Add(child);
		}
       // Debug.Log("AntScroll  listChild.Count ============================= " + listChild.Count);
		for (int i = 0; i < listChild.Count; i++)
		{
			if (_prefabItem == null)
			{
				_prefabItem = listChild[i]; //content 对象 ~
				_prefabItem.gameObject.SetActive(false); //content 对象 ~先设置不可见
            }
			else
			{
				Destroy(listChild[i].gameObject); //仙小灰
			}
		}
        _itemSize = GetDimension(_prefabItem.sizeDelta); //此 RectTransform 相对于锚点之间距离的大小。实现类获取维度Vertor.y或.x
        _startIndex = 0;
        _endIndex = 0;
        _items = new List<RectTransform>();
        _pool = new List<RectTransform>();
        _poolFree = new Queue<RectTransform>();
    }

    public GameObject GetPrefab()
    {
        return _prefabItem.gameObject;
    }

    protected override void Start()
    {
        base.Start();
		if (Application.isPlaying == false)
			return;
        Refresh();
	}


	protected RectTransform GetPrefabItem(int index)
	{
		return _prefabItem;
	}

	public void SetCount(int value)
	{
        dataCount = value;
		  Debug.Log("SetCount  C#      " +dataCount);
        if (horizontal)
            content.sizeDelta = new Vector2(_prefabItem.sizeDelta.x * dataCount, content.sizeDelta.y);
        else
        {
         //   Debug.Log("_prefabItem  " + _prefabItem);
            content.sizeDelta = new Vector2(content.sizeDelta.x, _prefabItem.sizeDelta.y * dataCount);
        }
        Refresh();
	}
	/// <summary>
	/// 刷新
	/// </summary>
	public void Refresh()
	{
        for (int i = 0; i < _pool.Count; i++)
            _pool[i].gameObject.SetActive(false);

        float py = 0;
        if (_items.Count > 0)
            py = GetPos(_items[0].anchoredPosition);

        for (int i = _items.Count - 1; i > -1; i--)
            RemoveFromItems(i);

        float viewSize = GetDimension(rtf.sizeDelta);

        if (_startIndex > dataCount)
        {
            _startIndex = 0;
            py = 0f;
        }

        for (int i = _startIndex; i < dataCount; i++)
		{
            RectTransform newItem = CreateItem(i);
            _items.Add(newItem);

            newItem.anchoredPosition = GetVector(py);
			_endIndex = i;
			py = GetPos(newItem.anchoredPosition) + _itemSize;
			if (GetPos(content.anchoredPosition) + py > viewSize)
			{
				break;
			}
		}
	}


	private Vector2 _contentLastAnchoredPosition;

	/// <summary>
	/// 设置Content的位置
	/// </summary>
	/// <param name="position"></param>
	protected override void SetContentAnchoredPosition(Vector2 position)
	{
		base.SetContentAnchoredPosition(position);

		if (_contentLastAnchoredPosition == content.anchoredPosition)
		{
			content.anchoredPosition = new Vector2((float)System.Math.Round(_contentLastAnchoredPosition.x, 2), (float)System.Math.Round(_contentLastAnchoredPosition.y, 2));
		}
		_contentLastAnchoredPosition = content.anchoredPosition;

		if (_items == null || _items.Count == 0)
		{
			return;
		}

		RectTransform topItem = _items[0];
		RectTransform bottomItem = _items[_items.Count - 1];
		if (GetPos(content.anchoredPosition) + GetPos(topItem.anchoredPosition) > 0)
		{
			if (_startIndex > 0)
			{
				RectTransform newItem = CreateItem(_startIndex - 1);
                newItem.anchoredPosition = GetVector(GetPos(topItem.anchoredPosition) - _itemSize);
                newItem.SetSiblingIndex(0);
				_startIndex--;
				_items.Insert(0, newItem);
            }
		}
		else if (GetPos(content.anchoredPosition) + GetPos(topItem.anchoredPosition) + _itemSize < 0)
		{
            if(_items.Count != 1)
            {
                _startIndex++;
                RemoveFromItems(0);
            }
        }
		topItem = _items[0];
		bottomItem = _items[_items.Count - 1];
        //Debug.Log((GetDimension(content.anchoredPosition) + GetPos(bottomItem.anchoredPosition) + _itemSize) + " " + GetDimension(rtf.sizeDelta));
		if (GetPos(content.anchoredPosition) + GetPos(bottomItem.anchoredPosition) + _itemSize < GetDimension(rtf.sizeDelta))
		{
			if (_endIndex < dataCount - 1)
			{
				//float py = GetDimension(bottomItem.anchoredPosition + _fixDirect * bottomItem.sizeDelta / 2);
				RectTransform newItem = CreateItem(_endIndex + 1);
				newItem.anchoredPosition = GetVector(GetPos(bottomItem.anchoredPosition) + _itemSize);
				_items.Add(newItem);
				_endIndex++;
            }
		}
		else if (GetPos(content.anchoredPosition) + GetPos(bottomItem.anchoredPosition) >  GetDimension(rtf.sizeDelta))
		{
            if (_items.Count != 1)
            {
                RemoveFromItems(_items.Count - 1);
                _endIndex--;
            }
        }
	}
	/// <summary>
	/// 移除Item
	/// </summary>
	/// <param name="index"></param>
    protected void RemoveFromItems(int index)
    {
        _items[index].gameObject.SetActive(false);
        _poolFree.Enqueue(_items[index]); //队列入栈
        _items.RemoveAt(index);
    }

	/// <summary>
	/// 创建Item,加入对象池,并触发渲染事件
	/// </summary>
	/// <param name="index"></param>
	/// <returns></returns>
	protected RectTransform CreateItem(int index)
	{
        RectTransform newItem = null;
        if (_poolFree.Count > 0)
        {
            newItem = _poolFree.Dequeue(); //队列出栈
        }
        else
        {
            newItem = Instantiate(GetPrefabItem(index)) as RectTransform;
            newItem.transform.SetParent(content.transform, false);
            _pool.Add(newItem);
        }
        newItem.SetSiblingIndex(index);
        newItem.gameObject.name = "item" + index;
		newItem.gameObject.SetActive(true);
		RenderHandler(index, newItem);
        return newItem;
	}

    private void RenderHandler(int index, RectTransform tf)
	{
		Debug.Log("RenderHandler  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  "+renderHandler);
        if(renderHandler != null)
            renderHandler(index, tf, _pool.IndexOf(tf));
	}
}

EquipDemo.Lua逻辑脚本

equipDemo = {}
local UITable = require("UI/equip2/Base/equipDemoView")  
local UIEquipScrollRender = require("UI/equip2/UIEquipScrollDemoRender")
UIEquipScrollRender.__index = UIEquipScrollRender

function equipDemo.Create()
	local ui = {}
    setmetatable(ui, {__index=UITable}) 
    ui:Create()
    ui.layer = 3
    UI.LoadUI(ui)
    return ui
end

function UITable:Awake()
    self:StartInit()  
    self.oneLineNum = 3
    self.CrewList1 = {}
    self.CrewItemList1 = {}
    self.EquipScroll.renderHandler = function (nIndex,tempTransRect,nIndexTrans)  				 
        self:CrewItemRenderHandel1(nIndex,tempTransRect,nIndexTrans)
    end 
    self.equipId = "" 
    self:Init()
    self:AddListener("chooseEquip",self.chooseEquip) 
    self:AddListener("reFreshEquipL",self.reFreshEquipL) 
end

function UITable:Init()
    self:RefEquip()
    if GameMainData.nowequipId == "" then
        self.nowequipName.gameObject:SetActive(false);
        self.nowEquipPic.gameObject:SetActive(false);
        self.nowAtk.gameObject:SetActive(false);
    else
        self.nowequipName.text = GameMainData.getWuqiByID(GameMainData.nowequipId).Name;
        self.nowequipName.gameObject:SetActive(true);
        self.nowEquipPic.gameObject:SetActive(true);
        self.nowAtk.gameObject:SetActive(true);
        self.nowAtk.text = "攻击力+" .. GameMainData.getWuqiByID(GameMainData.nowequipId).atk;
    end
     
end

function UITable:RefEquip()
    self.CrewList1 = GameMainData.EquipData 
	local nTotal = #self.CrewList1
	local nLine = nTotal/self.oneLineNum
    self.EquipScroll:SetCount(math.ceil(nLine))
end

function UITable:CrewItemRenderHandel1(nIndex,tempTransRect,nIndexTrans)

 	local nDataTotal = 0
	local nNum = 0
	if self.CrewItemList1[nIndexTrans] == nil then
		self.CrewItemList1[nIndexTrans] = {}
		setmetatable(self.CrewItemList1[nIndexTrans] ,UIEquipScrollRender)
		self.CrewItemList1[nIndexTrans]:Init(tempTransRect)
	end

	nDataTotal = #self.CrewList1
 	for i=1,self.oneLineNum do
		nNum = nIndex * self.oneLineNum + i
 		if nNum <= nDataTotal then
			self.CrewItemList1[nIndexTrans].lineList[i]:SetData(self.CrewList1[nNum])
			self.CrewItemList1[nIndexTrans].lineList[i].transform.gameObject:SetActive(true)
		else
			self.CrewItemList1[nIndexTrans].lineList[i].transform.gameObject:SetActive(false)
		end
	end
end
 
 

function UITable:SetData(v)
	self.data=v
end

function UITable:Start()      
    self:StartInit()
  
end

 function UITable:ButtonClickHandler(btn)  
    --LuaTools.PlaySound("btnsound")
    if btn == self.equipTrue then  -- 
        self.equipMsg:SetActive(false)
        GameMainData.nowequipId =  self.nowSeeId
        self:Init()
    elseif btn == self.equipFalse then  -- 
        self.equipMsg:SetActive(false)
     elseif btn == self.BtnClose then  -- 
        self:Close() 
    end
 end

 function UITable:chooseEquip(evtName,equipid)  -- 选择装备 打开面板
    self.equipMsg:SetActive(true)
    self.nowSeeId = equipid;
    self.equipMsg_name.text = GameMainData.getWuqiByID(equipid).Name;
    self.equipMsg_Info.text = GameMainData.getWuqiByID(equipid).jieshao;
  --  self:Init() 
 end

 function UITable:reFreshEquipL(evtName,equipid)
    self:RefEquip()
 end
 
 

UIEquipScrollDemoRender.lua逻辑脚本 XXXScrollRender滑动逻辑脚本

local Render = UI.CreateRenderTable()

local UIEquipInfoRender = require("UI/equip2/UIEquipDemoItemRender")
UIEquipInfoRender.__index = UIEquipInfoRender
function Render:Awake()
	self.lineList = {}
end

function Render:SetUICompent(child)

	if child.name == "Item1" then
		self:CreateItemRender(child)
	elseif child.name == "Item2" then
		self:CreateItemRender(child) 
	elseif child.name == "Item3" then
		self:CreateItemRender(child) 
	end
end
function Render:CreateItemRender(tempTrans)
	local tempRender = {}
	setmetatable(tempRender,UIEquipInfoRender)
	tempRender:Init(tempTrans)
	table.insert(self.lineList, tempRender)
end

return Render

UIEquipDemoItemRender.lua逻辑脚本 XXXItemRender子项目渲染

local Render = UI.CreateRenderTable() 
Render.chooseBeC = nil
function Render:SetUICompent(child)
 
	 if child.name == "beChoose" then -- 点某一个装备按钮
		self.choose = child:GetComponent("Button") 
		self.choose.onClick:RemoveAllListeners()  
		self.choose.onClick:AddListener(function() 
		    self:chooseB()  -- 发消息通知装备模块打开装备详情
		end) 
	 elseif child.name == "zhuangbei" then -- 已经装备中的显示游戏体
	    self.zhuangbei = child.gameObject 
	end
end

function Render:SetData(v) 
   
	self.EquipData = v 
	self:RefreshEquipItem()
end

function Render:RefreshEquipItem() 
    if self.EquipData.ID == GameMainData.nowequipId then
       self.zhuangbei:SetActive(true)
    else 
       self.zhuangbei:SetActive(false)
    end 
end
 
function Render:chooseB()  -- 发消息通知装备模块打开装备详情
	 
	Event.Call("chooseEquip",self.EquipData.ID)
end

return Render
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值