如何创建一个列表,并在其中的每对项目之间自动插入一条规则?
答案1
2014-07-23:已更新以支持 的可选参数\item
。
您可以使用的另一种方法是重新定义\item
。在这种情况下,这不一定是更好的解决方案,但您不需要依赖其他包的内部结构。我使用了@Werner 在他的解决方案中定义的规则的修改版本,但可以根据需要进行调整。
这里我使用etoolbox
来处理我们不想在最开始就应用上面的规则的情况\item
。我更喜欢这种处理条件的方法,但任何其他方法
条件排版/构建
也可以使用。
第一步是保存项目的原始定义
\LetLtxMacro{\OriginalItem}{\item}%
由于我们正在重新定义带有可选参数的宏,因此我们\LetLtxMacro
使用包裹letltxmacro
。 的详细描述\LetLtxMacro
可以在这个问题中找到闭平方根符号。
现在我们可以用它定义我们自己的 item 版本:
\newcommand{\ItemWithRuleAbove}[1][]{%
\iftoggle{IsFirstItem}{}{\WernersHRule}% only add \hrule if not first item
\IfStrEq{#1}{}{\OriginalItem }{\OriginalItem [#1]}%
\togglefalse{IsFirstItem}%
}%
在哪里:
- 如果这不是第一项,我们添加规则,
- 应用 item 的原始定义,并
- 切换,
IsFirstItem
以便我们知道下次要应用规则。
使用这个定义,我们可以创建MyEnuterate
具有这种行为的环境(假设你并不总是想要这样):
\newenvironment{MyEnumerate}{%
\toggletrue{IsFirstItem}%
\let\item\ItemWithRuleAbove%
\begin{enumerate}%
}{%
\end{enumerate}%
}%
在这个环境中,我们重新定义\item
为使用\ItemWithRuleAbove
,而不是原来的\item
。在这个环境的开始,我们切换IsFirstItem
到 true,以便为这个实例初始化它MyEnumerate
。
笔记:
- 我用过包裹
xstring
用于字符串比较,但如果需要的话,可能不需要这个包就可以完成。 在这个答案对
mdframed
和项目之间的奇怪互动,egreg 提到重新定义
\item
可能很危险,而且会产生不可预测的结果然而,在这种情况下,重新定义保持在本地
MyEnumerate
环境中,所以应该没问题。
代码:
直接从@Werner 的解决方案中复制的枚举内容:
\documentclass{article}
\usepackage{etoolbox}
\usepackage{xstring}
\usepackage{letltxmacro}
\newtoggle{IsFirstItem}% so we don't add rule above first item
\toggletrue{IsFirstItem}% personal preference: initialize variables explicetly at time of defintion
\newcommand*{\WernersHRule}{% Slightly Modified
\par\kern\dimexpr.7\itemsep-\parskip-.6\baselineskip\relax%
\hrulefill%
\par\kern\dimexpr.3\itemsep-.3\parskip-.6\baselineskip\relax%
}%
\LetLtxMacro{\OriginalItem}{\item}% store existing definition of \item
\newcommand{\ItemWithRuleAbove}[1][]{%
\iftoggle{IsFirstItem}{}{\WernersHRule}% only add \hrule if not first item
\IfStrEq{#1}{}{\OriginalItem }{\OriginalItem [#1]}%
\togglefalse{IsFirstItem}%
}%
\newenvironment{MyEnumerate}{%
\toggletrue{IsFirstItem}%
\let\item\ItemWithRuleAbove%
\begin{enumerate}%
}{%
\end{enumerate}%
}%
\begin{document}
\begin{minipage}{.45\linewidth}
\begin{MyEnumerate}
\item An item with descender p
\item[a.] An item without descenders
\item abcdefghijklmnopqrstuvwxyz
\end{MyEnumerate}
\end{minipage}
%
\begin{minipage}{.45\linewidth}
\begin{enumerate}
\item An item with descender p
\item[a.] An item without descenders
\item abcdefghijklmnopqrstuvwxyz
\end{enumerate}
\end{minipage}
\end{document}
答案2
标准列表结构(itemize
和enumerate
)由组成\list
。在此的开头\list
,将条件\@newlist
设置为true
(通过)。这将根据插入的垂直空间将第一项与其余项分开。以下是摘自中\global\@newlisttrue
的条件\@item
latex.ltx
:
\if@newlist
\if@nobreak
\@nbitem
\else
\addpenalty\@beginparpenalty
\addvspace\@topsep
\addvspace{-\parskip}%
\fi
\else
\addpenalty\@itempenalty
\addvspace\itemsep
\fi
因此,基于此,\itemsep
只有当我们不是时才会插入\@newlist
。
使用etoolbox
现在可以进行修补\@item
和修改\addvspace\itemsep
以插入“装饰”:
\documentclass{article}
\usepackage{etoolbox}% http://ctan.org/pkg/xpatch
\begin{document}
\noindent%
\begin{minipage}{.45\linewidth}
\begin{enumerate}
\item An item with descender p
\item An item without descenders
\item abcdefghijklmnopqrstuvwxyz
\end{enumerate}
\end{minipage}
%
\makeatletter
\patchcmd{\@item}
{\addvspace\itemsep}
{\par\kern\dimexpr.7\itemsep-.7\parskip-.7\baselineskip\relax%
\hrulefill%
\par\kern\dimexpr.3\itemsep-.3\parskip-.3\baselineskip\relax}
{}{}%
\makeatother
%
\begin{minipage}{.45\linewidth}
\begin{enumerate}
\item An item with descender p
\item An item without descenders
\item abcdefghijklmnopqrstuvwxyz
\end{enumerate}
\end{minipage}
\end{document}
左侧是常规列表,右侧显示经过修改的相同列表\itemsep
。
如果你想要\hrulefill
拉伸整个\textwidth
(而不是\linewidth
),你可以使用
\makeatletter
\patchcmd{\@item}
{\addvspace\itemsep}
{\par\kern\dimexpr.7\itemsep-.7\parskip-.7\baselineskip\relax%
\hspace*{\dimexpr-\itemindent-\labelwidth-\labelsep}\hrulefill%
\par\kern\dimexpr.3\itemsep-.3\parskip-.3\baselineskip\relax}
{}{}%
\makeatother
它纠正了\itemindent
,\labelwidth
并将\labelsep
其插入列表中。
选择 70%/30% 跳过水平线有些随意,但基于 的定义\strutbox
。它们一起构成了整个\itemsep
。