len(bpy.data.materials) returns the number (int) of all materials in the file. To draw this number onto a custom panel, means that you have to pass it to the text argument of the label() call (string).
In fact, you can either use str.format() or the old C-style formatting syntax for integers "%i" % number to pass the variable. A nice collection of examples here: https://pyformat.info/
# Number of all Materials in the .blend
layout.label(text="Materials: {}".format(len(bpy.data.materials))
Following example displays the number materials per file (Data.materials) as well as all materials in the current scene (custom object iteration). Layout code is ripped from How to create a custom UI?

import bpy
from bpy.props import (BoolProperty,
IntProperty,
PointerProperty
)
from bpy.types import (Panel,
PropertyGroup
)
# ------------------------------------------------------------------------
# Scene Properties
# ------------------------------------------------------------------------
class MyProperties(PropertyGroup):
my_bool: BoolProperty(
name="Enable or Disable",
description="A bool property",
default = False
)
my_int: IntProperty(
name = "Int Value",
description="A integer property",
default = 23,
min = 10,
max = 100
)
# ------------------------------------------------------------------------
# Panel in Object Mode
# ------------------------------------------------------------------------
class OBJECT_PT_CustomPanel(Panel):
bl_label = "My Panel"
bl_idname = "OBJECT_PT_custom_panel"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Tools"
bl_context = "objectmode"
def scene_materials(self, context):
mat_list_per_object = []
for ob in context.scene.objects:
if ob.type in ("MESH", "CURVE", "SURFACE", "FONT", "GPENCIL"):
if ob.data.materials:
mat_list_per_object.append(ob.data.materials.items())
# Flatten the list and return a set (unique)
return set([i[0] for i in sum(mat_list_per_object, [])])
@classmethod
def poll(self,context):
return context.object is not None
def draw(self, context):
layout = self.layout
scene = context.scene
mytool = scene.my_tool
# Custom Properties
#layout.prop(mytool, "my_bool")
#layout.prop(mytool, "my_int")
# Number of Materials in File (bpy.data)
layout.label(text="Number of Materials in this File: {}".format(
len(bpy.data.materials))
)
# Number of materials (unique) per scene in context
layout.label(text='Unique Materials in "{}": {}'.format(
context.scene.name,
len(self.scene_materials(context)))
)
# Draw a list of materials per scene
layout.separator()
layout.label(text="List of Materials:")
for i in self.scene_materials(context):
layout.label(text=i)
layout.separator()
# ------------------------------------------------------------------------
# Registration
# ------------------------------------------------------------------------
classes = (
MyProperties,
OBJECT_PT_CustomPanel
)
def register():
from bpy.utils import register_class
for cls in classes:
register_class(cls)
bpy.types.Scene.my_tool = PointerProperty(type=MyProperties)
def unregister():
from bpy.utils import unregister_class
for cls in reversed(classes):
unregister_class(cls)
del bpy.types.Scene.my_tool
if __name__ == "__main__":
register()