![停止 enumitem \item 跨页](https://linux22.com/image/451091/%E5%81%9C%E6%AD%A2%20enumitem%20%5Citem%20%E8%B7%A8%E9%A1%B5.png)
一位同事问了这个问题。
你能自动要求枚举自定义列表中的项目不要跨分页符吗?假设这是针对考试的,考试中希望每个问题都一起显示,并且问题不超过一页。
原始上下文的简单版本如下。
\documentclass{article}
\usepackage[english]{babel} % needed by blindtext
\usepackage[pangram]{blindtext} % to produce dummy text only
\usepackage{enumitem}
\newlist{questions}{enumerate}{3}
\setlist[questions,1]{label*=\textbf{\arabic*}.}
\setlist[questions,2]{label=(\alph{questionsii})}
\setlist[questions,3]{label=(\roman{questionsiii})}
\begin{document}
~\vspace{15cm} % to push the text near the page break
\begin{questions}
\item \Blindtext[1][4]
\item \Blindtext[2][4]
\begin{questions}
\item \Blindtext[1][4]
\item \Blindtext[1][4]
\item \Blindtext[1][4]
\end{questions}
\end{questions}
\end{document}
我有几个想法,我会在这里将它们作为答案发布,因为(a)他说他在这个问题上的搜索并没有让他找到任何可以工作的东西;(b)我对可能更好的其他解决方案感兴趣。
答案1
这在大多数情况下应该有效。我们\interlinepenalty=10000
在环境中设置questions
并\nobreak
在后面添加\par
;由于\item
发出惩罚,因此项目之间可以中断。
\documentclass{article}
\usepackage[english]{babel} % needed by blindtext
\usepackage[pangram]{blindtext} % to produce dummy text only
\usepackage{enumitem}
\newlist{questions}{enumerate}{3}
\setlist[questions,1]{label*=\textbf{\arabic*}.}
\setlist[questions,2]{label=(\alph{questionsii})}
\setlist[questions,3]{label=(\roman{questionsiii})}
\makeatletter
\AddToHook{env/questions/begin}{%
\ifnum\enitdp@questions=0
\interlinepenalty=10000
\AddToHook{para/after}[nobreak]{\nobreak}%
\fi
}
\AddToHook{env/questions/end}{%
\ifnum\enitdp@questions=1
\RemoveFromHook{para/after}[nobreak]%
\fi
}
\makeatother
\begin{document}
\vspace*{15cm} % to push the text near the page break
\begin{questions}
\item \Blindtext[1][4]
\item \Blindtext[2][4]
\begin{questions}
\item \Blindtext[1][4]
\item \Blindtext[1][4]
\item \Blindtext[1][4]
\end{questions}
\end{questions}
\end{document}
由于存在嵌套的可能性,questions
我们只想将钩子添加到一次,因此我们在深度计数器为零时执行此操作(就像目前所看到的一样) 。仅当深度计数器为 1 时,即在外层,才会env/questions/begin
删除。\nobreak
\end{questions}
答案2
要使文本块不跨页,可以将其放在环境中\begin{minipage}...\end{minipage}
。我能想到几种方法来实现这一点。所有这些方法都会产生相同的结果,不同之处在于实现方式。我想我更喜欢选项 2,它在前言中更复杂,但在我看来使用起来更简单。
1. 将每个项目放入其自己的小页面中。
基本上,您需要执行此操作,并且可以手动执行:
\begin{questions}
\begin{minipage}{\linewidth}
\item question text
\end{minipage}
\end{questions}
这可能有点难记,所以你可以定义一个新命令来为你做这件事。这可以作为环境或命令来完成,但请注意,两者都会改变通常的使用习惯,\item text
因为 minipage 有开始和结束,而\item
只有开始。
1a. 作为环境。
我们nobreakitem
在前言中定义了一个名为 的环境。此环境用于代替命令\item
。前面的两个换行符\begin{minipage}
是必需的,因为否则它会认为minipage
是前一个的一部分\item
,并且不会在它们之间放置换行符。它可能只用于有问题的\item
,或用于所有\item
。对我来说,这有点奇怪,因为你正在执行\begin
和\end
而不是通常的操作\item
,而且与自己编写上述代码相比,它并没有节省太多。
\documentclass{article}
\usepackage[english]{babel} % needed by blindtext
\usepackage[pangram]{blindtext} % to produce dummy text only
\usepackage{enumitem}
\newlist{questions}{enumerate}{3}
\setlist[questions,1]{label*=\textbf{\arabic*}.}
\setlist[questions,2]{label=(\alph{questionsii})}
\setlist[questions,3]{label=(\roman{questionsiii})}
\newenvironment{nobreakitem}{
\begin{minipage}{\linewidth}\item}{\end{minipage}}
\begin{document}
~\vspace{15cm} % to push the text near the page break
\begin{questions}
\begin{nobreakitem}
\Blindtext[1][4]
\end{nobreakitem}
\begin{nobreakitem}
\Blindtext[2][4]
\begin{questions}
\item \Blindtext[1][4]
\item \Blindtext[1][4]
\item \Blindtext[1][4]
\end{questions}
\end{nobreakitem}
\end{questions}
\end{document}
1b. 作为命令。
我们在前言中定义了一个名为 的命令\nobreakitem
。标准\item
仅适用于其后的内容,但这里我们需要告诉它将 放在哪里\end{minipage}
,所以我们必须用 括住后面的内容{}
并将其传递给我们的命令,这是对 的一个不幸的改变\item
。同样,定义中的换行符\newcommand
是必要的。
\documentclass{article}
\usepackage[english]{babel} % needed by blindtext
\usepackage[pangram]{blindtext} % to produce dummy text only
\usepackage{enumitem}
\newlist{questions}{enumerate}{3}
\setlist[questions,1]{label*=\textbf{\arabic*}.}
\setlist[questions,2]{label=(\alph{questionsii})}
\setlist[questions,3]{label=(\roman{questionsiii})}
\newcommand{\nobreakitem}[1]{
\begin{minipage}{\linewidth}\item #1\end{minipage}}
\begin{document}
~\vspace{15cm} % to push the text near the page break
\begin{questions}
\nobreakitem{\Blindtext[1][4]}
\nobreakitem{\Blindtext[2][4]
\begin{questions}
\item \Blindtext[1][4]
\item \Blindtext[1][4]
\item \Blindtext[1][4]
\end{questions}}
\end{questions}
\end{document}
2. 保留通常使用方法的替代方案\item
\item
为了在问题中保留通常使用的,我们可以使用 的功能enumitem
,其中列表可以恢复上一个列表。这里每个都是包装在 中的\begin{question}
实例,但编号为全局问题集的延续。每个应该只包含一个顶级,但它可以包含子部分(以通常的方式通过 定义)。然后每个顶级问题及其子部分不会跨页。\begin{questions}
minipage
\begin{question}
\item
\begin{questions}
之所以\ifthenelse
使用,是因为连续计数enumitem
需要对第一个列表使用与后续列表不同的命令,并且我希望用户避免考虑这一点。
\documentclass{article}
\usepackage[english]{babel} % needed by blindtext
\usepackage[pangram]{blindtext} % to produce dummy text only
\usepackage{enumitem}
\newlist{questions}{enumerate}{3}
\setlist[questions,1]{label*=\textbf{\arabic*}.}
\setlist[questions,2]{label=(\alph{questionsii})}
\setlist[questions,3]{label=(\roman{questionsiii})}
\usepackage{ifthen}
\gdef\questionsstarted{0}
\newenvironment{question}{\ifthenelse{\equal{\questionsstarted}{0}}{\gdef\questionsstarted{1}\begin{minipage}{\textwidth}\begin{questions}[series=questions,start=1,leftmargin=*,resume]}{\begin{minipage}{\textwidth}\begin{questions}[resume*=questions]}}{\end{questions}\end{minipage}\bigskip}
\begin{document}
~\vspace{15cm} % to push the text near the page break
\begin{question}
\item \Blindtext[1][4]
\end{question}
\begin{question}
\item \Blindtext[2][4]
\begin{questions}
\item \Blindtext[1][4]
\item \Blindtext[1][4]
\item \Blindtext[1][4]
\end{questions}
\end{question}
\end{document}