JSP обманывает для создания шаблонной обработки легче?

Вопрос в том, как манипулировать изображением, подобным ImageView.ScaleType.CENTER_CROP , но сместить фокус из центра в другое место, которое находится на 20% от верхней части изображения. Сначала давайте посмотрим, что делает CENTER_CROP:

Из документации :

CENTER_CROP

Scale изображение равномерно (сохраняйте пропорции изображения), так что оба размера (ширина и высота) изображения будут равны или больше соответствующего размера вида (минус отступ). Затем изображение центрируется на виде. Из XML используйте этот синтаксис: android:scaleType="centerCrop".

blockquote>

Другими словами, масштабируйте изображение без искажений так, чтобы ширина или высота изображения (или ширина, и высота) вписывались в вид, чтобы вид был полностью заполнен изображением (без пропусков). .)

Еще один способ думать об этом состоит в том, что центр изображения «прикреплен» к центру изображения. Затем изображение масштабируется в соответствии с указанными выше критериями.

В следующем видео белые линии отмечают центр изображения; красные линии отмечают центр зрения. Тип шкалы - CENTER_CROP. Обратите внимание, как центральные точки изображения и вида совпадают. При изменении размера представления эти две точки продолжают перекрываться и всегда отображаются в центре вида независимо от размера представления.

enter image description here

Итак, что значит иметь подобный центру поведение в другом месте, например, на 20% сверху? Как и в центре обрезки, мы можем указать, что точка, которая находится в 20% от верхней части изображения, и точка, в которой 20% от верхней части вида будут «закреплены», как точка 50% «закреплена» в центре обрезки. Горизонтальное расположение этой точки остается на уровне 50% изображения и вида. Теперь изображение можно масштабировать для соответствия другим условиям обрезки по центру, которые указывают, что ширина и / или высота изображения будут соответствовать виду без зазоров. (Под размером представления понимается размер представления без заполнения).

