自动计算列表中最高行的高度

自动计算列表中最高行的高度

我经常有枚举列表,其中列表中的项目高度不均匀,通常是因为显示数学项目,例如dfrac。 (是的,我知道内联显示的显示数学的印刷问题,但这种布局是我正在准备的文档类型的要求。)为了使列表间距均匀,我目前使用vphantom,如下面的 MWE 所示:

\documentclass{article}
\usepackage{enumitem}
\usepackage{mathtools}
\begin{document}

\begin{enumerate}[label=\Alph*)]
    \item $x = y^2 + 4y + 13 \vphantom{\sqrt{\dfrac{x-4}{2}}}$
    \item $x = 2\left(y + 1\right)^2 + 4 \vphantom{\sqrt{\dfrac{x-4}{2}}}$
    \item $y = 2\left(x + 1 \right)^2 - 4 \vphantom{\sqrt{\dfrac{x-4}{2}}}$
    \item $y = -\sqrt{\dfrac{x-4}{2}}+2$
\end{enumerate}

\end{document}

我想做的是让最终用户无需一直记住添加vphantom。据我所知,我需要一个命令来跟踪列表中每行的高度,将最大的一行保存到辅助文件中,并在每个项目中插入一个支柱,该支柱的大小取自保存的值。有没有一个包已经可以做到这一点?或者,我该如何创建这样的命令?(我还没有掌握辅助文件。)

编辑:

Heiko 的解决方案给了我完成这项工作所需的线索。下面是我为包装整个过程所做的工作,这样我就不必每次都费心定义:

\documentclass{article}
\usepackage{enumitem}
\usepackage{mathtools}
\usepackage{etoolbox}
\usepackage{xparse}

\newcommand{\choicestext}{}
\newcommand{\phantomtext}{}

\newcommand{\choice}[1]{%
    \xappto\choicestext{\unexpanded{\item #1\vph}}%
    \xappto\phantomtext{\unexpanded{\{#1\}}}
}

\newenvironment{choices}{%
    \renewcommand{\choicestext}{}%
    \renewcommand{\phantomtext}{}%
}{%
    \def\vph{\vphantom{\smash[b]\phantomtext}}%
    \begin{enumerate}[label=\Alph*)]
        \choicestext
    \end{enumerate}
}

\begin{document}

\begin{choices}
    \choice{$x = y^2 + 4y + 13$}
    \choice{$x = 2\left(y + 1\right)^2 + 4$}
    \choice{$y = 2\left(x + 1 \right)^2 - 4$}
    \choice{$y = -\sqrt{\dfrac{x-4}{2}}+2$}
\end{choices}

\end{document}

答案1

可以将公式放入本地定义的宏中。然后,\vphantom只需使用它们全部,而不需要知道哪个公式具有最大的高度和深度。

\documentclass{article}
\usepackage{enumitem}
\usepackage{mathtools}
\begin{document}

\begin{enumerate}[label=\Alph*)]
    \def\fa{$x = y^2 + 4y + 13$}
    \def\fb{$x = 2\left(y + 1\right)^2 + 4$}
    \def\fc{$y = 2\left(x + 1 \right)^2 - 4$}
    \def\fd{$y = -\sqrt{\dfrac{x-4}{2}}+2$}
    \def\vph{\vphantom{\fa\fb\fc\fd}}
    \item\fa\vph
    \item\fb\vph
    \item\fc\vph
    \item\fd\vph
\end{enumerate}

\end{document}

Result

从图中可以看出,使用最大的公式会浪费大量垂直空间,因为第四个公式的深度很大,与公式之间的间距无关。可以通过以下方法解决此问题:

\documentclass{article}
\usepackage{enumitem}
\usepackage{mathtools}
\begin{document}

\begin{enumerate}[label=\Alph*)]
    \def\fa{$x = y^2 + 4y + 13$}
    \def\fb{$x = 2\left(y + 1\right)^2 + 4$}
    \def\fc{$y = 2\left(x + 1 \right)^2 - 4$}
    \def\fd{$y = -\sqrt{\dfrac{x-4}{2}}+2$}
    \def\vph{\vphantom{\smash[b]{\fa\fb\fc\fd}}}
    \item\fa\vph
    \item\fb\vph
    \item\fc\vph
    \item\fd\vph
\end{enumerate}

\end{document}

Result

如上例所示,对所有公式使用相同的最大高度和深度的做法通常会浪费空间。更好的目标是优化公式之间的空间,即深度与以下高度的总和,换句话说\baselineskip

可以利用 TeX 的行距算法:如果两行太窄(\lineskiplimit),则 TeX 不会使用\baselineskip来实现均匀间距,而是插入\lineskip。以下算法使用不同的 来设置两次 ,以\lineskip检测不均匀间距。然后,\baselineskip增加 ,直到它足够大以实现均匀间距。

采用这种方式时,代码中不应该设置 \baselineskip或者\lineskip明确要求间隔均匀,否则优化会失败。

\documentclass{article}
\usepackage{enumitem}
\usepackage{mathtools}

\makeatletter
\newif\ifEvenSpacing@Uneven
\newcommand*{\EvenSpacing}[1]{%
  \par
  \begingroup
    \EvenSpacing@Try{#1}%
    \@whilesw\ifEvenSpacing@Uneven\fi{%
      \advance\baselineskip by .1pt
      \advance\normalbaselineskip by .1pt
      \EvenSpacing@Try{#1}%
    }%
    #1\par
  \endgroup
}
\newcommand*{\EvenSpacing@Try}[1]{%
  \lineskip=0pt
  \normallineskip=0pt
  \settototalheight{\dimen0}{\parbox{\linewidth}{#1}}%
  \lineskip=1pt
  \normallineskip=1pt
  \settototalheight{\dimen2}{\parbox{\linewidth}{#1}}%
  \ifdim\dimen0=\dimen2
    \EvenSpacing@Unevenfalse
  \else
    \EvenSpacing@Uneventrue
  \fi
}
\makeatother

\begin{document}

\EvenSpacing{\begin{enumerate}[label=\Alph*)]
  \item $x = y^2 + 4y + 13$
  \item $x = 2\left(y + 1\right)^2 + 4$
  \item $y = 2\left(x + 1 \right)^2 - 4$
  \item $y = -\sqrt{\dfrac{x-4}{2}}+2$
\end{enumerate}}

\end{document}

Result

可以通过使用指数搜索来改进算法,直到\baselineskip太大。然后,二分搜索找到最佳的 \baselineskip

相关内容