首页 > 解决方案 > 使用 React Native 进行精确绘图

问题描述

我需要一些帮助来弄清楚如何在 React Native 中精确绘图。我之前在(原生)iOS 上做过这种事情,但还没有在 Android 上做过,所以我可能会错过一个 Android 的东西,但我最好只使用 React Native 方法来解决这个问题,而不是求助于实现自定义视图。

我正在尝试绘制乐谱的五线谱,例如:

员工示例

我正在使用FlatList水平模式下的 React Native 来执行此操作。我在内容单元格内绘制垂直线作为分隔符和水平线。在这一点上,这就是我所关心的,还不是数字等。

我尝试了两种使用 React Native 绘制它的方法:

  1. PNG;我提供普通、@2x 和@3x 版本并将它们呈现在ImageBackground标签中。这适用于 iOS,但在 Android 上,线条并不能完美对齐,因此垂直线和水平线连接不好,存在间隙,并且垂直组件的大小不一样,因此它们是太短。这是因为 @2x 和 @3x 对于 iOS 来说是完美的像素,但仍需要为 Android 进行缩放?
  2. SVG ( react-native-svg); 这给出了类似的问题。同样在 iOS 上的结果相当不错,但在 Android 上的像素排列不正确。为了说明这一点,请参见以下三个屏幕截图。

iOS 上的 SVG:接近完美(但不是 100%): iOS

Android低分辨率设备(emu)上的SVG:很奇怪不同部分的高度有很大不同:

安卓低分辨率

Android高分辨率设备(emu)上的SVG:水平线不连续,垂直线超出上下人员:

安卓高分辨率

我不明白为什么这会变成它在 Android 上的方式。我不确定我是否使用正确的方法来实现这一点。我应该使用什么方法?任何帮助深表感谢!

下面是相关的源代码。它在 ClojureScript 中,但即使您不熟悉它,您也应该能够识别 SVG 的构建方式。我小心地使用半像素值作为线坐标和方形结尾,以便理论上所有内容都应该准确地排列在像素上。

(defn bar-lines [width]
  (take 5 (map (fn [y] ^{:key (str y)}
                 [:> Line {:x1 0.5 :y1 y :x2 (+ 0.5 (dec width)) :y2 y
                           :stroke-width 1 :stroke "black"
                           :stroke-linecap "square"}])
               (iterate (partial + 8) 0.5))))

(defn cell [details]
  (let [item (details "item")
        num (item "measureNumber")]
    [:> ViewOverflow {:style {:width 68 :height 65}}
     [:> Svg {:height 34 :width 68 :view-box "0 0 68 33"
              :style {:position "absolute" :bottom 0}}
      (bar-lines 68)]]))

(defn single-line-separator []
  [:> ViewOverflow {:style {:width 1 :height 65}}
   [:> Svg {:height 34 :width 1 :view-box "0 0 1 33"
            :style {:position "absolute" :bottom 0}}
    [:> Line {:x1 0.5 :y1 0.5 :x2 0.5 :y2 32.5 :stroke-linecap "square" :stroke-width 1 :stroke "black"}]]])

(defn double-line-separator []
  [:> ViewOverflow {:style {:width 3 :height 65}}
   [:> Svg {:height 34 :width 3 :view-box "0 0 3 33"
            :style {:position "absolute" :bottom 0}}
    [:> Line {:x1 0.5 :y1 0.5 :x2 0.5 :y2 32.5 :stroke-linecap "square" :stroke-width 1 :stroke "black"}]
    [:> Line {:x1 2.5 :y1 0.5 :x2 2.5 :y2 32.5 :stroke-linecap "square" :stroke-width 1 :stroke "black"}]
    (bar-lines 3)]])

(defn separator [props]
  (if (show-double-bar? (.-measureNumber (.-leadingItem props)))
    (double-line-separator)
    (single-line-separator)))

(defn header []
  [:> rn/View {:style {:width 15 :height 65}}
   [:> Svg {:height 34 :width 15 :view-box "0 0 15 33"
            :style {:position "absolute" :bottom 0}}
    (bar-lines 15)
    [:> Line {:x1 14.5 :y1 0.5 :x2 14.5 :y2 32.5 :stroke-linecap "square" :stroke-width 1 :stroke "black"}]]])

(defn footer []
  [:> rn/View {:style {:width 11 :height 65}}
   [:> Svg {:height 34 :width 11 :view-box "0 0 11 33"
            :style {:position "absolute" :bottom 0}}
    [:> Line {:x1 0.5 :y1 0.5 :x2 0.5 :y2 32.5 :stroke-linecap "square" :stroke-width 1 :stroke "black"}]
    [:> Line {:x1 4.5 :y1 1.5 :x2 4.5 :y2 31.5 :stroke-linecap "square" :stroke-width 3 :stroke "black"}]
    (bar-lines 3)]])

(defn Staff [styles]
  [:> rn/View styles
   [:> rn/FlatList
    {:data (clj->js (mapv (fn [n] {:key (str n) :measureNumber n}) (range 1 4)))
     :horizontal true
     :Cell-renderer-component ViewOverflow
     :List-header-component #(r/as-element [header])
     :List-footer-component #(r/as-element [footer])
     :Item-separator-component #(r/as-element [separator %])
     :render-item (fn [details] (r/as-element [cell (js->clj details)]))}]])

标签: androidiosreact-native

解决方案


推荐阅读