自定义环境中的正确垂直间距和分页符

自定义环境中的正确垂直间距和分页符

我想设计一个显示示例的简单环境。这是我目前得到的:

\documentclass{article}
\usepackage{xcolor}
\usepackage{parskip}
\usepackage{lipsum}

\makeatletter
  \newcommand\filltoend{\leavevmode\leaders\hrule height 0.7ex depth \dimexpr0.4pt-0.7ex\hfill\kern0pt}
  \newcounter{example}
  \newenvironment{example}[1][]{%
    \refstepcounter{example}%
    \textbf{Example~\theexample{}}~{\color{gray}\filltoend}% number and line
    \nopagebreak% is this the right place?
    \par% should I call other vertical spacing commands so I can use the plus/minus syntax?
    \textbf{#1}% Heading
    \par\itshape\ignorespaces%
  }{%
     \\% it would be nice to keep this together with contents
     {\color{gray}\null\filltoend\null}
  }

\makeatother


\begin{document}
\lipsum[1-4]
\begin{example}[My example]
    \lipsum[5]
\end{example}
\end{document}

这很简单而且还可以。

如何指定示例的数字和行、标题和文本之间需要一些不可拉伸的垂直空间?如何阻止 LaTeX 在标题组件之间放置分页符?

换句话说:我希望将Example # ---标题和内部段落的开头保持在同一页面上,并且它们之间的间距不要太大。

答案1

如果你愿意使用额外的包,我建议你使用tcolorbox。这为您提供了无限的自定义可能性,并为您提供了解决您提到的问题的机制(标题中没有分页符,分页符前至少有 5 行,自动处理可选参数,轻松自定义各个元素之间的间距)。

这是一个模拟您的环境的小示例:

\documentclass{article}
\usepackage[a5paper]{geometry}% just for the example
\usepackage{lipsum}
\usepackage{tcolorbox}
\tcbuselibrary{most}

\tcbset{mybox/.style={
  before={\par\vskip3ex\noindent},
  after={\par\vskip1.5ex}}}

\newtcolorbox[auto counter=example]{example}[1][]{
breakable,
mybox,
notitle after break,
lines before break=5,
enhanced,
colback=white,
colframe=white,
coltitle=black,
fonttitle=\bfseries,
arc=0pt,
outer arc=0pt,
leftrule=0pt,
rightrule=0pt,
left=0pt,
right=0pt,
boxsep=0pt,
toptitle=.5\baselineskip,
bottomtitle=-.1\baselineskip,
title=#1,
enlarge top by=4ex,
overlay unbroken={
    \node[fill=white,anchor=west,font=\bfseries,inner xsep=0pt] 
      at (frame.north west) (title) {Example~\thetcbcounter\enspace};
    \draw[thick] (title.east|-frame.north east) -- (frame.north east);
    \draw[thick] (frame.south west) -- (frame.south east);
  },
overlay first={
    \node[fill=white,anchor=west,font=\bfseries,inner xsep=0pt] 
      at (frame.north west) (title) {Example~\thetcbcounter\enspace};
    \draw[thick] (title.east|-frame.north east) -- (frame.north east);
  },
overlay last={
    \draw[thick] (frame.south west) -- (frame.south east);
  },
}


\begin{document}
\lipsum[5]
\begin{example}[My example]
\lipsum[5]
\end{example}
\lipsum[5]
\begin{example}
\lipsum[1-3]
\end{example}
\lipsum[5]

\end{document}

在此处输入图片描述

答案2

标题现在实际上是文本第一行的一部分,因此无法分离。

\documentclass{article}
\usepackage{xcolor}
\usepackage{parskip}

\newlength{\test}

\newcommand\filltoend{\leavevmode\leaders\hrule height 0.7ex depth \dimexpr0.4pt-0.7ex\hfill\kern0pt}
  \newcounter{example}
  \newenvironment{example}[1][]{%
  \refstepcounter{example}%
  \vspace{0.5\baselineskip}\par\noindent%
  \raisebox{\baselineskip}{\parbox[b]{\linewidth}%
  {\textbf{Example~\theexample{}}~{\color{gray}\filltoend}% number and line
  \settowidth{\test}{#1}\ifdim\test>0pt% test for optional argument
  \vspace{0.5\baselineskip}\linebreak\textbf{#1}\fi}% Heading
  \hspace{-\linewidth}}\hspace{\parindent}%start of text
    }{%
  \hfill% the following acts as a strut at the end of the line
  {\hspace{-\linewidth}\color{gray}\rule[-.5\baselineskip]{\linewidth}{.4pt}}
  \par
}

\begin{document}
\rule{1pt}{.88\textheight}\\% Easier to adjust
last line.

\begin{example}[My example]% adds a space if not commented
Fusce mauris. Vestibulum luctus nibh at lectus. Sed bibendum, nulla a faucibus
semper, leo velit ultricies tellus, ac venenatis arcu wisi vel nisl. Vestibulum diam.
Aliquam pellentesque, augue quis sagittis posuere, turpis lacus congue quam,
in hendrerit risus eros eget felis. Maecenas eget erat in sapien mattis porttitor.
Vestibulum porttitor. Nulla facilisi. Sed a turpis eu lacus commodo facilisis.
Morbi fringilla, wisi in dignissim interdum, justo lectus sagittis dui, et vehicula
libero dui cursus dui. Mauris tempor ligula sed lacus. Duis cursus enim ut
augue. Cras ac magna. Cras nulla. Nulla egestas. Curabitur a leo. Quisque
egestas wisi eget nunc. Nam feugiat lacus vel est. Curabitur consectetuer.
\end{example}

New paragraph.
\end{document}

为了使环境的末尾正常工作,我必须使用实际文本而不是 \lipsum,它必须在每个段落的末尾包含一个 \par。

答案3

我想出了自己的解决方案并在这里分享,因为它可能对其他人有用。

使用tcolorboxmdframed类似的包是一种选择,但首先,我想知道如何进行适当的间距,其次,这些线条不一定会出现在我的最终设计中,第三,tikz对于我的需求来说,它们似乎有点过度(它们使用)。

所以我看了这个问题第一段以粗体显示且无分页符的环境 并意识到要走的路是设置惩罚和寡妇/孤儿值。因此,为了有一个段落分隔符来阻止分页并使文本保持在一起,您可以定义如下内容:

\newcommand{\nbpar}{\widowpenalty=10000 \@@par\penalty10000}

那么我的环境可以重写为

\newenvironment{example}[1][]{%
  \def\@extitle@{#1}%
  \refstepcounter{example}%
  \par\smallskip%
  {\parskip=0.5\baselineskip \advance\parskip by 0pt plus 0pt%
  \textbf{Example~\theexample{}}~{\color{gray}\filltoend}%
  \ifx\@extitle@\@empty\relax\else\nbpar\textbf{#1}\fi\nbpar\mbox{}}%
  \itshape\ignorespaces}%
  {\nbpar{\color{gray}\filltoend\mbox{}}}

我也在那里重新定义了(在一个组中),\parskip这样我就可以控制标题块中的空间的可拉伸程度。

现在,由于我不太喜欢它的外观,我选择了一种更简单但我认为很好的方式来将示例与其余内容区分开来:粗体标题和末尾的装饰;使用\nbpar如上所述来处理间距。

\usepackage{adforn}
\newcommand{\exOrnament}{\adforn{21}}

\newenvironment{example}[1][]{%
  \def\@extitle@{#1}%
  \refstepcounter{example}%
  \par\medskip%
  {\parskip=0.5\baselineskip \advance\parskip by 0pt plus 0pt
  \textbf{Example~\theexample{}}%
  \ifx\@extitle@\@empty\relax\else~--~\textbf{#1}\fi\nbpar\makebox{}}%
  \itshape\ignorespaces}%
  {\unskip\nbpar\hfill\exOrnament\hfill\mbox{}\par}

相关内容