Вот короткое видео об этом поведении кадрирования на 20%. В этом видео белые линии показывают середину изображения, красные линии показывают закрепленную точку на виде, а синяя линия, которая отображается за горизонтальной красной линией, обозначает 20% от верхней части изображения. (Демонстрационный проект находится на GitHub .

enter image description here

Вот результат, показывающий полное изображение, которое было предоставлено, и видео в квадратной рамке, переходящее из неподвижного изображения.

enter image description here

MainActivity.kt
[ 1115] prepareMatrix() - это метод, позволяющий определить, как масштабировать / обрезать изображение. Необходимо выполнить дополнительную работу с видео, так как кажется, что видео сделано в соответствии с TextureView как масштаб введите "FIT_XY", когда он назначен для TextureView. Из-за этого масштабирования размер носителя должен быть восстановлен до того, как prepareMatrix() будет вызвано для видео

class MainActivity : AppCompatActivity() {
    private val imageResId = R.drawable.test
    private val videoResId = R.raw.test
    private var player: SimpleExoPlayer? = null
    private val mFocalPoint = PointF(0.5f, 0.2f)

    override fun onCreate(savedInstanceState: Bundle?) {
        window.setBackgroundDrawable(ColorDrawable(0xff000000.toInt()))
        super.onCreate(savedInstanceState)
        if (cache == null) {
            cache = SimpleCache(File(cacheDir, "media"), LeastRecentlyUsedCacheEvictor(MAX_PREVIEW_CACHE_SIZE_IN_BYTES))
        }
        setContentView(R.layout.activity_main)
        //        imageView.visibility = View.INVISIBLE
        imageView.setImageResource(imageResId)
        imageView.doOnPreDraw {
            imageView.scaleType = ImageView.ScaleType.MATRIX
            val imageWidth: Float = ContextCompat.getDrawable(this, imageResId)!!.intrinsicWidth.toFloat()
            val imageHeight: Float = ContextCompat.getDrawable(this, imageResId)!!.intrinsicHeight.toFloat()
            imageView.imageMatrix = prepareMatrix(imageView, imageWidth, imageHeight, mFocalPoint, Matrix())
            val b = BitmapFactory.decodeResource(resources, imageResId)
            val d = BitmapDrawable(resources, b.copy(Bitmap.Config.ARGB_8888, true))
            val c = Canvas(d.bitmap)
            val p = Paint()
            p.color = resources.getColor(android.R.color.holo_red_dark)
            p.style = Paint.Style.STROKE
            val strokeWidth = 10
            p.strokeWidth = strokeWidth.toFloat()
            // Horizontal line
            c.drawLine(0f, imageHeight * mFocalPoint.y, imageWidth, imageHeight * mFocalPoint.y, p)
            // Vertical line
            c.drawLine(imageWidth * mFocalPoint.x, 0f, imageWidth * mFocalPoint.x, imageHeight, p)
            // Line in horizontal and vertical center
            p.color = resources.getColor(android.R.color.white)
            c.drawLine(imageWidth / 2, 0f, imageWidth / 2, imageHeight, p)
            c.drawLine(0f, imageHeight / 2, imageWidth, imageHeight / 2, p)

            imageView.setImageBitmap(d.bitmap)
            imageViewFull.setImageBitmap(d.bitmap)
        }
    }

    fun startPlay(view: View) {
        playVideo()
    }

    private fun getViewWidth(view: View): Float {
        return (view.width - view.paddingStart - view.paddingEnd).toFloat()
    }

    private fun getViewHeight(view: View): Float {
        return (view.height - view.paddingTop - view.paddingBottom).toFloat()
    }

    private fun prepareMatrix(targetView: View, mediaWidth: Float, mediaHeight: Float,
                              focalPoint: PointF, matrix: Matrix): Matrix {
        if (targetView.visibility != View.VISIBLE) {
            return matrix
        }
        val viewHeight = getViewHeight(targetView)
        val viewWidth = getViewWidth(targetView)
        val scaleFactorY = viewHeight / mediaHeight
        val scaleFactor: Float
        val px: Float
        val py: Float
        if (mediaWidth * scaleFactorY >= viewWidth) {
            // Fit height
            scaleFactor = scaleFactorY
            px = -(mediaWidth * scaleFactor - viewWidth) * focalPoint.x / (1 - scaleFactor)
            py = 0f
        } else {
            // Fit width
            scaleFactor = viewWidth / mediaWidth
            px = 0f
            py = -(mediaHeight * scaleFactor - viewHeight) * focalPoint.y / (1 - scaleFactor)
        }
        matrix.postScale(scaleFactor, scaleFactor, px, py)
        return matrix
    }

    private fun playVideo() {
        player = ExoPlayerFactory.newSimpleInstance(this@MainActivity, DefaultTrackSelector())
        player!!.setVideoTextureView(textureView)
        player!!.addVideoListener(object : VideoListener {
            override fun onVideoSizeChanged(width: Int, height: Int, unappliedRotationDegrees: Int, pixelWidthHeightRatio: Float) {
                super.onVideoSizeChanged(width, height, unappliedRotationDegrees, pixelWidthHeightRatio)
                val matrix = Matrix()
                // Restore true media size for further manipulation.
                matrix.setScale(width / getViewWidth(textureView), height / getViewHeight(textureView))
                textureView.setTransform(prepareMatrix(textureView, width.toFloat(), height.toFloat(), mFocalPoint, matrix))
            }

            override fun onRenderedFirstFrame() {
                Log.d("AppLog", "onRenderedFirstFrame")
                player!!.removeVideoListener(this)
                imageView.animate().alpha(0f).setDuration(2000).start()
                imageView.visibility = View.INVISIBLE
            }
        })
        player!!.volume = 0f
        player!!.repeatMode = Player.REPEAT_MODE_ALL
        player!!.playRawVideo(this, videoResId)
        player!!.playWhenReady = true
        //        player!!.playVideoFromUrl(this, "https://sample-videos.com/video123/mkv/240/big_buck_bunny_240p_20mb.mkv", cache!!)
        //        player!!.playVideoFromUrl(this, "https://sample-videos.com/video123/mkv/720/big_buck_bunny_720p_1mb.mkv", cache!!)
        //        player!!.playVideoFromUrl(this@MainActivity, "https://sample-videos.com/video123/mkv/720/big_buck_bunny_720p_1mb.mkv")
    }

    override fun onStop() {
        super.onStop()
        if (player != null) {
            player!!.setVideoTextureView(null)
            //        playerView.player = null
            player!!.release()
            player = null
        }
    }

    companion object {
        const val MAX_PREVIEW_CACHE_SIZE_IN_BYTES = 20L * 1024L * 1024L
        var cache: com.google.android.exoplayer2.upstream.cache.Cache? = null

        @JvmStatic
        fun getUserAgent(context: Context): String {
            val packageManager = context.packageManager
            val info = packageManager.getPackageInfo(context.packageName, 0)
            val appName = info.applicationInfo.loadLabel(packageManager).toString()
            return Util.getUserAgent(context, appName)
        }
    }

    fun SimpleExoPlayer.playRawVideo(context: Context, @RawRes rawVideoRes: Int) {
        val dataSpec = DataSpec(RawResourceDataSource.buildRawResourceUri(rawVideoRes))
        val rawResourceDataSource = RawResourceDataSource(context)
        rawResourceDataSource.open(dataSpec)
        val factory: DataSource.Factory = DataSource.Factory { rawResourceDataSource }
        prepare(LoopingMediaSource(ExtractorMediaSource.Factory(factory).createMediaSource(rawResourceDataSource.uri)))
    }

    fun SimpleExoPlayer.playVideoFromUrl(context: Context, url: String, cache: Cache? = null) = playVideoFromUri(context, Uri.parse(url), cache)

    fun SimpleExoPlayer.playVideoFile(context: Context, file: File) = playVideoFromUri(context, Uri.fromFile(file))

    fun SimpleExoPlayer.playVideoFromUri(context: Context, uri: Uri, cache: Cache? = null) {
        val factory = if (cache != null)
            CacheDataSourceFactory(cache, DefaultHttpDataSourceFactory(getUserAgent(context)))
        else
            DefaultDataSourceFactory(context, MainActivity.getUserAgent(context))
        val mediaSource = ExtractorMediaSource.Factory(factory).createMediaSource(uri)
        prepare(mediaSource)
    }
}

305
задан Community 23 May 2017 в 01:47
поделиться

4 ответа

Как предположил скаффман , Файлы тегов JSP 2.0 - это колени пчелы.

Возьмем ваш простой пример.

Поместите следующее в WEB-INF / tags / wrapper.tag

<%@tag description="Simple Wrapper Tag" pageEncoding="UTF-8"%>
<html><body>
  <jsp:doBody/>
</body></html>

Теперь на вашей странице example.jsp :

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:wrapper>
    <h1>Welcome</h1>
</t:wrapper>

Это именно то, что вы думаете.


Итак, давайте расширим это до чего-то более общего. WEB-INF / tags / genericpage.tag

<%@tag description="Overall Page template" pageEncoding="UTF-8"%>
<%@attribute name="header" fragment="true" %>
<%@attribute name="footer" fragment="true" %>
<html>
  <body>
    <div id="pageheader">
      <jsp:invoke fragment="header"/>
    </div>
    <div id="body">
      <jsp:doBody/>
    </div>
    <div id="pagefooter">
      <jsp:invoke fragment="footer"/>
    </div>
  </body>
</html>

Чтобы использовать это:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:genericpage>
    <jsp:attribute name="header">
      <h1>Welcome</h1>
    </jsp:attribute>
    <jsp:attribute name="footer">
      <p id="copyright">Copyright 1927, Future Bits When There Be Bits Inc.</p>
    </jsp:attribute>
    <jsp:body>
        <p>Hi I'm the heart of the message</p>
    </jsp:body>
</t:genericpage>

Что это дает вам? На самом деле, много, но становится еще лучше ...


WEB-INF / tags / userpage.tag

<%@tag description="User Page template" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>
<%@attribute name="userName" required="true"%>

<t:genericpage>
    <jsp:attribute name="header">
      <h1>Welcome ${userName}</h1>
    </jsp:attribute>
    <jsp:attribute name="footer">
      <p id="copyright">Copyright 1927, Future Bits When There Be Bits Inc.</p>
    </jsp:attribute>
    <jsp:body>
        <jsp:doBody/>
    </jsp:body>
</t:genericpage>

Чтобы использовать это: (предположим, что у нас есть пользовательская переменная в запросе)

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:userpage userName="${user.fullName}">
  <p>
    First Name: ${user.firstName} <br/>
    Last Name: ${user.lastName} <br/>
    Phone: ${user.phone}<br/>
  </p>
</t:userpage>

Но оказывается, вам нравится использовать этот блок сведений о пользователе в других местах. Итак, мы проведем рефакторинг. WEB-INF / теги / userdetail.tag

<%@tag description="User Page template" pageEncoding="UTF-8"%>
<%@tag import="com.example.User" %>
<%@attribute name="user" required="true" type="com.example.User"%>

First Name: ${user.firstName} <br/>
Last Name: ${user.lastName} <br/>
Phone: ${user.phone}<br/>

Теперь предыдущий пример выглядит следующим образом:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="t" tagdir="/WEB-INF/tags" %>

<t:userpage userName="${user.fullName}">
  <p>
    <t:userdetail user="${user}"/>
  </p>
</t:userpage>

Прелесть файлов тегов JSP заключается в том, что они позволяют вам помечать общую разметку, а затем рефакторировать ее так, как вам нравится.

Файлы тегов JSP в значительной степени узурпировали такие вещи, как Tiles и т. Д., По крайней мере, для меня. Я считаю, что их намного проще использовать, так как единственная структура - это то, что вы ей даете, без предвзятости. Кроме того, вы можете использовать файлы тегов JSP для других целей (например, фрагмент сведений о пользователе выше).

Вот пример, похожий на DisplayTag, который я сделал, но все это делается с помощью файлов тегов (и фреймворка Stripes , то есть s: tags ..). В результате получается таблица строк, чередующихся цветов, навигации по страницам и т. Д .:

<t:table items="${actionBean.customerList}" var="obj" css_class="display">
  <t:col css_class="checkboxcol">
    <s:checkbox name="customerIds" value="${obj.customerId}"
                onclick="handleCheckboxRangeSelection(this, event);"/>
  </t:col>
  <t:col name="customerId" title="ID"/>
  <t:col name="firstName" title="First Name"/>
  <t:col name="lastName" title="Last Name"/>
  <t:col>
    <s:link href="/Customer.action" event="preEdit">
      Edit
      <s:param name="customer.customerId" value="${obj.customerId}"/>
      <s:param name="page" value="${actionBean.page}"/>
    </s:link>
  </t:col>
</t:table>

Конечно, теги работают с тегами JSTL (например, c: if и т. Д.). Единственное, что вы не можете сделать в теле тега файла тега, - это добавить код скриптлета Java, но это не такое большое ограничение, как вы могли подумать. Если мне нужны скриптлеты, я просто вставляю логику в тег и вставляю его. Легко.

Итак, файлы тегов могут быть практически такими, какими вы хотите их видеть. На самом базовом уровне это простой рефакторинг вырезания и вставки. Возьмите кусок макета, вырежьте его, выполните простую параметризацию и замените его вызовом тега.

На более высоком уровне вы можете делать сложные вещи вроде этого тега таблицы, который у меня здесь.

678
ответ дан 23 November 2019 в 01:21
поделиться

добавьте dependecys для использования < % @tag описание = "Шаблон User Page" pageEncoding = % "UTF-8">

<dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.2</version>
        <scope>provided</scope>
    </dependency>
        <dependency>
            <groupId>javax.servlet.jsp.jstl</groupId>
            <artifactId>javax.servlet.jsp.jstl-api</artifactId>
            <version>1.2.1</version>
        </dependency>
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
    </dependencies>
0
ответ дан 23 November 2019 в 01:21
поделиться

Это может также быть достигнуто с jsp:include. Чадское Правило штукатура объясняет хорошо здесь в этом видео https://www.youtube.com/watch? v=EWbYj0qoNHo

0
ответ дан 23 November 2019 в 01:21
поделиться

Используйте плитки . Это спасло мне жизнь.

Но если вы не можете, есть тег include , что делает его похожим на php.

Тег body может не делать то, что вам нужно, если только у вас нет сверхпростого содержимого. Тег body используется для определения тела указанного элемента. Взгляните на этот пример :

<jsp:element name="${content.headerName}"   
   xmlns:jsp="http://java.sun.com/JSP/Page">    
   <jsp:attribute name="lang">${content.lang}</jsp:attribute>   
   <jsp:body>${content.body}</jsp:body> 
</jsp:element>

Вы указываете имя элемента, любые атрибуты, которые может иметь элемент (в данном случае «lang»), а затем текст, который идет в нем - тело. Итак, если

  • content.headerName = h1 ,
  • content.lang = fr и
  • content.body = Заголовок на французском языке

, то вывод будет

<h1 lang="fr">Heading in French</h1>
4
ответ дан 23 November 2019 в 01:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: