<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Amine Aytaç on Medium]]></title>
        <description><![CDATA[Stories by Amine Aytaç on Medium]]></description>
        <link>https://medium.com/@amineytc_?source=rss-8cadd461f54d------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*3LbHxJkumY9kyc3MkoVdWA.jpeg</url>
            <title>Stories by Amine Aytaç on Medium</title>
            <link>https://medium.com/@amineytc_?source=rss-8cadd461f54d------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 25 May 2026 15:23:28 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@amineytc_/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Android | Custom View First Look]]></title>
            <link>https://medium.com/@amineytc_/android-custom-view-first-look-856dc41d8caa?source=rss-8cadd461f54d------2</link>
            <guid isPermaLink="false">https://medium.com/p/856dc41d8caa</guid>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[custom-views]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[custom-view-android]]></category>
            <dc:creator><![CDATA[Amine Aytaç]]></dc:creator>
            <pubDate>Fri, 25 Oct 2024 07:14:56 GMT</pubDate>
            <atom:updated>2024-10-25T07:24:19.105Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-w6J28HqHKjeKUd0NrVJzA.jpeg" /></figure><p>Hello everyone!! In this article, we will introduce custom views, which play an important role in Android development. Additionally, we will explore the usage of commonly used structures such as Canvas, Paint, and Path in custom views. Enjoy reading in advance!</p><h4>👀Custom View</h4><p>When creating Android screen designs, we usually use ready-made components or views (such as TextView, Button, ImageView). However, we may encounter situations in our projects where standard views and components are insufficient, requiring more unique and application-specific designs and functionalities. At this point, we take advantage of the flexibility offered by custom views by creating our own views.</p><p>Creating our own custom views gives us complete control over the functionality and appearance of the view. We can create views in various styles according to our requirements and make any changes we want to these views without any restrictions.</p><p>✦There are different approaches to creating custom views. These include:</p><p>➜ We can create custom views by inheriting from views such as Button, TextView, and ImageView that we use in screen design, and we can add new features to these views.</p><p>➜ We can create a more flexible and customized custom view structure from scratch by inheriting from the View class itself.</p><p>➜ When we want to create and use multiple custom views together, we can build this structure using FrameLayout or LinearLayout. This allows us to easily arrange and manage nested custom views.</p><p>In the following sections of the article, we will explore how to create a custom view from scratch and how to use these views nested within each other.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/783/1*a3MJKWAkuVQ21hBs5ZBUXw.png" /></figure><p>In our custom view example, which we will create by inheriting from the <strong>View</strong> class, we will try to achieve the appearance shown above.</p><pre>class One @JvmOverloads constructor(<br>    context: Context,<br>    attrs: AttributeSet? = null,<br>    defStyleAttr: Int = 0<br>) : View(context, attrs, defStyleAttr) {}</pre><p>➜ As the first step, we inherited from the View class and created a class named One. Thus, the One class now represents a custom view. The <strong>@JvmOverloads </strong>annotation next to the constructor allows for the creation of overloaded constructors so that the constructors of the View class can be called with different parameter combinations from the Java side.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/386/1*0jK1Er4Ey1DDhSONoa48uw.png" /></figure><p>Inheriting from the View class brings the use of Context, AttributeSet, and Int in the constructor. So why do we use them, and what are their roles?</p><p>Each parameter is necessary for the custom view to function and be used correctly in environments such as activities and fragments. The Context parameter indicates in which environment the custom view will operate and which resources it will access accordingly. This is because a view accesses resources through its environment. The Attrs parameter allows us to read the attributes defined for the custom view in the XML file, making these XML-defined attributes usable by the custom view. The DefStyleAttr parameter is necessary if we want to apply a specific style or theme to the view.</p><p>👉🏻 We are not required to use all of the Context, attrs, and defStyleAttr parameters in the constructor. If we want to use the custom view programmatically instead of in XML, there is no need to use the attrs and defStyleAttr parameters.</p><pre>private val viewRectF = RectF()<br><br>override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {<br>   super.onSizeChanged(w, h, oldw, oldh)<br>   viewRectF.set(0f,0f,w.toFloat(),h.toFloat())<br>}</pre><p>➜ In the next step, we override the onSizeChanged function. This function is called whenever the size of the custom view we used in XML changes, allowing for dynamic updates to the size. For example, when we change the orientation of the mobile device from portrait to landscape or when views like a bottom sheet dialog appear on the screen, the onSizeChanged function is called, thus keeping track of the old and new size values of the custom view.</p><p>By creating a RectF object, we store the boundary information of the custom view (left, top, right, bottom). This way, when we assign values using viewRectF.set() within the onSizeChanged function, the boundaries are updated according to the new dimensions of the custom view each time the function is called.</p><pre>private val imageRectF=RectF() <br><br>private val bitmap: Bitmap =<br>   BitmapFactory.decodeResource(context.resources,R.drawable.book)<br><br>private val matrix = Matrix()<br><br>private val imagePaint = Paint().apply { isAntiAlias=true }</pre><p>➜ In this step, we make the necessary definitions to draw the image in our custom view. We create a RectF object named imageRectF to hold the boundary information of the image (left, top, right, bottom). This way, we will keep the size information of the image.</p><p>If we want to draw images on custom views, we need to use the Bitmap class for this purpose. A Bitmap represents an image (such as a picture or an icon) and contains a grid of pixels, holding the color information for each pixel. In other words, when we want to create an image on the screen, Android processes and displays this image in Bitmap format. Therefore, we convert our image from the drawable resource into a Bitmap object.</p><p>👉🏻 We cannot create files like SVG and XML with Bitmap. If we want to use an image, it must be in PNG, JPG, or WEBP format. The reason for this is that Bitmap is designed to process pixels. Since files like SVG and XML are vector-based rather than pixel-based, we cannot use them with Bitmap.</p><p>We create a <strong>Matrix</strong> object for operations such as drawing the Bitmap on the screen, scaling it, or stretching it from the left or right. Then, we create a <strong>Paint</strong> object named imagePaint. You can think of the Paint class as a brush. When we want to draw a bitmap or a shape, we can define the color properties using the Paint class. In our example, since we are using a bitmap, we did not specify any color. We only set <strong>isAntiAlias = true</strong> to prevent rough edges from appearing around the bitmap.</p><pre>private fun initImageMatrix() {<br>   imageRectF.set(0f,0f,bitmap.width.toFloat(),bitmap.height.toFloat())<br><br>   val widthScale = viewRectF.width() / imageRectF.width()<br>   val heightScale = viewRectF.height() / imageRectF.height()<br><br>   val scaleFactor = max(widthScale, heightScale)<br><br>   val translateX = (viewRectF.width()-scaleFactor*imageRectF.width())/2f<br>   val translateY = (viewRectF.height()-scaleFactor*imageRectF.height())/2f<br><br>   matrix.setScale(scaleFactor,scaleFactor)<br>   matrix.postTranslate(translateX,translateY)<br>   invalidate()<br>}</pre><p>After the necessary definitions, we use the initImageMatrix() function to set the scaling of the bitmap according to the viewRectF. This way, whenever the boundaries of viewRectF change, the bitmap will also adjust to fit those boundaries.</p><pre>imageRectF.set(0f,0f,bitmap.width.toFloat(),bitmap.height.toFloat())</pre><p>Initially, we set the boundaries of the imageRectF object according to the bitmap. Thus, the left, top, right, and bottom values of imageRectF will take on the boundary values of the bitmap.</p><pre>val widthScale = viewRectF.width() / imageRectF.width()<br>val heightScale = viewRectF.height() / imageRectF.height()<br>val scaleFactor = max(widthScale, heightScale)</pre><p>Then, by dividing the width and height of viewRectF by the width and height of imageRectF, we obtain the scale values needed to fit imageRectF within viewRectF. By using the maximum scaling factor, we ensure that the bitmap is positioned within viewRectF while maintaining its height and width values. (You can think of the maximum scaling factor as the centerCrop scale type)</p><pre>val translateX = (viewRectF.width()-scaleFactor*imageRectF.width())/2f<br>val translateY = (viewRectF.height()-scaleFactor*imageRectF.height())/2f<br><br>matrix.setScale(scaleFactor,scaleFactor)<br>matrix.postTranslate(translateX,translateY)<br>invalidate()</pre><p>As the final step for the InitImageMatrix function, we calculate the offset ratio in the width and height parameters to ensure that imageRectF fits perfectly within viewRectF. Then, we use the matrix to correctly position imageRectF inside viewRectF. By calling invalidate, we ensure that the current state of imageRectF is redrawn on the screen for the custom view.</p><pre>override fun onDraw(canvas: Canvas) {<br>   canvas.drawBitmap(bitmap,matrix,imagePaint)<br>}</pre><p>To draw the bitmap we created on the screen, we override the onDraw function and perform this operation using the canvas object (which you can think of as a blank piece of paper). This function is called whenever the size of the custom view changes, just like in the onSizeChanged function, and it performs the necessary updates.</p><pre>override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {<br>   super.onSizeChanged(w, h, oldw, oldh)<br>   viewRectF.set(0f,0f,w.toFloat(),h.toFloat())<br>   initImageMatrix()<br>}</pre><p>As the final step of this phase, we call the initImageMatrix function within the onSizeChanged function. This way, whenever onSizeChanged is executed, the dimensions of the bitmap are updated, and it is scaled according to these dimensions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Q2so_KJru1fMQrWz1BcEjg.png" /><figcaption>Display the bitmap with different values</figcaption></figure><p>➜ As the next step, we will draw the black outer border of the image in our example.</p><pre>private val framePath = Path()<br>private val framePaint=Paint(Paint.ANTI_ALIAS_FLAG).apply {<br>    color= ContextCompat.getColor(context,R.color.black)<br>    style=Paint.Style.STROKE<br>    strokeWidth=12.toFloat()<br>}</pre><p>Initially, we create a Path object named framePath. The <strong>Path</strong> helps us draw lines between specific points, allowing us to create the desired shape. Then, we create a <strong>Paint</strong> object named framePaint. To avoid a jagged appearance, we set the ANTI_ALIAS_FLAG, and we select a color from our color resource using ContextCompat.getColor(). By setting the style to stroke, we indicate that the painting should only occur on the edges and that the inside should remain uncolored. We also specify the thickness of the line using FrameStrokeWidth.</p><pre>private fun initFramePath() {<br>    val cornerRadius = 100f<br>    framePath.reset()<br><br>    framePath.moveTo(viewRectF.left, viewRectF.top)<br>    framePath.lineTo(viewRectF.right , viewRectF.top)<br>    framePath.lineTo(viewRectF.right, viewRectF.bottom )<br>    framePath.lineTo(viewRectF.left + cornerRadius, viewRectF.bottom)<br>    framePath.arcTo(viewRectF.left, viewRectF.bottom - 2 * cornerRadius, 2 * cornerRadius,<br>        viewRectF.bottom, 90f, 90f, false)<br>    framePath.lineTo(viewRectF.left, viewRectF.top + cornerRadius)<br>    framePath.close()<br><br>    invalidate()<br>}</pre><p>In the next step, we created the initFramePath function, where we will draw our shape. We established a cornerRadius value to define the corner radius for rounded corners. Since the dimensions of the shape we draw with the path will also change whenever the custom view&#39;s size changes, we reset the path using framePath.reset . This ensures that the path is redrawn according to the new dimensions.</p><p>When drawing lines with the Path, we start by defining a starting point using framePath.moveTo . Then, we create our lines sequentially with framePath.lineTo. To achieve rounded corners, we use the framePath.arcTo method. Once we complete the shape, we close the path by calling framePath.close . Finally, we call invalidate to ensure that the custom view is redrawn so that the updated shape appears on the screen.</p><pre>override fun onDraw(canvas: Canvas) {<br>    canvas.clipPath(framePath)<br>    canvas.drawBitmap(bitmap,matrix,imagePaint)<br>    canvas.drawPath(framePath,framePaint)<br>}<br><br>override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {<br>   super.onSizeChanged(w, h, oldw, oldh)<br>   viewRectF.set(0f,0f,w.toFloat(),h.toFloat())<br>   initImageMatrix()<br>   initFramePath()<br>}</pre><p>As the final step of this process, we call the initFramePath function within the onSizeChanged function. This way, every time onSizeChanged is executed, initFramePath will also be called, allowing the path to be redrawn according to size changes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PiKEx7y9nhyPvsdSJAznhg.png" /><figcaption>Different values for the custom view appearance</figcaption></figure><p>We have seen how to create a custom view from scratch. Now let’s move on to how we can use nested custom views in XML…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/779/1*l1-G-22Ziyle_DA2IriQMg.png" /></figure><p>➜ The operations we will perform in this section are quite simple. We just need to make a few changes to the first example we did.</p><pre>class Two @JvmOverloads constructor(<br>    context: Context,<br>    attrs: AttributeSet? = null,<br>    defStyleAttr: Int = 0<br>) : FrameLayout(context, attrs, defStyleAttr) {}</pre><p>The first of these changes is to inherit from FrameLayout instead of the View class. This way, the custom view we write will behave like a layout.</p><pre>init {<br>  setWillNotDraw(false)<br>}</pre><p>The second change is that when we inherit from FrameLayout, the onDraw function within the custom view will not be drawn. To prevent this, we set setWillNotDraw to false. This way, we can use the onDraw function.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/764/1*nav-lkYIpipRlloW6KQiLw.png" /></figure><p>Source code:</p><p><a href="https://github.com/amineytc/CustomViewExamples">GitHub - amineytc/CustomViewExamples</a></p><p>I hope this article has been helpful and informative for you. For more detailed information, you can check the links below, and feel free to contact me via <a href="https://www.linkedin.com/in/amine-aytac/">LinkedIn</a> for any comments or questions regarding the article.</p><p>See you in the next article!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/498/1*IbSBPGezGO8kzt-0SpOfIQ.gif" /></figure><p>References:</p><ul><li><a href="https://blog.devgenius.io/tagged/custom-views">Custom Views - Dev Genius</a></li><li><a href="https://developer.android.com/develop/ui/views/layout/custom-views/custom-components">Create custom view components | Views | Android Developers</a></li><li><a href="https://www.lvguowei.me/categories/android-custom-view-102/page/4/">Android Custom View 102</a></li><li><a href="https://medium.com/@ibrahimethemsen/android-custom-view-101-df4b4143cf93">Android Custom View 101</a></li><li><a href="https://halil-ozcan.medium.com/android-custom-views-1-matrix-porterduffxfermode-c5a00454201b">Android Custom Views — 1 (Matrix &amp; PorterDuffXfermode)</a></li><li><a href="https://medium.com/@paulnunezm/canvas-animations-simple-circle-progress-view-on-android-8309900ab8ed">Canvas animations: Simple Circle Progress View on Android</a></li><li><a href="https://medium.com/mindorks/building-a-customview-tictactoe-6afa054df928">Building a CustomView -TicTacToe</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=856dc41d8caa" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Android | Custom View İlk Bakış]]></title>
            <link>https://medium.com/@amineytc_/android-custom-view-i%CC%87lk-bak%C4%B1%C5%9F-b0c6cba18a7d?source=rss-8cadd461f54d------2</link>
            <guid isPermaLink="false">https://medium.com/p/b0c6cba18a7d</guid>
            <category><![CDATA[andorid]]></category>
            <category><![CDATA[custom-view-android]]></category>
            <category><![CDATA[custom-views]]></category>
            <category><![CDATA[kotlin]]></category>
            <dc:creator><![CDATA[Amine Aytaç]]></dc:creator>
            <pubDate>Fri, 25 Oct 2024 07:14:15 GMT</pubDate>
            <atom:updated>2024-10-25T07:23:48.908Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-w6J28HqHKjeKUd0NrVJzA.jpeg" /></figure><p>Tekrardan merhabalar herkese. Bu yazımda Android geliştirmede önemli bir yeri olan custom view’lara giriş yapacağız. Ek olarak custom view’larda yaygın olarak kullanılan Canvas, Paint ve Path yapılarının kullanımlarını da görmüş olacağız. Şimdiden keyifli okumlar…</p><h4>👀Custom View</h4><p>Android ekran tasarımlarını oluştururken genellikle hazır component’ler veya view’lar (TextView, Button, ImageView gibi) kullanırız. Ancak, projelerimizde zaman zaman standart view ve component’lerin yetersiz kaldığı, daha özgün ve uygulamaya özel tasarım ve işlevselliklerin gerektiği durumlarla karşılaşabiliriz. Bu noktada kendi view’larımızı oluşturarak custom view’lerin sunduğu esneklikten faydalanırız.</p><p>Kendi custom view’larımızı oluşturmak view’in işlevi ve görselliği üzerinde tam kontrol sahibi olmamızı sağlar. Gereksinimlere göre çeşitli tarzlarda view’ler oluşturabilir ve herhangi bir kısıtlama olmadan bu view’ler üzerinde istediğimiz değişiklikleri yapabiliriz.</p><p>✦ Custom View oluşturmada farklı yaklaşımlar vardır. Bunlar;</p><p>➜ Ekran tasarımında kullandığımız Button, TextView, ImageView gibi view’lardan kalıtım alarak custom view’lar oluşturabilir ve bu view’lara yeni özellikler ekleyebiliriz.</p><p>➜ View sınıfının kendisinden kalıtım alarak sıfırdan, daha esnek ve özelleştirilmiş bir custom view yapısı oluşturabiliriz.</p><p>➜ Birden fazla custom view oluşturmak ve birlikte kullanmak istediğimiz durumlarda, FrameLayout veya LinearLayout kullanarak bu yapıyı oluşturabiliriz. Bu sayede iç içe custom view’ları kolayca yerleştirip yönetebiliriz.</p><p>Yazının ilerleyen bölümünde, sıfırdan bir custom view oluşturmayı ve bu view’ları nasıl iç içe kullanabileceğimizi inceleyeceğiz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/783/1*a3MJKWAkuVQ21hBs5ZBUXw.png" /></figure><p><strong>View</strong> sınıfını kalıtım alarak oluşturacağımız custom view örneğimizde yukarıda yer alan görünümü elde etmeye çalışacağız.</p><pre>class One @JvmOverloads constructor(<br>    context: Context,<br>    attrs: AttributeSet? = null,<br>    defStyleAttr: Int = 0<br>) : View(context, attrs, defStyleAttr) {}</pre><p>➜ İlk adım olarak View sınıfını kalıtım alıp, One isminde bir sınıf oluşturduk. Böylece One sınıfı artık bir custom view’ı temsil eder hale geldi. Constructor yanında yer alan <strong>@JvmOverloads</strong> annotation’ı ise View sınıfına ait yapılandırıcıların ( constructor’ların ) Java tarafında farklı parametre kombinasyonları ile çağırılabilmesi için overloaded yapılandırıcılar oluşturmakta.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/386/1*0jK1Er4Ey1DDhSONoa48uw.png" /></figure><p>View sınıfını kalıtım almamız, constructor’da Context, AttributeSet ve Int kullanımını beraberinde getirmekte. Peki neden kullanıyoruz ve görevleri neler?</p><p>Her bir parametre custom view’ın activity ve fragment gibi kullanılacağı ortamlarda doğru şekilde çalışabilmesi ve de kullanılması için gereklidir. <strong>Context </strong>parametresi bize custom view’ın hangi ortamda çalışacağını ve buna bağlı olarak hangi kaynaklara erişeceğini belirtir. Çünkü bir view, bulunduğu ortam üzerinden kaynaklara erişim sağlar. <strong>Attrs </strong>parametresi, custom view’ın XML dosyasında tanımladığımız özelliklerini okumamızı sağlar. Böylece XML de tanımlanan özellikler custom view tarafından kullanılabilir hale gelir. <strong>DefStyleAttr </strong>parametresi ise view’a belirli bir stil veya tema uygulamak istiyorsak gereklidir.</p><p>👉🏻 Context, attrs ve defStyleAttr parametrelerinin hepsini constructor da kullanmak zorunda değiliz. Eğer oluşturduğumuz custom view’ı XML yerine programatik bir şekilde kullanmak istiyorsak attrs ve defStyleAttr parametrelerini kullanımına gerek kalmıyor.</p><pre>private val viewRectF = RectF()<br><br>override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {<br>   super.onSizeChanged(w, h, oldw, oldh)<br>   viewRectF.set(0f,0f,w.toFloat(),h.toFloat())<br>}</pre><p>➜ Bir sonraki adımda ise onSizeChanged fonksiyonunu override ediyoruz. Bu fonksiyon, XML içerisinde kullandığımız custom view’ın size’ı her değiştiğinde çağırılır ve size üzerinde dinamik olarak güncelleme yapar. Örneğin, mobil cihazı dikey konumdan yatay konuma aldığımızda ya da ekranda bottom sheet dialog gibi görünümler çıktığında onSizeChanged fonksiyonu çağırılır ve böylece custom view’ın eski ve yeni size değerleri tutulmuş olur.</p><p>RectF nesnesi oluşturarak, custom view&#39;ın çerçeve sınır bilgilerini (left, top, right, bottom) saklamış oluruz. Bu sayede, onSizeChanged fonksiyonu içerisinde viewRectF.set() ile değer atadığımızda ve fonksiyon çağırımı her yapıldığında custom view&#39;ın yeni boyutlarına göre sınırları güncellenmiş olur.</p><pre>private val imageRectF=RectF() <br><br>private val bitmap: Bitmap =<br>   BitmapFactory.decodeResource(context.resources,R.drawable.book)<br><br>private val matrix = Matrix()<br><br>private val imagePaint = Paint().apply { isAntiAlias=true }</pre><p>➜ Bu adımda ise örneğimizdeki resmi custom view’a çizmek için gerekli olan tanımlamaları yapıyoruz. Resmimizin çerçeve sınır bilgilerini (left, top, right, bottom) tutacak <strong>imageRectF</strong> isminde bir RectF nesnesi oluşturuyoruz. Bu sayede resmin boyut bilgilerini tutmuş olacağız.</p><p>Custom view’lara resim çizmek istiyorsak bunun için <strong>Bitmap </strong>sınıfını<strong> </strong>kullanmamız gerekli. Bitmap, bir görüntüyü (resim, ikon vb.) temsil eder. Piksellerin sıralandığı bir ızgarayı içerir ve her bir pikselin renk bilgilerini barındırır. Yani, ekranda bir görüntü oluşturmak istediğimizde Android, bu görüntüyü Bitmap formatında işler ve gösterir. Bunun için biz de drawable dosyasında yer alan resmimizi Bitmap nesnesine dönüştürüyoruz.</p><p>👉🏻 ️Bitmap ile svg ve xml gibi dosyaları create edemeyiz. Eğer bir görsel kullanmak istiyorsak bu png, jpg veya webp uzantılı dosyalarla olmalıdır. Bunun sebebi ise Bitmap’in pikselleri işlemek üzere tasarlanmış olması. Svg ve xml gibi dosyalar piksel yerine vector tabanlı olduğu için Bitmap ile kullanımını sağlayamayız.</p><p>Bitmap’in ekranda çizilmesi, büyültülmesi, sağdan veya soldan genişletilmesi gibi işlemleri için <strong>Matrix</strong> nesnesi oluşturuyoruz. Ardından imagePaint isminde bir <strong>Paint</strong> nesnesi oluşturuyoruz. Paint sınıfını kalem gibi düşünebilirsiniz. Bir bitmap veya şekil çizmek istediğimizde renk özelliklerini Paint sınıfı ile belirleyebiliyoruz. Örneğimizde bitmap kullandığımız için herhangi bir renk vermedik. Sadece <strong>isAntiAlias = true</strong> ifadesi ile bitmap kenarlarında pürüzlü görünümlerin oluşmasını engelledik.</p><pre>private fun initImageMatrix() {<br>   imageRectF.set(0f,0f,bitmap.width.toFloat(),bitmap.height.toFloat())<br><br>   val widthScale = viewRectF.width() / imageRectF.width()<br>   val heightScale = viewRectF.height() / imageRectF.height()<br><br>   val scaleFactor = max(widthScale, heightScale)<br><br>   val translateX = (viewRectF.width()-scaleFactor*imageRectF.width())/2f<br>   val translateY = (viewRectF.height()-scaleFactor*imageRectF.height())/2f<br><br>   matrix.setScale(scaleFactor,scaleFactor)<br>   matrix.postTranslate(translateX,translateY)<br>   invalidate()<br>}</pre><p>Gerekli olan tanımlamaların ardından initImageMatrix() fonksiyonu ile oluşturduğumuz bitmap’in viewRectF’e göre ölçeklendirilmesini ayarlıyoruz. Böylece viewRectF sınırları her değiştiğinde bitmap de bu sınırlara uyum sağlayacakır.</p><pre>imageRectF.set(0f,0f,bitmap.width.toFloat(),bitmap.height.toFloat())</pre><p>Başlangıçta imageRectF nesnesinin sınırlarını bitmap’e göre ayarlıyoruz. Böylece imageRectF’in left, top, right ve bottom değerleri bitmap’in sınır değerlerini alacaktır.</p><pre>val widthScale = viewRectF.width() / imageRectF.width()<br>val heightScale = viewRectF.height() / imageRectF.height()<br>val scaleFactor = max(widthScale, heightScale)</pre><p>Ardından viewRectF’in genişlik ve yükseliği ile imageRectF’in genişlik ve yükseliğini bölerek, imageRectF’i viewRectF’e sığdırmak için gerekli olan scale değerlerini elde ediyoruz. Scale değerlerini <strong>max </strong>ölçekleme faktörü<strong> </strong>ile aldığımızda bitmap’in viewRectF’e yükseklik ve genişlik değerleri korunarak yerleşmesini sağlamış oluyoruz. ( max<strong> </strong>ölçekleme faktörünü, centerCrop<strong> </strong>scale type’ı olarak düşünebilirsiniz )</p><pre>val translateX = (viewRectF.width()-scaleFactor*imageRectF.width())/2f<br>val translateY = (viewRectF.height()-scaleFactor*imageRectF.height())/2f<br><br>matrix.setScale(scaleFactor,scaleFactor)<br>matrix.postTranslate(translateX,translateY)<br>invalidate()</pre><p>InitImageMatrix fonksiyonu için son adım olarak, imageRectF&#39;in viewRectF içerisine tam olarak yerleşebilmesi için genişlik ve yükseklik parametrelerindeki kaydırma oranını hesaplıyoruz. Ardından, matrix ile imageRectF&#39;in viewRectF içerisine doğru bir şekilde yerleşimini gerçekleştiriyoruz. Invalidete ile de imageRectF&#39;in güncel halinin ekranda görünmesi için custom view&#39;ın yeniden çizilmesini sağlıyoruz.</p><pre>override fun onDraw(canvas: Canvas) {<br>   canvas.drawBitmap(bitmap,matrix,imagePaint)<br>}</pre><p>Oluşturduğumuz bitmap’in ekrana çizilebilmesi için onDraw fonksiyonunu override ederek, bu işlemi canvas nesnesi (beyaz bir kağıt gibi düşünebilirsiniz) aracılığıyla gerçekleştiriyoruz. Bu fonksiyon onSizeChanged fonksiyonunda olduğu gibi custom view’ın size’ı her değiştiğinde çağırılır ve güncelleme yapar.</p><pre>override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {<br>   super.onSizeChanged(w, h, oldw, oldh)<br>   viewRectF.set(0f,0f,w.toFloat(),h.toFloat())<br>   initImageMatrix()<br>}</pre><p>Bu adımın son işlemi olarak initImageMatrix fonksiyonunu onSizeChanged fonksiyonu içerisinde çağırıyoruz. Bu şekilde, onSizeChanged her çalıştığında bitmap&#39;in boyutları güncellenir ve bu boyutlara göre ölçeklenmiş olur.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Q2so_KJru1fMQrWz1BcEjg.png" /><figcaption>Farklı değerlerde bitmap görünümü</figcaption></figure><p>➜ Bir sonraki adım olarak örneğimizde yer alan resmin siyah dış çerçevesini çizeceğiz.</p><pre>private val framePath = Path()<br>private val framePaint=Paint(Paint.ANTI_ALIAS_FLAG).apply {<br>    color= ContextCompat.getColor(context,R.color.black)<br>    style=Paint.Style.STROKE<br>    strokeWidth=12.toFloat()<br>}</pre><p>Başlangıçta, framePath isminde bir Path nesnesi oluşturuyoruz. <strong>Path</strong>, belirli noktalar arasında çizgiler çizmemize yardımcı oluyor. Yani, istediğimiz şekli Path ile oluşturacağız. Ardından framePaint isminde bir <strong>Paint</strong> nesnesi oluşturuyoruz. Pürüzlü bir görünüm oluşmaması için ANTI_ALIAS_FLAG , renk belirlemek için ise ContextCompat.getColor() ile kendi color dosyamızdan renk seçiyoruz. Style’a stroke vererek boyamanın sadece kenarlarda olmasını, iç kısmın boyalı olmaması gerektiğini söylüyoruz. FrameStrokeWidth ile de çizgimizin kalınlığını belirtiyoruz.</p><pre>private fun initFramePath() {<br>    val cornerRadius = 100f<br>    framePath.reset()<br><br>    framePath.moveTo(viewRectF.left, viewRectF.top)<br>    framePath.lineTo(viewRectF.right , viewRectF.top)<br>    framePath.lineTo(viewRectF.right, viewRectF.bottom )<br>    framePath.lineTo(viewRectF.left + cornerRadius, viewRectF.bottom)<br>    framePath.arcTo(viewRectF.left, viewRectF.bottom - 2 * cornerRadius, 2 * cornerRadius,<br>        viewRectF.bottom, 90f, 90f, false)<br>    framePath.lineTo(viewRectF.left, viewRectF.top + cornerRadius)<br>    framePath.close()<br><br>    invalidate()<br>}</pre><p>Sıradaki işlemde şeklimizi çizeceğimiz initFramePath fonksiyonunu oluşturduk. Köşe ovalliği için cornerRadius değeri oluşturarak köşe yarıçapı belirledik. Custom view size’ı her değiştiğinde path ile çizdiğimiz şeklin boyutları da değişeceği için framePath.reset<strong> </strong>diyerek, path’in sıfırlanmasını sağladık. Bu sayede yeni boyutlara göre path tekrardan çizilmiş olacak.</p><p>Path ile çizgi çizerken ilk adımda framePath.moveTo ile bir başlangıç noktası belirliyoruz. Ardından framePath.lineTo ile sırasıyla çizgilerimizi oluşturuyoruz. Köşe ovalliği için ise framePath.arcTo methodunu kullanıyoruz. Şekli tamamladığımızda framePath.close diyerek path’i kapatıyoruz. En son ise invalidate diyerek, güncel halinin ekranda görünmesi için custom view’ın yeniden çizilmesini sağlıyoruz.</p><pre>override fun onDraw(canvas: Canvas) {<br>    canvas.clipPath(framePath)<br>    canvas.drawBitmap(bitmap,matrix,imagePaint)<br>    canvas.drawPath(framePath,framePaint)<br>}<br><br>override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {<br>   super.onSizeChanged(w, h, oldw, oldh)<br>   viewRectF.set(0f,0f,w.toFloat(),h.toFloat())<br>   initImageMatrix()<br>   initFramePath()<br>}</pre><p>Bu adımın son işlemi olarak initFramePath fonksiyonunu onSizeChanged fonksiyonu içerisinde çağırıyoruz. Bu şekilde, onSizeChanged her çalıştığında initFramePath de çağırılarak, path’in boyut değişikliklerine göre tekrardan çizimi sağlanacaktır.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PiKEx7y9nhyPvsdSJAznhg.png" /><figcaption>Farklı değerlerde custom view görünümü</figcaption></figure><p>Sıfırdan bir custom view’ı nasıl oluşturacağımızı görmüş olduk. Artık XML üzerinde iç içe custom view kullanımını nasıl yapacağımıza geçelim…</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/779/1*l1-G-22Ziyle_DA2IriQMg.png" /></figure><p>➜ Bu kısımda yapacağımız işlemler oldukça basit. Sadece ilk yaptığımız örnek üzerinde birkaç değişiklik yapmamız gerekli.</p><pre>class Two @JvmOverloads constructor(<br>    context: Context,<br>    attrs: AttributeSet? = null,<br>    defStyleAttr: Int = 0<br>) : FrameLayout(context, attrs, defStyleAttr) {}</pre><p>Bu değişikliklerden ilki View sınıfını kalıtım almak yerine FrameLayout’dan kalıtım almak. Böylece yazdığımız custom view bir layout gibi davranacaktır.</p><pre>init {<br>  setWillNotDraw(false)<br>}</pre><p>İkinci değişiklik ise, FrameLayout’dan kalıtım aldığımızda custom view içerisindeki onDraw fonksiyonu çizilmez bir hale gelecek. Bunu engellemek için setWillNotDraw’u false ayarlıyoruz. Böylelikle onDraw fonksiyonunu kullanabilir hale geliyoruz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/764/1*nav-lkYIpipRlloW6KQiLw.png" /></figure><p>Kaynak kodlar :</p><p><a href="https://github.com/amineytc/CustomViewExamples">GitHub - amineytc/CustomViewExamples</a></p><p>Umarım faydalı ve açıklayıcı bir yazı olmuştur sizin için. Detaylı bilgi için aşağıdaki linklere bakabilir, yazı ile ilgili görüş ve sorularınız için <a href="https://www.linkedin.com/in/amine-aytac/">Linkedin</a> üzerinden benimle iletişime geçebilirsiniz.</p><p>Bir sonraki yazıda görüşmek üzere🙌🏻</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/498/1*IbSBPGezGO8kzt-0SpOfIQ.gif" /></figure><p>Kaynaklar :</p><ul><li><a href="https://blog.devgenius.io/tagged/custom-views">Custom Views - Dev Genius</a></li><li><a href="https://developer.android.com/develop/ui/views/layout/custom-views/custom-components">Create custom view components | Views | Android Developers</a></li><li><a href="https://www.lvguowei.me/categories/android-custom-view-102/page/4/">Android Custom View 102</a></li><li><a href="https://medium.com/@ibrahimethemsen/android-custom-view-101-df4b4143cf93">Android Custom View 101</a></li><li><a href="https://halil-ozcan.medium.com/android-custom-views-1-matrix-porterduffxfermode-c5a00454201b">Android Custom Views — 1 (Matrix &amp; PorterDuffXfermode)</a></li><li><a href="https://medium.com/@paulnunezm/canvas-animations-simple-circle-progress-view-on-android-8309900ab8ed">Canvas animations: Simple Circle Progress View on Android</a></li><li><a href="https://medium.com/@arastrak/android-puls-view-canvas-path-and-vectors-b67bc46443f4">Android puls view: Canvas, Path and vectors</a></li><li><a href="https://medium.com/mindorks/building-a-customview-tictactoe-6afa054df928">Building a CustomView -TicTacToe</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b0c6cba18a7d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Android | Activity, Fragment & Lifecycles]]></title>
            <link>https://medium.com/@amineytc_/android-activity-fragment-lifecycles-5a3f82481a46?source=rss-8cadd461f54d------2</link>
            <guid isPermaLink="false">https://medium.com/p/5a3f82481a46</guid>
            <category><![CDATA[fragments]]></category>
            <category><![CDATA[context]]></category>
            <category><![CDATA[activity]]></category>
            <category><![CDATA[lifecycle]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Amine Aytaç]]></dc:creator>
            <pubDate>Fri, 03 Nov 2023 08:14:07 GMT</pubDate>
            <atom:updated>2024-08-02T07:36:29.051Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WfbwbDnfDaWmqrZ8J73e5A.jpeg" /></figure><p>Selamlar👋, bu yazımda android bileşenlerinden biri olan activity ve onunla birlikte kullanılan fragment ikilisinin ne olduğundan, yaşam döngü süreçlerinden bahsedeceğim. Aynı zamanda context ve single activity pattern kavramlarını da görmüş olacağız💫</p><h4>👀<strong>Activity</strong></h4><p><strong>Activity</strong>, uygulamalarımızda kullanıcı ara yüzünün temsil edildiği ekran ve de kullanım sırasında yapılan eylemlere bağlı olarak kendine ait yaşam döngüsü ile uygulama kontrolünü sağlayan bir android bileşenidir(component).</p><p>👉🏻Uygulamalarımızda birden fazla activity barındırabiliriz fakat genel kullanım olarak <em>Single Activity Pattern</em> kullanımı tercih edilmekte. <strong>Single Activity Pattern</strong>, <em>tek bir</em> <em>activity </em>üzerine bir veya birden fazla fragment bağlanmasını ifade eder.</p><p>👉🏻Aynı zamanda Activity’ler birer <strong>context</strong> dir. Bu yüzden oluşturulma maliyetleri yüksektir. Context kavramına yakından bakalım;</p><p>✔️<strong>Context, </strong>uygulama kaynak ve sınıflarına erişim sağlaması ile birlikte activity başlatılmasında, intent ile ekranlar arası geçişlerde, veri tabanı işlemleri gibi işlevlerin gerçekleştirilmesinde kullanılan abstract bir sınftır.</p><p>✔️Context, uygulamada o an bulunulan ortamı işaret eder ve diğer uygulama bileşenleri ile de iletişimi sağlar. Daha iyi kavramak adına örneklendirelim; Bir okulda branş bazlı öğretmenler ve sınıflar olsun. Öğretmenleri uygulama bileşenleri olarak düşünebiliriz. Her bir öğretmen <em>kendi</em> branş sınıfında gerekli kontrolleri sağlamakta ve öğrencilere bilgi aktarımında bulunmakla görevli (fragmentları öğretmen olarak düşünürsek, kendi lifecycle döngülerinde durum kontrollerini sağlar ve de kendi ortamından sorumludur ). Burada okul, bizim için <em>context</em> kavramını ifade eder. Context olmadan uygulama bileşenlerinin görevlerini yapması mümkün değildir.</p><p>✔️Context, <strong>application context</strong> ve <strong>activity context</strong> olmak üzere ayrılır. <strong><em>Application context;</em> </strong>Uygulama yaşam döngüsü sonlanmadığı sürece ayakta kalır ve uygulama seviyesinde kaynak erişimine açıktır.</p><p><strong><em>Activity context; </em></strong><em>A</em>ctivity seviyesinde kaynak erişimine açıktır. Her bir activitynin <em>kendine ait</em> activity context i vardır ve <em>kendi</em> activity lifecycle süreçlerine bağlıdır. Eğer bulunulan activity sonlandırılırsa o activity context de sonlanmış olur.</p><h4>👀Fragment</h4><p><strong>Fragment,</strong> activity içerisinde kullanılabilen aynı zamanda uygulama işlevselliğini artıran bir UI component dir. Bir veya birden fazla fragment activity içerisinde yer alabilir.</p><p>👉🏻Fragmentlar kendi yaşam döngülerine sahiptir.</p><p>👉🏻Fragment lar bir context değildir. Bu sebeple fragment oluşturmak activity kıyasla daha az maliyetlidir.</p><p>⚡Şimdi sırasıyla activity ve fragment lifecycle süreçlerine bakalım..</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2FKYDNnecoxHtelTuYXt%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2FKYDNnecoxHtelTuYXt%2Fgiphy-downsized-large.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2FKYDNnecoxHtelTuYXt%2Fgiphy-downsized-large.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="244" frameborder="0" scrolling="no"><a href="https://medium.com/media/0eaa304f1f5377bc628d98e602eb206e/href">https://medium.com/media/0eaa304f1f5377bc628d98e602eb206e/href</a></iframe><h4>👀Activity Lifecycle</h4><p>Activity lifecycle, bir activity nin oluşturulduğu an ve sonlandığı an arasında oluşabilecek durumlar ve bu durumların birbirleri ile olan bağlantısını içerir.</p><p>👉Uygulama kullanımı sırasında kullanıcının; Activity değiştirmesi, ilgili activity arka planda bekletmesi, dikey ve yatay mod arasında geçişler yapması (configuration changed) gibi durumlar lifecycle metotlarının değişimine sebep olur.</p><p>👉Lifecycle sürecinde callback metotları ile oluşabilecek durumları kontrol edebilir ve gerekli anda ihtiyaç olan durumları yönetebiliriz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YSla09s3skbIoqqW4UV-cQ.png" /></figure><p>Yukarıdaki görselden metot açıklamalarını ve lifecycle sürecini görebilirsiniz.🔎Senaryo bazlı metot çağırımlarına bakalım..</p><p>👉Uygulama açıldığında :</p><p>onCreate -&gt; onStart -&gt; onResume</p><p>👉Home tuşuna basarak uygulamayı arka plana aldığımızda :</p><p>onUserInteraction -&gt; onUserLeaveHint -&gt; onPause -&gt; onStop</p><p>📌onUserInteraction : Odak activity de iken kullanıcının ekranda her hangi bir yere tıklaması sonucu çağırılan metot.</p><p>📌onUserLeaveHint : Kullanıcı home tuşuna her bastığında çağırımı gerçekleşen metot.</p><p>👉Arka plandan uygulamayı çıkarıp activity tekrar gördüğümüzde :</p><p>onRestart -&gt; onStart -&gt; onResume</p><p>👉Ön plana başka bir uygulama alıp, asıl uygulamamızı arka planda beklettiğimizde :</p><p>onPause -&gt; onSaveInstanceState -&gt; onStop</p><p>📌onSaveInstanceState : Aktivite durumunun ve verilerin bundle ile geçici olarak saklandığı metot.</p><p>👉Ekran döndürüldüğünde :</p><p>onPause → onSaveInstanceState -&gt; onStop → onDestroy → onCreate → onStart → onRestoreInstanceState -&gt; onResume</p><p>📌onRestoreInstanceState : Geçici olarak saklanan activity durumu ve verilerin geri yüklendiği metot.</p><p>👉Uygulamadan çıktığımızda :</p><p>onPause → onStop → onDestroy</p><h4>👀Fragment Lifecycle</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/607/0*Kl7GzbJ6kD9B0nmd.png" /></figure><p>Activity lifecycle da olan <em>onCreate, onStart, onResume, onPause, onStop ve onDestroy</em> metotları fragment lifecycle sürecinde de mevcut. Activity lifecycle sürecinde bu metotların açıklamalarını yapmıştık. 🔎Fragment lifecycle özel diğer metotların ne olduğuna bakalım..</p><p>👉<strong>onAttach : </strong>Fragment oluşturulmadan önce activity-fragment bağlantısı gerçekleştiğinde çağırılan metot.</p><p>👉<strong>onCreateView : </strong>Fragment kullanıcı arayüzünün(UI) oluşturulurken çağırımı yapılan metot.</p><p>👉<strong>onActivityCreated : </strong>Fragment bağlandığı activity nin onCreate metot çağırımı gerçekleştiğinde çağırımı yapılır.</p><p>👉<strong>onDestroyView : </strong>Fragment kullanıcı ara yüzünün görünür olmadığı durumda çağırılan metot. Ara yüz görünür olmasa bile fragment varlığını sürdürmeye devam eder.</p><p>👉<strong>onDetach :</strong> Fragment-activity bağlantısının koptuğu an da çağırılan metot.</p><ul><li><a href="https://developer.android.com/reference/android/content/Context">Context | Android Developers</a></li><li><a href="https://developer.android.com/guide/fragments">Fragments | Android Developers</a></li><li><a href="https://developer.android.com/guide/fragments/lifecycle">Fragment lifecycle | Android Developers</a></li><li><a href="https://developer.android.com/guide/components/activities/activity-lifecycle">The activity lifecycle | App architecture | Android Developers</a></li><li><a href="https://developer.android.com/reference/android/app/Activity">Activity | Android Developers</a></li><li><a href="https://medium.com/androiddevelopers/the-android-lifecycle-cheat-sheet-part-iii-fragments-afc87d4f37fd">The Android Lifecycle cheat sheet — part III : Fragments</a></li></ul><p>Umarım faydalı ve açıklayıcı bir yazı olmuştur sizin için. Detaylı bilgi için yukarıdaki linklere bakabilir, yazı ile ilgili görüş ve sorularınız için <a href="https://www.linkedin.com/in/amine-aytac/">Linkedin</a> üzerinden benimle iletişime geçebilirsiniz.</p><p>Bir sonraki yazıda görüşmek üzere🙌</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2FcArmte7hBPzxt095X6%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2FcArmte7hBPzxt095X6%2Fgiphy.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2FcArmte7hBPzxt095X6%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="244" frameborder="0" scrolling="no"><a href="https://medium.com/media/d93007e45975046ba9382f0e764bb2f3/href">https://medium.com/media/d93007e45975046ba9382f0e764bb2f3/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5a3f82481a46" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kotlin | Classes]]></title>
            <link>https://medium.com/@amineytc_/kotlin-classes-2c7f6aa6a149?source=rss-8cadd461f54d------2</link>
            <guid isPermaLink="false">https://medium.com/p/2c7f6aa6a149</guid>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[constructor]]></category>
            <category><![CDATA[class]]></category>
            <category><![CDATA[object-oriented]]></category>
            <dc:creator><![CDATA[Amine Aytaç]]></dc:creator>
            <pubDate>Tue, 22 Aug 2023 16:04:34 GMT</pubDate>
            <atom:updated>2024-06-12T10:06:28.645Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OXHRwgYcptcjprUPRUS85Q.jpeg" /></figure><p>Tekrardan merhabalar herkese. Bu yazımda nesne yönelimli programlamanın temel yapı taşlarından olan sınıflardan bahsedeceğim. Ek olarak sınıflarda yaygın olarak kullanılan init ve this yapılarının kullanımlarını örnekler üzerinden görmüş olacağız.</p><h4>👀Sınıflar</h4><p>Sınıflar belirli bir gruba ait özelliklerin ve işlevlerin toplandığı yerdir. Günlük yaşamdan örnek verirsek; insan sınıfımız olsun. Bu sınıf insana ait isim, yaş, meslek gibi özelliklere ve de yürüme, koşma gibi işlevlere de sahip olabilir. Her bir birey de insan sınıfından türemiş nesneleri ifade edebilir. Her bir bireyin kendine özgü ismi, yaşı vb. özellik ve işlevleri vardır.</p><p>🔎Şimdi sınıfların kotlin ile nasıl yazılabildiğini inceleyelim.</p><pre>fun main(){<br><br>    val electronicDevice=ElectronicDevice()<br>}<br><br>class ElectronicDevice</pre><p>👉🏻Kotlin’de classanahtar kelimesiyle sınıflarımızı oluştururuz.</p><p>Bu örnekte ElectronicDeviceisminde bir sınıfımız var. Bu sınıfımız herhangi bir özelliğe ya da işleve sahip değil. Bu yüzden<em> sınıf isimlendirmesinin sonuna</em> parantez()koymamıza gerek yok.</p><p>Sınıfımızdan bir instance ( nesne olarak düşünebilirsiniz ) oluşturmak istediğimizde sınıfımızı yapılandırmamız gerek. Bunun için de sınıf ismi ve <em>yapılandırıcı parantezi</em> birlikte kullanıyoruz. Bu örneğimizde instance (nesne)electronicDevice bizim için.</p><p>📌Burada bahsi geçen <em>yapılandırıcı parantez</em> aslında <strong><em>constructor parantezi</em></strong><em>. </em><strong><em>Constructor</em></strong><em> </em>ise<em> </em>yapılandırma fonksiyonu<em>. </em>Constructor lar instance oluşturmada ve sınıfa ait özelliklerin tanımlanması noktasında karşımıza çıkar.</p><p>📌Constructor lar <strong><em>primary</em></strong><em> </em>ve <strong><em>secondary</em> <em>constructor</em></strong> olmak üzere ikiye ayrılır. Sınıf tanımının yanına yapılandırıcı parantez açarak <em>primary constructor </em>tanımlamış oluruz. Yapılandırıcı parantez den önce ister constructor kelimesi yazılmış olsun ister olmasın, yapılandırıcı parantezi açmak <em>primary constructor </em>olduğunu belirtir.</p><p>📌Primary constructor tanımı yapmasak bile arka planda () default boş bir constructor oluşturulur.</p><p>📌S<em>econdary constructor</em> ise harici olarak class içerisinde constructor kelimesi ile kullanılarak tanımlanır. Secondary constructor tanımı yaparken primary constructor’ı işaret etme zorunluluğumuz vardır.</p><p>📌Secondary constructor, primary constructor da herhangi bir değere sahip olan değişkenleri içermek zorunda değildir.</p><p>🔎 Teorik anlatım havada kalmış olabilir. Örnekler üzerinden constructor yapısına yakından bakalım.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2FfeOLsVVsYft04%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2FfeOLsVVsYft04%2Fgiphy.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2FfeOLsVVsYft04%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="244" frameborder="0" scrolling="no"><a href="https://medium.com/media/5fe2b6b3f91a5d2bd38a56cd726e9158/href">https://medium.com/media/5fe2b6b3f91a5d2bd38a56cd726e9158/href</a></iframe><pre>fun main(){<br><br>    val electronicDevice = ElectronicDevice(45,&quot;cable&quot;)<br>    println(electronicDevice.electricPower) // 45<br>}<br><br>class ElectronicDevice constructor(<br>    val electricPower:Int,<br>    val electronicComponents:String)</pre><p>Yukarıdaki örnekte ElectronicDevicesınıfına ait özellikleri (electricPower, electronicComponents) yapılandırma aşamasında belirttik. Instance oluştururken ise parametre tiplerine göre değerler verip instance oluşturmuş olduk.</p><p>Örneğimizdeki constructor, sınıf isminin hemen ardından gelmiş durumda. Bu sebeple yapılandırıcımız <em>primary constructor</em>.</p><p>🤔Sınıfa ait özellikleri yapılandırırken constructoranahtar kelimesinin yukarıdaki örnekte kullanıldığını gördük. Peki constructor kelimesini yazmak bu örnek için gerçekten gerekli mi ? Cevabımız hayır.</p><pre>class ElectronicDevice (val electricPower:Int,val electronicComponents:String)</pre><p>📌Eğer primary constructor herhangi bir annotation veya visibility modifier içermiyorsa constructor kelimesini yazmadan da kullanabiliriz.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/632/1*_Z5Oj_nKmFxdiFVOMJr2Iw.png" /></figure><p>Aynı örneği constructor içindeki parametrelere valveya varvermeden yazdığımızda, üretilen nesneden parametrelere ulaşamayız.</p><p>📌Constructor içindeki parametrelere valveya varverirsem o sınıfa ait bir özellik haline gelirler yani erişim sağlayıp kullanabilirim. Vermediğimde ise o sınıfa ait bir özellik değil de o sınıfı yapılandırmaya yardımcı bir değer haline gelirler. Ve sadece <em>init blokları</em> içerisinde erişip kullanabilirim.</p><pre>fun main(){<br>    val deviceOne = ElectronicDevice(45, &quot;cable&quot;)<br>    val deviceTwo = ElectronicDevice(&quot;samsungS23&quot;)<br>    println(deviceOne.electricPower)<br>}<br><br>class ElectronicDevice (val electricPower:Int,val  electronicComponents:String){<br><br>    init{<br>        println(&quot;Power: $electricPower, Components: $electronicComponents&quot;)<br>    }<br><br>    constructor(deviceName:String) : this(60,&quot;&quot;) {<br>        println(&quot;Secondary constructor - deviceName: $deviceName&quot;)<br>    }<br>}<br><br>/*<br>Power: 45, Components: cable<br>Power: 60, Components: <br>Secondary constructor - deviceName: samsungS23<br>45<br>*/</pre><p>Bu örneğimizde sınıf isminin hemen ardından <em>primary constructor</em> ve de sınıf içerisinde constructor anahtar kelimesiyle <em>secondary constructor</em> oluşturulmuş durumda.</p><p>🔎Şimdi sırasıyla örneğimizde yer alan init ve this yapılarına göz gezdirelim.</p><p>📌 <strong>init : </strong>Sınıfa parametre verileri <em>geldiği anda</em> eğer veriler ile bir şeyleri sınıf içerisinde değiştirmek veya işlem yapmak istiyorsam, <em>init bloğu</em> oluşturmam gerekli.</p><p>Örneğimizde de parametre verileri geldiği anda çalıştırılması için init blokları içerisinde println ile ekrana belirtilen ifadenin yazılmasını sağladık.</p><p>👉🏻 val olarak tanımladığım bir değişkene init bloğunda değer atıyorsam, değişkeni val olarak kullanmaya devam edebilirim.</p><p>👉🏻Bir sınıf birden fazla <strong>init</strong> bloğuna sahip olabilir.</p><p>👉🏻<strong>Init</strong> ler yazıldığı sıraya göre çalışırlar.</p><p>📌<strong>this: </strong>İçinde bulunduğumuz sınıfın kendisine erişmek için kullandığımız yapılardır.</p><p>Örneğimizde <em>secondary constructor</em> tanımlarlen <em>this</em> yapısının kullanıldığını görüyoruz. Bu şekilde bir kullanım yapmamızın sebebi , <em>primary constructor da yer alan parametrelerin initialize edilmesi gerektiği</em>. Eğer secondary constructor da this yapısını kullanmazsak hata ile karşılaşırız.</p><pre>class Phone( val model: String,val costs: Int){<br><br>    init{<br>        println(&quot;$model phone costs $ $costs &quot;)<br>    }<br><br>    constructor( color:String) : this(&quot;iphone14&quot;,900){<br>        println(&quot;$model phone color is $color&quot;)<br>    }<br>}<br><br>fun main(){<br><br>    val phoneWithPrimaryConst = Phone(&quot;samsungS23&quot;,800)<br>    val phoneWithSecondaryConst = Phone(&quot;black&quot;)<br>}<br><br>/*<br>samsungS23 phone costs $ 800 <br>iphone14 phone costs $ 900 <br>iphone14 phone color is black<br>*/</pre><p>Örneğimizde iki tane instance tanımı yapılmış durumda. İlk olarak primary constructor ardından secondary constructor gereklilikleri ile instance oluşturulmuş.</p><p>Tüm bu yapılan işlemler çalıştırıldığında ilk init blok içerisi ekrana yazılmış olacak. Sebebi ise primay constructor’a veriler geldiğinde init bloğunun çalışıyor olması. phoneWithSecondaryConstinstance çağırımı yapıldığında ise secondary constructor da this yapısı ile primary constructor initialize edildiği için tekrardan init bloğu içerisi çalışıp sonrasında secondary constructor bloğu içerisindeki işlem yapılmış olacak.</p><p><a href="https://kotlinlang.org/docs/classes.html">Classes | Kotlin</a></p><p>Umarım faydalı ve açıklayıcı bir yazı olmuştur sizin için. Yazı ile ilgili fikir ve sorularınız için <a href="https://www.linkedin.com/in/amine-aytac/">Linkedin</a> üzerinden benimle iletişime geçebilirsiniz.</p><p>Bir sonraki yazıda görüşmek üzere!</p><p>İyi kodlamalarr..</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2F3ov9jPgJXd58xyzWzS%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2F3ov9jPgJXd58xyzWzS%2Fgiphy.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2F3ov9jPgJXd58xyzWzS%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="217" frameborder="0" scrolling="no"><a href="https://medium.com/media/5c314907531e52cded4893bd03d9221d/href">https://medium.com/media/5c314907531e52cded4893bd03d9221d/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2c7f6aa6a149" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kotlin | Higher Order Functions]]></title>
            <link>https://medium.com/@amineytc_/kotlin-higher-order-functions-8a42d29cec96?source=rss-8cadd461f54d------2</link>
            <guid isPermaLink="false">https://medium.com/p/8a42d29cec96</guid>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[higher-order-function]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[Amine Aytaç]]></dc:creator>
            <pubDate>Fri, 21 Jul 2023 20:38:41 GMT</pubDate>
            <atom:updated>2023-11-05T13:01:33.469Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jlUWQLk4kTRVKfnE2nvPRA.jpeg" /></figure><p>Tekrardan merhaba herkese. Bu yazımda Kotlin’de önemli bir yeri olan kimi zaman da kafa karışıklığı yaratan higher order fonksiyonlara değineceğim. Şimdiden keyifli okumalar..</p><h4>👀Higher Order Functions</h4><p>Parametre olarak fonksiyon alan ya da duruma bağlı olarak fonksiyon döndüren <em>fonksiyonun kendisine</em> higher order fonksiyon diyoruz. ✍Higher Order fonksiyon tanımladığımızda parametre olarak gelen fonksiyon, bir fonksiyon referansı oluyor. Yani bir lambda expression veya anonymous fonksiyon olabilir.</p><p>🚀Örnekler üzerinden Higher Order fonksiyonlara yakından bakalımm..</p><pre>fun main(){<br><br>    fun myhigherOrderFunction(a:Int, b:Int, operation: (Int, Int) -&gt; Int){<br>        println(operation.invoke(a,b))  // 20<br>    }<br><br>    myhigherOrderFunction(5,4) { number1, number2 -&gt;<br>        number1 * number2<br>    }<br><br>} </pre><p>Yukarıda myhigherOrderFunctionisimli fonksiyonumuz parametre olarak inttipinde a ve bparametrelerini alıyor. Ek olarak tanımda bahsettiğimiz gibi operationisminde <em>fonksiyon referansı</em> almış durumda. Fonksiyon referansı; birinci ve ikinci parametreleriint,geri dönüş tipi ise yine int bu örnek için.</p><p>Fonksiyon kapsamında referansımıza invoke işlevi ile a ve b parametrelerini kullanarak çağırım yaptık. Higher Order fonksiyonumuzun kendisini kullanmak istediğimizde ise beklenen değerleri vererek çarpım işlemini gerçekleştirdik.</p><pre>fun main(){<br>    val myFunction  =fun(a:String,b:String):Int{<br>        return a.length * b.length<br>    }<br>    myHigherOrderFunc(&quot;Marilyn&quot;,&quot;Monroe&quot;,myFunction)<br><br>}<br><br>fun myHigherOrderFunc(nameOne:String, nameTwo:String, parameter:(String,String)-&gt;Int){<br>    println(parameter.invoke(nameOne,nameTwo)) // 42 <br>    // println(parameter(nameOne,nameTwo) // 42 <br><br>} </pre><p>Bu örneğe baktığımızda ise belirtilen string&#39;lerin uzunluklarını alarak çarpım işleminin yapıldığını görüyoruz. Higher Order fonksiyonun kendisine baktığımızda string tipinde iki tane parametre almış durumda. Fonksiyon referansı olarak ise birinci ve ikinci parametre tipleri string , geri dönüş tipi intolan parameterisminde referansımız mevcut.</p><p>👉🏻Higher Order fonksiyona nameOneve nameTwoisminde iki parametre verdik bu örnekte. Kullanıma göre parametre sayısını çoğaltabilir veya hiç yer vermeyebilirsiniz.</p><p>👉🏻Burada dikkat etmemiz gereken asıl nokta kendimiz ayrı bir fonksiyon tanımı yapıp Higher Order fonksiyon çağırımında kullanmış olmamız. Örneğimizde anonymous fonksiyon oluşturulup kullanıldığını görüyoruz.</p><pre>fun main(){<br><br>    myHigherOrderFunction(&quot;Weeknd&quot;){<br>        println(it)<br>    }<br><br>}<br>fun myHigherOrderFunction(a:String,actionNotifier:(String)-&gt;Unit){<br>    actionNotifier.invoke(&quot;Hello Alien!!&quot;)<br>    val nameLength = a.length*a.length<br>    println(nameLength)<br>    actionNotifier.invoke(&quot;See you soon Alien!!&quot;)<br>}<br><br>/* <br>Hello Alien!!<br>36<br>See you soon Alien!!<br>*/</pre><p>Örneğimizdeki Higher Order fonksiyonu stringtipinde aparametresini ve de stringtipinde parametre alan herhangi bir değer döndürmeyen lambda expression işlevini içeriyor. Lambda işlevini iki kez çağırarak belirtilen mesajların yanında string uzunluğunun karesini alma işlemini gerçekleştiriyor.</p><p>🚀Bir sonraki örneğe geçelimm..</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2Fm0Z1LPu6flQDS%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2Fm0Z1LPu6flQDS%2Fgiphy.gif&amp;image=https%3A%2F%2Fmedia4.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExMmY1enZyazN6NTFyamphNmQxaTg4ZzdtYnFuczF2OXZ4Z3phNzlkcSZlcD12MV9naWZzX2dpZklkJmN0PWc%2Fm0Z1LPu6flQDS%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="246" frameborder="0" scrolling="no"><a href="https://medium.com/media/c524d5f57f5cd3f742e7ef52ca4ecff7/href">https://medium.com/media/c524d5f57f5cd3f742e7ef52ca4ecff7/href</a></iframe><pre>fun main(){<br>    higherOrderFunctions(&quot;pomme&quot;,&quot;billie&quot;,::sumHigher)<br><br>}<br><br>fun sumHigher(name1:String,name2:String) = name1.length * name2.length<br><br>fun higherOrderFunctions(a:String,b:String,parameter:(String,String)-&gt;Int){<br>    println(parameter.invoke(a,b)) // 30</pre><p>Bu örneğimizdeki Higher Order fonksiyon görüldüğü üzere stringtipinde iki adet parametre yanında parameter isminde birinci ve ikinci parametreleri string, dönüşü ise inttipinde olan fonksiyon referansı almakta.</p><p>sumHigherfonksiyonu ise string uzunluklarını alarak çarpım işlemi gerçekleştirmekte. Burada dikkat etmemiz gereken nokta sumHigherfonksiyonunun <em>top level decleration</em> olması. ✍Top level decleration, herhangi bir sınıf, nesne veya kod parçasının dışında üst düzey olarak tanımlanan işlevdir. Kullanıma bağlı olarak bir fonksiyon ya da değişken olabilir.</p><p>✍Higher order fonksiyon çağırım esnasında top level decleration erişmek için :: gösterimini yapmış olduk.</p><p><a href="https://kotlinlang.org/docs/lambdas.html">Higher-order functions and lambdas | Kotlin</a></p><p>Umarım faydalı ve açıklayıcı bir yazı olmuştur sizin için. Detaylı bilgi için yukarıdaki linke bakabilir, yazı ile ilgili fikir ve sorularınız için <a href="https://www.linkedin.com/in/amine-aytac/">Linkedin</a> üzerinden benimle iletişime geçebilirsiniz.</p><p>Bir sonraki yazıda görüşmek üzere!</p><p>İyi kodlamalarr..</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2F40KXzKllSl6ve%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2F40KXzKllSl6ve%2Fgiphy.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2F40KXzKllSl6ve%2Fgiphy.gif&amp;key=d04bfffea46d4aeda930ec88cc64b87c&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="175" frameborder="0" scrolling="no"><a href="https://medium.com/media/6523609c1224cb8e114e9941198189c2/href">https://medium.com/media/6523609c1224cb8e114e9941198189c2/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8a42d29cec96" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kotlin | Lambda Expression & Anonymous Functions]]></title>
            <link>https://medium.com/@amineytc_/kotlin-lambda-expression-anonymous-functions-8733a3d7de0e?source=rss-8cadd461f54d------2</link>
            <guid isPermaLink="false">https://medium.com/p/8733a3d7de0e</guid>
            <category><![CDATA[lambda-expressions]]></category>
            <category><![CDATA[anonymous-function]]></category>
            <category><![CDATA[kotlin]]></category>
            <dc:creator><![CDATA[Amine Aytaç]]></dc:creator>
            <pubDate>Mon, 17 Jul 2023 17:42:30 GMT</pubDate>
            <atom:updated>2023-11-05T12:49:28.489Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*sUvnLATPVz1USNVKZXdt3Q.jpeg" /></figure><p>Merhabalar. Bu yazımda function literal olarak da geçen lambda expression ve anonymous fonksiyonlardan bahsedeceğim. İyi okumalarr..</p><h4>👀Lambda Expression</h4><p>Lambda expression’lar aslında çağırılabilir bir fonksiyondur. Yazım olarak süslü parantezler ile çevrilir. İlk süslü parantezden sonra parametrelerin arasına virgül konularak parametreler yazılır. Ardından ok işareti konulur ve expression body si normal fonksiyon gibi yazılır. Aynı zamanda tanımladıktan sonra anlık olarak kullanabiliriz.</p><p>🚀Fonksiyon referans gösterimine bakalımm..</p><p>🔎()-&gt; Int</p><p>Yukarıdaki örnek hiçbir parametre almayan Int tipinde geri dönüş sağlayan fonksiyon anlamı taşımakta.</p><p>🔎(Boolean, Int, String)-&gt;String</p><p>Bu örnek ise birinci parametresi boolean, ikinci parametresi int, üçüncü parametresi string tipinde olan, geri dönüş tipi ise yine string tipinde fonksiyon tanımını ifade eder.</p><p>🚀Şimdi örnekler üzerinden lambda expression inceleyelimm..</p><pre>fun main(){<br><br>    val impactOperation:(String,String)-&gt;Int = {elementOne:String,elementTwo:String-&gt;<br>        elementOne.length*elementTwo.length<br>    }<br><br>    println(impactOperation.invoke(&quot;lara&quot;,&quot;fabian&quot;))<br>}<br><br>// 24 </pre><p>Bu temel örnekte int tipinde geri dönüş değeri olan impactOperation fonksiyonu, verilen string elemanların uzunluklarını alıp çarpma işlemi gerçekleştirmekte.</p><p>🔎impactOperation.invoke(“lara”,”fabian”)</p><p>🔎impactOperation(“lara”,”fabian”)</p><p>Fonksiyon çağırımını <em>invoke</em> <em>işlevi </em>ile gerçekleştirdik örneğimizde. Invoke kullanmadan normal fonksiyon çağırımı ile de aynı işlemi yapabiliriz. Performans açısından herhangi bir farkları olmadığını da belirtmeliyim bu noktada.</p><p>🔎{elementOne:String, elementTwo:String-&gt; }</p><p>🔎{elementOne, elementTwo-&gt; }</p><p>Expression body içinde yer alan isimlendirmeleri tip belirtmeden de kullanabiliriz.</p><p>Dikkat etmemiz gereken bir başka nokta ise fonksiyon içerisinde <em>return</em> ifadesini kullanmamamız.✍<em>Lambda expression’ların son ifadesi return tipi olarak tanımlanır yani return ifadesini yazmamıza gerek yoktur. Ve de return type’ı açık olarak belirtemezler.</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/355/1*oqqHp8Ns5iDJRfbmdLN9cA.png" /></figure><p>Bu örnekte ise lambda expression tek parametreli. Bu yüzden parametre otomatik olarak it diye isimlendirilir. Ve de yine tek parametreli olduğu için ok işareti -&gt; koymaya gerek yoktur.</p><h4>👀Anonymous Functions</h4><p>Anonymous normal fonksiyonlar gibidir. Normal fonksiyonlardan farkı fonksiyon ismi belirtilmeden yazılmalarıdır. ✍<em>Lambda ifadelerden farkları ise dönüş tipinin belirtilmesidir.</em></p><p>✍Anonymous fonksiyonlar single expression veya fonksiyon body si şeklinde de yazılabilirler.</p><p>📌fun (a:Int):Boolean</p><pre>fun main(){<br>    val toplama = fun(x: Int, y: Int): Int {<br>        return x * y<br>    }<br><br>    println(toplama.invoke(12, 8))<br>}<br><br>// 96</pre><p>Örnekte gördüğümüz gibi fonksiyon ismi belirtmeden anonymous oluşturuyoruz. Int tipinde geri dönüşü de belirtilmiş durumda.</p><pre>fun main(){<br>    // single expression örnekleri<br>    val modOne = fun(number1: Int, number2: Int): Int = number1 % number2<br>    val modTwo = fun(number1: Int, number2: Int) = number1 % number2<br>    <br>}</pre><p><a href="https://kotlinlang.org/docs/lambdas.html#lambda-expressions-and-anonymous-functions">Higher-order functions and lambdas | Kotlin</a></p><p>Umarım faydalı bir yazı olmuştur sizin için. Detaylı bilgi için yukarıdaki linke bakabilirsiniz.</p><p>Yazı ile ilgili fikir ve sorularınız için <a href="https://www.linkedin.com/in/amine-aytac/">Linkedin</a> üzerinden benimle iletişime geçebilirsiniz. Bir sonraki yazıda görüşmek üzere!</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2FmP8GermRyOFWV8PQeq%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExajEweGNkcmpqZnliajdmOWZyaWN1bms3ZzdqOWp6OWtvaGU3N3FwOSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw%2FmP8GermRyOFWV8PQeq%2Fgiphy.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2FmP8GermRyOFWV8PQeq%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="435" frameborder="0" scrolling="no"><a href="https://medium.com/media/5e8c9ff60db9c536e3fe5269b3b06670/href">https://medium.com/media/5e8c9ff60db9c536e3fe5269b3b06670/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8733a3d7de0e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kotlin | Extension & Infix Functions]]></title>
            <link>https://medium.com/@amineytc_/kotlin-extension-infix-functions-ac3a090c044a?source=rss-8cadd461f54d------2</link>
            <guid isPermaLink="false">https://medium.com/p/ac3a090c044a</guid>
            <category><![CDATA[extension-functions]]></category>
            <category><![CDATA[infix-function]]></category>
            <category><![CDATA[kotlin]]></category>
            <dc:creator><![CDATA[Amine Aytaç]]></dc:creator>
            <pubDate>Sat, 15 Jul 2023 13:10:48 GMT</pubDate>
            <atom:updated>2023-11-05T12:45:00.292Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3MuN4ve5FLRRn2vaCfQToA.jpeg" /></figure><p>Tekrardan merhabalar herkese. Bu yazımda Extension ve Infix fonksiyonların ne olduğunu ve de temel kullanım şekillerini örnekler üzerinden aktaracağım.</p><h4>👀Extension Fonksiyonlar</h4><p>Kullandığımız bir sınıfa veya veri tipine yeni özellik eklemek istediğimiz, fakat modifiye etmek istemediğimiz durumlarda extension fonksiyon yazarız.</p><p>✍Extension fonksiyonlar statik olarak tutulurlar yani hafızada yer kaplarlar. Statik olarak tutuldukları için de ayrı bir fonksiyon yazılmış gibi davranış gösterirler.</p><p>✍Bir sınıf içerisinde extension fonksiyon yazdığımızda artık sadece o sınıf içerisinden ulaşılabilir duruma gelir bizim için. Ve de sınıfımızı receiver olarak adlandırırız.</p><p>📌fun Type.funcName(parameters):ReturnType</p><p>Şimdi ise örnekler üzerinden extension fonksiyonlara göz gezdirelim.</p><pre>fun main(){<br>    val firstArray= arrayOf(14,15,3,46,10,25)<br>    println(firstArray.myExtensionFuc().toList())<br><br>}<br>fun Array&lt;Int&gt;.myExtensionFuc():Array&lt;Int&gt;{<br><br>    for(i in this.indices) this[i]*=this[i]<br>    return this<br><br>}<br><br>// [196, 225, 9, 2116, 100, 625]</pre><p>Bu örnekte int tipinde elemanlardan oluşan diziye extension fonksiyon yazdık. Fonksiyon bizim için her bir elemanın karesini alıp dizi index güncelliyor ve de geri dönüş olarak diziyi döndürüyor.</p><pre>fun main(){<br>    val firstArray= arrayOf(&quot;bilbo&quot;,&quot;thorin&quot;,&quot;gandalf&quot;,&quot;obliviate&quot;)<br>    println(firstArray.myextensionFunction().toList())<br><br>}<br>fun Array&lt;String&gt;.myextensionFunction(): Array&lt;Int?&gt; {<br><br>    val emptyIntArray = arrayOfNulls&lt;Int&gt;(this.size)<br><br>    this.forEachIndexed { index, element -&gt;<br>        emptyIntArray[index] =  index * element.length<br>    }<br>    <br>    return emptyIntArray<br>}<br><br>// [0, 6, 14, 27]</pre><p>Bu örnekte ise type olarak string array’e extension fonksiyon yazdık. Fonksiyon genel anlamda bizim için her bir string elemanın bulunduğu index numarası ile, string uzunluğunu alarak çarpım işlemi gerçekleştiriyor. Ve bu çarpım işlemi sonucunu bize geri döndürüyor.</p><h4>👀Infix Fonksiyonlar</h4><p>Infix fonksiyonlar bizim daha anlaşılabilir bir şekilde işlemler yapmamızı sağlamasının yanı sıra temelde extension fonksiyonlar ile benzerdir. Ve bir infix fonksiyon kesinlikle extension fonksiyon olmak durumundadır.</p><p>Infix fonksiyonlar hakkında bilmemiz gereken birkaç nokta ise :</p><p>👉🏻Infix fonksiyonlar sadece bir parametre alır.</p><p>👉🏻Infix fonksiyonların parametresi default value alamaz.</p><p>👉🏻Infix fonksiyonlar daha düşük üstünlüğe sahiptir.</p><p>📌infix fun Type.funcName(parameter):ReturnType</p><pre>fun main(){<br>    val firstArray= arrayOf(75,8,10,55,7,14,24)<br>    val number = 5<br>    println(number myInfixFunc firstArray)<br>    <br>}<br>infix fun Int.myInfixFunc(myArray:Array&lt;Int&gt;): ArrayList&lt;Int&gt; {<br><br>    val emptyArrayList: ArrayList&lt;Int&gt; = ArrayList()<br><br>    for(i in myArray) if(i % this == 0) emptyArrayList.add(i)<br>    return emptyArrayList<br>}<br><br>// [75, 10, 55]</pre><p>Int tipindeki değerlere infix fonksiyon yazıldığını görüyoruz bu örnekte. Fonksiyon parametre olarak int array alıp array içerisinde her bir elemanın mod alma işlemini gerçekleştiriyor. Mod işleminin kalansız olması durumunda ise de array içerisindeki eleman yeni bir arraylist içerisine ekleniyor ve dönüş işlemi sağlanıyor.</p><ul><li><a href="https://kotlinlang.org/docs/extensions.html">Extensions | Kotlin</a></li><li><a href="https://kotlinlang.org/docs/functions.html">Functions | Kotlin</a></li></ul><p>Umarım faydalı bir yazı olmuştur sizin için. Detaylı bilgi için yukarıdaki linklere bakabilirsiniz.</p><p>Yazı ile ilgili fikir ve sorularınız için <a href="https://www.linkedin.com/in/amine-aytac/">Linkedin</a> üzerinden benimle iletişime geçebilirsiniz. Bir sonraki yazıda görüşmek üzere!</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2FmP8GermRyOFWV8PQeq%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2FmP8GermRyOFWV8PQeq%2Fgiphy.gif&amp;image=https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2Fv1.Y2lkPTc5MGI3NjExY3hrb3VhOXl6bW1oY2xiYnI0a3F5cWw2dm1tdHM0dDV4djZvMmttZSZlcD12MV9naWZzX2dpZklkJmN0PWc%2FmP8GermRyOFWV8PQeq%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="435" frameborder="0" scrolling="no"><a href="https://medium.com/media/deeb2ab39735ad9a4e511d66045ce267/href">https://medium.com/media/deeb2ab39735ad9a4e511d66045ce267/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ac3a090c044a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kotlin | Break, Continue, Return & Labelling Review on forEach]]></title>
            <link>https://medium.com/@amineytc_/foreach-%C3%BCzerinde-break-continue-return-ve-labeling-i%CC%87ncelemesi-82c8e195db7b?source=rss-8cadd461f54d------2</link>
            <guid isPermaLink="false">https://medium.com/p/82c8e195db7b</guid>
            <category><![CDATA[continue]]></category>
            <category><![CDATA[break]]></category>
            <category><![CDATA[labeling]]></category>
            <category><![CDATA[return]]></category>
            <category><![CDATA[foreach]]></category>
            <dc:creator><![CDATA[Amine Aytaç]]></dc:creator>
            <pubDate>Tue, 20 Jun 2023 08:27:20 GMT</pubDate>
            <atom:updated>2024-06-29T16:20:36.094Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/480/0*P3f9ef5CopiwAQdc" /></figure><p>Merhabalar, bu yazımda forEach işlevi üzerinde örnekler vererek break, continue, return ve labelling ifadelerini inceleyeceğim. Keyifli okumalar.</p><p>İlk olarak kullanacağımız ifadeleri hatırlayalım.</p><blockquote><strong><em>Break:</em> </strong><em>Döngü içerisinde </em>break<em> ile karşılaştığımız anda içinde bulunduğumuz döngü sonlanır. Eğer iç içe iki tane döngü söz konusu ve de en içteki döngüde </em>break<em> ifadesi var ise içteki döngü sonlandırılır. Kod parçası olması durumunda işleme devam edilir.</em></blockquote><blockquote><strong><em>Continue: </em></strong><em>Döngü içerisinde kendisinden sonraki kod parçalarının atlanmasını ve bulunduğu döngünün en başına giderek bir sonraki adımdan devam edilmesini sağlar.</em></blockquote><blockquote><strong><em>Return: </em></strong><em>Döngü içinde return ifadesi yer alıyorsa kendisinden sonra kod parçaları olsa bile döngü sonlandırılır.</em></blockquote><blockquote><strong><em>Labeling: </em></strong><em>Labelling için işlem parçacığının etiketlenmesi diyebiliriz. Döngü ifadesine veya bloğa etiketleme yapabilirsiniz.</em></blockquote><p>İncelemeye forEach işlevini örneklendirerek başlayalım.</p><pre>intArrayOf(41,36,89,43,12,50,99).forEach {it-&gt;<br>        println(it)<br>}</pre><p>Yukarıda forEach temel kullanımı yer almakta. forEach, <em>döngü yapısını oluşturmadan elemanlar üzerinde işlemler yapabilmemizi sağlayan bir işlevdir. For veya while gibi bir döngü ifadesi değildir.</em> Aynı zamanda forEach <strong>higher-order bir fonksiyondur.</strong></p><h4>Break &amp; Continue</h4><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*Tcd42KRhTK4oJUJO-wwBxA.png" /><figcaption>forEach içerisinde break ve continue kullanımı</figcaption></figure><p>forEach içerisinde<em> </em>break — continue kullanmak istediğimizde <em>hata alırız</em>.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2FitTf5594jwVDW%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2FitTf5594jwVDW%2Fgiphy.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2FitTf5594jwVDW%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="244" frameborder="0" scrolling="no"><a href="https://medium.com/media/3609c923ea4740d8fc62cd7574cf2ee9/href">https://medium.com/media/3609c923ea4740d8fc62cd7574cf2ee9/href</a></iframe><p><em>Bunun temel sebebi break-continue ikilisinin döngü yapıları ile kullanılması gerektiğidir.</em> forEach içerisinde break ve continue yerine aynı etkiyi yaratan alternatif çözümler kullanabiliriz.</p><h4>Return</h4><pre>val arrayOne=intArrayOf(56,74,32,14,78,96,65,52)<br>arrayOne.forEach {m-&gt;<br>     if(m&gt;50 &amp;&amp; m&lt;75) {<br>         println(m)<br>         return<br>     }<br>}<br><br>// 56</pre><p>Yukarıdaki örnekte arrayOne dizisi elemanları sırasıyla if koşulunu sağlarsa yazdırılmaktadır. Kod parçası çalıştırıldığında ilk olarak m değeri 56 olacak ve belirtilen aralığı da sağladı için yazma işlemi gerçekleştirilecektir. if koşul aralığından çıkıldığında <em>return</em> ifadesi ile karşılaştığımız için <em>forEach</em> çalışması sonlandırılacaktır.</p><pre>intArrayOf(41,36,89,43,12).forEach {element-&gt;<br>        println(element)<br>        intArrayOf(9,8,7,6).forEach {a-&gt;<br>            if(a&gt;7) println(a+a)<br>        }<br>        return<br>}<br><br>/*<br>41<br>18<br>16<br>*/</pre><p>Bu örnekte ise iç içe iki tane <em>forEach</em> yer almakta. İlk <em>forEach</em> çalıştığında dizinin ilk elemanını yazdırma işlemi gerçekleşmiş olacak. İkinci <em>forEach</em> baktığımızda dizi elemanlarının üzerinden sırasıyla koşul kontrol edilecek. Koşul sağlanması durumunda ise de toplama işlemi yapılıp yazdırılacaktır. İkinci <em>forEach</em> bloğunda tüm elemanlar kontrol edilip bloktan çıkıldığında <em>return</em> ile karşılaştığımız kod blokları tamamen sonlandırılacaktır.</p><h4>Labelling</h4><pre>intArrayOf(81,42,35,84,95).forEach expression@{<br>        if(it&gt;50) return@expression<br>        println(it)<br>}<br><br>/*<br>42<br>35<br>*/</pre><p><em>expression@ yazarak etiketleme işlemi yapıyoruz. Etiket ismini farklı bir isim de verebilirsiniz.</em></p><p>return@expression bizim için o adımı ve sonrasını atla anlamı taşıyor. <em>Aslında continue’nun yaptığı işlevi sağlıyor bizim için.</em> Sırasıyla elemanlara bakarak 50 sayısından büyük olma koşulu sağlandığında diziye tekrar gidip diğer elemanları incelemeye devam ediyor.</p><pre>run breaking@ {<br>        intArrayOf(42,81,35,84,95).forEach {a-&gt;<br>            if(a&gt;50) return@breaking<br>            println(a)<br>        }<br>}<br><br>println(&quot;here&quot;)<br><br>/* <br>42<br>here<br>*/</pre><p><em>Döngü sonlandırıp döngü dışındaki bir ifadeye dönmek istiyorsak run fonksiyonu yazarak bunu sağlayabiliriz.</em></p><p>Bu örnekte dizi elemanları sırasıyla incelenip elemanın 50 sayısından büyük olma koşulunu sağladığında yazdığımız run fonksiyonu ile döngüyü sonlandırıp döngü dışına çıkıyoruz.</p><pre>val arrayOne=intArrayOf(8,10,79,98,19)<br>run breaking@{<br>    arrayOne.forEach {m-&gt;<br>        intArrayOf(2,3,4).forEach expression@{n-&gt;<br>           if(m&gt;50 ){<br>              return@breaking<br>           }else if(n&gt;2){<br>                 return@expression<br>           }<br>           println(&quot;m:$m * n:$n =  ${m*n}&quot;)<br>        }<br>    }<br>}<br>println(&quot;here&quot;)<br><br>/*<br>m:8 * n:2 =  16<br>m:10 * n:2 =  20<br>here<br>*/</pre><p>İç içe iki tane forEach kullanarak labeling incelemesi yapıyoruz bu örnekte. arrayOne dizi elemanının 50 den büyük olması şartı sağlandığında döngü tamamen sonlanacaktır. İç kısımda yer alan dizi elemanının da 2 sayısından büyük olması durumda o adım ve devamında yer alan kod satırları atlanacaktır.</p><pre>val arrayOne=intArrayOf(120,79,98,19,56)<br>run breaking@{<br>    intArrayOf(25,61,8,37,10,72,18,16,5,12).forEach {a-&gt;<br>      run one@{<br>        intArrayOf(100,488,675,288).forEach {b-&gt;<br>         run two@ {<br>             arrayOne.forEach {c-&gt;<br>                  if(c&gt;b) return@two<br>             }<br>         }<br>         if(b%a==0) println(&quot;b:$b mod a:$a = 0&quot;) else if (b&lt;500) return@one<br>        }<br>        println(&quot;you are here&quot;)<br>      }<br>      if(a&gt;70) return@breaking<br>    }<br>}<br><br><br>/* <br>b:100 mod a:25 = 0<br>b:100 mod a:10 = 0<br>*/</pre><p>Bu örnekte ise iç içe üç tane forEach işlevi kullanıyoruz. Koşulların sağlanması durumlarına göre işlevler sonlandırılıyor.</p><p><em>Debug modda kodları inceleyerek çalışma mantığını daha iyi bir şekilde anlayabilirsiniz.</em></p><p><a href="https://kotlinlang.org/docs/returns.html#return-to-labels">Returns and jumps | Kotlin</a></p><p>Umarım faydalı bir yazı olmuştur sizin için , bir sonraki yazıda görüşmek üzere!</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fgiphy.com%2Fembed%2FJmhXwlk96NQD8TxSCK%2Ftwitter%2Fiframe&amp;display_name=Giphy&amp;url=https%3A%2F%2Fmedia.giphy.com%2Fmedia%2FJmhXwlk96NQD8TxSCK%2Fgiphy.gif&amp;image=https%3A%2F%2Fi.giphy.com%2Fmedia%2FJmhXwlk96NQD8TxSCK%2Fgiphy.gif&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=giphy" width="435" height="244" frameborder="0" scrolling="no"><a href="https://medium.com/media/483dc3a922cbf6491f2024baa9e2f7bf/href">https://medium.com/media/483dc3a922cbf6491f2024baa9e2f7bf/href</a></iframe><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=82c8e195db7b" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>