반응형

1. 빌드세팅에서 그림과같이 체크한부분을 확인하여 맞춰준다.

2. 플레이어세팅에 XR Settings를 열고 위와같이 세팅한다.

 

3. Publishing Settings / Capablilities의 SpatialPerception을 체크한다.

 

4. MRTK에서 제공하는 샘플신을 열고 빌드를 하면 해당폴더에 Visual Studio Project가 생성이되는데 실행하면 비쥬얼 스튜디오가 열린다. (별도 설치 필요)

 

5. 아까 유니티 빌드세팅에서 맞춰놓은대로 비쥬얼 스튜디오도 그림처럼 맞춘다.

 

6. 속성을 눌러 들어간다.

 

7. 디버깅 탭을 누르고 컴퓨터 이름을 맞춰주는데 이때 이름은 홀로렌즈의 이름을 넣어주어야 한다. 홀로렌즈이름은 홀로렌즈 홈에서 /세팅/시스템 순서로 들어가면 확인할 수 있다.

 

8. 상단의 빌드/ 솔루션배포를 누르면 홀로렌즈에 앱을 빌드 할 수 있다. 여기서 만양 홀로렌즈에 배포가 되지 않고 핀번호를 입력하라고 나오면, 홀로렌즈 홈에서 세팅/업데이트/개발자모드 로 들어가서 페어링 버튼을 누르면 기기의 페어링번호가 뜨고 그 번호를 넣어주면 된다.

 

 

**2019.1.14f1일 경우 솔루션대상을 변경해주어야 합니다. 마찬가지로 비쥬얼 스튜디오 2019버전을 사용 할 경우 프로젝트/솔루션 대상 변경을 누르고 

확인을 눌러주변 홀로렌즈로 빌드를 할 수 있습니다.

반응형
반응형

1. 정보 :

 

성수동에 위치한 할아버지공장

넓은 공간과 맛있는 음식이 마음을 사로잡는다.

1층, 2층, 3층 공간으로 기존 공장을 개조한 카페레스토랑으로 한번 가보면 또 가고싶은 그런 곳이다.

사이트

20200629일자 메뉴판 정복메뉴 밑줄

블로그 검색해보고 갔는데 메뉴가 달라진걸 보니 수시로 바뀌는듯 하다.

대림창고를 하던 사장이 대림창고를 처분하고 다시 시작한 곳이라고 하는데 홍동희작가님을 검색해봐야겠다.

 

2. 위치

 

3. 별점

반응형

'맛집' 카테고리의 다른 글

스물다섯스물하나 촬영지  (0) 2022.04.03
반응형

2016/01/19 - [unity C#] - [Unity] GUI Infinity Scroll List 무한 리스트 구현 Json 

 

[Unity] GUI Infinity Scroll List 무한 리스트 구현 Json

어떻게 보면 간단한 구현 일 수도 있겠지만 난 어려웠다. ㅠㅠ 그래서 다시 정리하는 차원에서 포스팅 해본다. 먼저 간략하게 요약해보자면… Unity의 기본제공되는 GUI를 사용, 데이터 형태는 Json형태로 만들어..

knightk.tistory.com

이미지가 깨져서 다시 올려봅니다.

 

Hierarchy 구성

Hierarchy
리스트 요소가 될 Item은 Image와 Text 정도만으로 구성

스크립트 구성

스크립트 구성

 

ManagerHandler.cs

using UnityEngine;

public class ManagerHandler : MonoBehaviour {
    public InfiniteScroll infiniteScroll;
    void Start () {
        Application.targetFrameRate = 60;
        initList ();
    }

    void initList () {
        infiniteScroll.ListStart ();
    }
}

 

ModelHandler.cs

using System.Collections;
using System.Collections.Generic;
using LitJson;
using UnityEngine;

public class ModelHandler : MonoBehaviour {
    private JsonData jsonData;
    public List<DataVO> List;
    string jsonString () {
        TextAsset t = (TextAsset) Resources.Load ("data", typeof (TextAsset));
        return t.text;
    }

    void Awake () {
        jsonData = JsonMapper.ToObject (jsonString ());
        parsing ();
    }

    void parsing () {
        for (int i = 0; i < jsonData["music"].Count; i++) {

            ListModel.Instance.dataVO.SongTitle = (string) jsonData["music"][i]["songtitle"];
            ListModel.Instance.dataVO.Singer = (string) jsonData["music"][i]["singer"];
            ListModel.Instance.dataVO.Color = hexToColor ((string) jsonData["music"][i]["color"]);
            ListModel.Instance.dataVO.Genre = (string) jsonData["music"][i]["genre"];
            ListModel.Instance.dataVO.PlayTime = float.Parse ((string) jsonData["music"][i]["playtime"]);

            ListModel.Instance.MusicList.Add (ListModel.Instance.dataVO);
        }
    }

    static Color hexToColor (string hex) {
        hex = hex.Replace ("0x", "");
        hex = hex.Replace ("#", "");
        byte a = 255;
        byte r = byte.Parse (hex.Substring (0, 2), System.Globalization.NumberStyles.HexNumber);
        byte g = byte.Parse (hex.Substring (2, 2), System.Globalization.NumberStyles.HexNumber);
        byte b = byte.Parse (hex.Substring (4, 2), System.Globalization.NumberStyles.HexNumber);
        if (hex.Length == 8) {
            a = byte.Parse (hex.Substring (6, 2), System.Globalization.NumberStyles.HexNumber);
        }
        return new Color32 (r, g, b, a);
    }
}

 

ListModel.cs

using System;
using System.Collections.Generic;
using UnityEngine;

[Serializable]
public struct DataVO {
    public string SongTitle;
    public string Singer;
    public Color32 Color;
    public string Genre;
    public float PlayTime;
}

public class ListModel : MonoBehaviour {
    private static ListModel _instance = null;
    public DataVO dataVO;
    public List<DataVO> MusicList = new List<DataVO> ();
    public static ListModel Instance {
        get {
            if (_instance == null) {
                _instance = (GameObject.Find ("Manager")).AddComponent<ListModel> ();
            }
            return _instance;
        }
    }

}

 

InfiniteScroll.cs

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class InfiniteScroll : MonoBehaviour {
    [SerializeField]
    private RectTransform m_ItemBase;
    [SerializeField]
    int m_instantiateItemCount = 9;
    [SerializeField]
    float m_itemWidth = 1080;
    [SerializeField]
    float m_itemHeight = 200;
    [SerializeField]
    float gap = 10;
    public Direction direction;
    [System.NonSerialized]
    public List<RectTransform> m_itemList = new List<RectTransform> ();
    protected float m_diffPreFramePosition = 0;
    [SerializeField]
    private int m_currentItemNo = 0;
    public ScrollRect scrollRect;
    public List<DataVO> listData;
    public enum Direction {
        Vertical,
        Horizontal,
    }

    // cache component
    public RectTransform m_Content;

    private float AnchoredPosition {
        get {
            return (direction == Direction.Vertical) ?
                -m_Content.anchoredPosition.y :
                m_Content.anchoredPosition.x;
        }
    }
    private float ItemScale {
        get {
            return (direction == Direction.Vertical) ?
                m_itemHeight :
                m_itemWidth;
        }
    }

    void Start () {
        m_itemWidth = Screen.width;
        m_itemHeight = Screen.height / 12;
    }

    public void ListStart () {
        listData = ListModel.Instance.MusicList;

        if (listData.Count < m_instantiateItemCount) {
            m_instantiateItemCount = listData.Count;
        } else {
            m_instantiateItemCount = (direction == Direction.Vertical) ?
                Mathf.RoundToInt (Screen.height / ItemScale) + 3 :
                Mathf.RoundToInt (Screen.width / ItemScale) + 3;
        }

        // create items
        scrollRect.horizontal = direction == Direction.Horizontal;
        scrollRect.vertical = direction == Direction.Vertical;

        if (direction == Direction.Vertical) {
            m_Content.SetSizeWithCurrentAnchors (RectTransform.Axis.Vertical, (ItemScale + gap) * (listData.Count - 1) + gap);
            m_Content.SetSizeWithCurrentAnchors (RectTransform.Axis.Horizontal, m_itemWidth + gap * 2);
        } else {
            m_Content.SetSizeWithCurrentAnchors (RectTransform.Axis.Horizontal, (ItemScale + gap) * (listData.Count - 1) + gap);
            m_Content.SetSizeWithCurrentAnchors (RectTransform.Axis.Vertical, m_itemHeight + gap * 2);
        }

        scrollRect.onValueChanged.AddListener (valueChange);
        Debug.Log (listData.Count);
        m_ItemBase.gameObject.SetActive (false);
        for (int i = 0; i < m_instantiateItemCount; i++) {
            var item = GameObject.Instantiate (m_ItemBase) as RectTransform;
            item.SetParent (transform, false);
            item.name = i.ToString ();

            if (direction == Direction.Vertical) {
                item.SetSizeWithCurrentAnchors (RectTransform.Axis.Horizontal, m_itemWidth - gap * 2);
                item.SetSizeWithCurrentAnchors (RectTransform.Axis.Vertical, m_itemHeight);
            } else {
                item.SetSizeWithCurrentAnchors (RectTransform.Axis.Horizontal, m_itemWidth);
                item.SetSizeWithCurrentAnchors (RectTransform.Axis.Vertical, m_itemHeight);
            }

            item.anchoredPosition =
                (direction == Direction.Vertical) ?
                new Vector2 (gap, -gap - (ItemScale + gap) * i) :
                new Vector2 ((ItemScale + gap) * i + gap, -gap);
            m_itemList.Add (item);

            item.gameObject.SetActive (true);
            item.GetComponent<Item> ().UpdateItem (i);
        }
    }

    private void valueChange (Vector2 _pos) {
        // scroll up, item attach bottom  or  right
        while (AnchoredPosition - m_diffPreFramePosition < -(ItemScale + gap) * 2) {
            m_diffPreFramePosition -= (ItemScale + gap);

            var item = m_itemList[0];
            m_itemList.RemoveAt (0);
            m_itemList.Add (item);

            var pos = (ItemScale + gap) * m_instantiateItemCount + (ItemScale + gap) * m_currentItemNo;
            item.anchoredPosition = (direction == Direction.Vertical) ? new Vector2 (gap, -pos - gap) : new Vector2 (pos + gap, -gap);

            m_currentItemNo++;

            if (m_currentItemNo + m_instantiateItemCount < listData.Count) {
                item.GetComponent<Item> ().UpdateItem (m_currentItemNo + m_instantiateItemCount);
            } else {
                item.GetComponent<Item> ().UpdateItem (-100);
            }
        }

        // scroll down, item attach top  or  left
        while (AnchoredPosition - m_diffPreFramePosition > 0) {
            m_diffPreFramePosition += (ItemScale + gap);

            var itemListLastCount = m_instantiateItemCount - 1;
            var item = m_itemList[itemListLastCount];
            m_itemList.RemoveAt (itemListLastCount);
            m_itemList.Insert (0, item);

            m_currentItemNo--;

            var pos = (ItemScale + gap) * m_currentItemNo + gap;
            item.anchoredPosition = (direction == Direction.Vertical) ? new Vector2 (gap, -pos) : new Vector2 (pos, -gap);

            if (m_currentItemNo > -1) {
                item.GetComponent<Item> ().UpdateItem (m_currentItemNo);
            } else {
                item.GetComponent<Item> ().UpdateItem (-100);
            }
        }
    }
}

 

Item.cs

using UnityEngine;
using UnityEngine.UI;

public class Item : MonoBehaviour {
    public Text m_Text;
    public Image m_Image;
    public void UpdateItem (int count) {
        if (count == -100) {
            m_Text.gameObject.SetActive (false);
            m_Image.gameObject.SetActive (false);
        } else {
            m_Text.gameObject.SetActive (true);
            m_Image.gameObject.SetActive (true);
            m_Text.text = count + 1 + " - " + Screen.width + " x " + Screen.height;
            m_Image.color = ListModel.Instance.MusicList[count].Color;
        }
    }
}

 

Manager 오브젝트에 ManagerHandler.cs / ModelHandler.cs / ListModel.cs 붙여줍니다.

Manager Object

ScrollView를 만들어 다음과같이 세팅해줍니다.

ScrollRect

InfinityContent 오브젝트에 InfinityScroll.cs 를 붙여주고

ScrollRect항목에 위에서 설정한 ScrollRect를 드래그앤 드랍으로 넣어줍니다.

Content항목에 InfinityContent오브젝트를 끌어넣어 연결해줍니다.

InfinityScroll.cs 붙이기

 

Item 오브젝트에 Item.cs를 붙여주고 위에 InfinityScroll 인스펙터에 ItemBase에 드래그앤 드랍으로 넣어줍니다.

Item인스펙터의 Text와 Image를 해당 오브젝트로 연결시켜줍니다.

Item.cs 붙이기

 

data.txt 파일 생성

Resources폴더에 data.txt파일만들어 아래와 같이 데이터를 넣어줍니다. 아래 데이터는 테스트 하기 위해 임의로 생성한 것이고 자신의 리스트에 맞게 수정해서 사용하면 됩니다.

{
  "music":[
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "f98181",
      "genre" : "rock",
      "playtime" : "0"
    },
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "f981bc",
      "genre" : "rock",
      "playtime" : "0"
    }, 
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "f881f9",
      "genre" : "rock",
      "playtime" : "0"
    },
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "d081f9",
      "genre" : "rock",
      "playtime" : "0"
    }, 
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "ab81f9",
      "genre" : "rock",
      "playtime" : "0"
    },
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "8c81f9",
      "genre" : "rock",
      "playtime" : "0"
    }, 
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "8192f9",
      "genre" : "rock",
      "playtime" : "0"
    },
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "81a8f9",
      "genre" : "rock",
      "playtime" : "0"
    }, 
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "81c8f9",
      "genre" : "rock",
      "playtime" : "0"
    },
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "81e4f9",
      "genre" : "rock",
      "playtime" : "0"
    }, 
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "81f9e4",
      "genre" : "rock",
      "playtime" : "0"
    },
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "81f9c5",
      "genre" : "rock",
      "playtime" : "0"
    }, 
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "81f9a3",
      "genre" : "rock",
      "playtime" : "0"
    },
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "81f989",
      "genre" : "rock",
      "playtime" : "0"
    }, 
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "a0f981",
      "genre" : "rock",
      "playtime" : "0"
    },
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "c2f981",
      "genre" : "rock",
      "playtime" : "0"
    }, 
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "e9f981",
      "genre" : "rock",
      "playtime" : "0"
    },
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "f9e981",
      "genre" : "rock",
      "playtime" : "0"
    }, 
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "f9cd81",
      "genre" : "rock",
      "playtime" : "0"
    },
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "f9b181",
      "genre" : "rock",
      "playtime" : "0"
    }, 
    {
      "songtitle" : "Love Will Show You Everything",
      "singer" : "Various Artists",
      "color" : "f99781",
      "genre" : "rock",
      "playtime" : "0"
    }
  ]
}

 

실행화면

실행화면

 

반응형
반응형

[진행과정]

1. 아두이노에 HC-06블루투스 모듈 설치

2. 아두이노 세팅 및 코딩

3. 유니티프로젝트 생성 및 세팅 (

4. 안드로이드 빌드 및 블루투스 연결

 

요렇게 진행합니다.

 

1. 아두이노에 HC-06모듈 및 마그네틱 센서 설치

HC-06 : 디지털인풋 2/3번/GND/5V 에 연결.

마그네틱 센서 : 디지털인풋 8번/GND에 연결.

hc-06 모듈 및 마그네틱센서 설치

참조1

 

[아두이노 - 블루투스 연동]

안녕하세요!! 이번 포스팅은 아두이노에서 블루투스 연동을 통해 앱과 통신하는 방법을 알아보겠습니다. * ...

blog.naver.com

참조2

 

[Unity]04.아두이노 사용하기 - Blutooth로 채팅하기

안녕하세요 유랑입니다. 오늘은 아두이노와 유니티 통신하는 방법에 대해서 알아보겠습니다. 통신방법은 블루투스를 사용하겠습니다^^ 1. 아두이노와 유니티로 채팅하기 유니티에서 Android 프로젝트에서 디바이스..

you-rang.tistory.com

2. 아두이노 세팅 및 코딩

먼저 아두이노사이트에 가서 아두이노를 설치해 줍니다.

아두이노 프로그램 다운로드

아두이노와 PC를 USB로 연결 한 후 아래 그림처럼 순서대로 보드와 포트를 자신에 맞는 것으로 선택해 줍니다.

아두이노 보드/포트 설정

블루투스 모듈을 슬레이브로변경하기 위해,시리얼 모니터창을 열어 아래 명령어를  입력해줍니다.

AT+ROLE=S

참고

 

HC-06 블루투스모듈 설정 변경하기! (마스터에서 슬레이브, 슬레이브에서 마스터로, HC-06자가진단하기!)

안녕하세요 메카솔루션입니다. 이번에는 HC-06의 마스터와 슬레이브를 수정하는방법과, 그리고 간단하게 ...

blog.naver.com

시리얼 모니터창에서 “AT”라고입력하여 OK가 반환되면,블루투스 모듈 연결이 잘 된 것입니다.

이후,AT+NAME이름을 입력하면 블루투스 모듈 이름을 설정할 수 있습니다.(AT+NAME000입력 시,000으로이름 설정)

그리고 AT+PIN핀번호 4자리를 입력하면 블루투스 연결 시 비밀번호를 설정할 수 있습니다.

마지막으로 AT+BAUD4 을 입력하여 OK9600이 반환되는 것을 확인합니다.(통신 속도 설정)

참고

 

[아두이노 - 블루투스 연동]

안녕하세요!! 이번 포스팅은 아두이노에서 블루투스 연동을 통해 앱과 통신하는 방법을 알아보겠습니다. * ...

blog.naver.com

모두 설정되었다면 아두이노에 코딩작업을 해줍니다.

#include<SoftwareSerial.h>

SoftwareSerial BTSerial (3, 2); //Connect HC-06. Use your (TX, RX) settings

int val;
int tempVal;

void setup () {
  Serial.begin (9600);
  BTSerial.begin (9600); // set the data rate for the BT port
  pinMode (8, INPUT_PULLUP);
}

void loop () {
  //switch value update
  val = digitalRead (8);

  // BT –> Data –> Serial
  if (BTSerial.available ()) {
    Serial.println ("BT available");
    Serial.write (BTSerial.read ());
  }

  if (val == HIGH) {
    if (val != tempVal) {
      tempVal = val;
      BTSerial.println ("off");
      // Do Something

    }
  } else {
    if (val != tempVal) {
      tempVal = val;
      BTSerial.println ("on");
      // Do Something

    }
  }
  delay (100);
}

코드를 대략 요약하자면 마그네틱센서가 붙으면 "on", 떨어지면 "off"라는 스티링을 블루투스 시리얼로 보내는 동작을 합니다.

찾아본 바로는 BTSerial.write("on"); 요렇게 하라고 되어있었는데 전혀 아무런 신호가 보내지지 않아서 저렇게 바꿔보니 잘되더군요.

코딩작업을 마쳤으면 두번째 아이콘을 눌러 아두이노에 업로드를 합니다.

 

3. 유니티프로젝트 생성 및 세팅

적당한 이름으로 새로운 프로젝트를 만들고 아래 파일을 다운받아 임포트 시켜줍니다.

ArduinoBluetooth.unitypackage
1.23MB

Build Settings / Player Settings… 를 열어 Other Settings를 다음과 같이 설정합니다. 

Bundle Identifier 는 똑같지 않아도 상관없으며ApiCompatibility Level* 이부분이 .Net4.x 로 선택해주어야 합니다.

안드로이드로 타겟플랫폼을 변경해주고

새로운 Scene을 만들고 Project탭의Assets/ArduinoBluetooth/Demo/Prefab폴더로 이동하여

__Manager파일을 Hierarchy에 끌어 넣습니다.

 

숫자 "0"번 키로 아래 GUI를 끄고 켤수 있습니다.

 

__Manager를 클릭해보면 Manager.cs라는 스크립트파일이 붙어있습니다.

Manager.cs를 열어서 deviceName 을 위에 아두이노 설정시 변경했던 블루투스 이름과 동일하게 수정해줍니다.

예)AT+NAMEHC-06

OnDoorOpenOnDoorClose위 두가지 이벤트가 있고외부 클래스에서 다음과 같이 사용할 수 있습니다.

public Manager _manager;

void Start(){
    _manager.onDoorOpen.AddListener(OnDoorOpen);
    _manager.onDoorClose.AddListener(OnDoorClose);
}

void OnDoorOpen(){
    //문이 열렸을 때
}
void OnDoorOpen(){
    //문이 닫혔을 때
}
…

 

연결 테스트영상입니다.

 

반응형
반응형

테스트 하기 위해 새로운 프로젝트를 만들고 

main.dart 코드를 다음과 같이 세팅한다.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'ListViews',
      theme: ThemeData(
        primarySwatch: Colors.teal,
      ),
      home: Scaffold(
        appBar: AppBar(title: Text('ListViews')),
        body: BodyLayout(),
      ),
    );
  }
}

class BodyLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return _myListView(context);
  }
}

// replace this function with the code in the examples
Widget _myListView(BuildContext context) {
  return ListView();
}

 

ListView

설정메뉴나 고정적인 메뉴 항목일 경우 유용하게 사용할 수 있음.

리스트 선이 있는 경우

Widget _myListView(BuildContext context) {
  return ListView(
    children: ListTile.divideTiles(
      context: context,
      tiles: [
        ListTile(
          title: Text('Sun'),
        ),
        ListTile(
          title: Text('Moon'),
        ),
        ListTile(
          title: Text('Star'),
        ),
      ],
    ).toList(),
  );
}

 

리스트 선이 없는 경우

Widget _myListView(BuildContext context) {
  return ListView(
    children: <Widget>[
      ListTile(
        title: Text('Sun'),
      ),
      ListTile(
        title: Text('Moon'),
      ),
      ListTile(
        title: Text('Star'),
      ),
    ],
  );
}

 

Dynamic ListView

데이터를 가져와 동적으로 리스트를 생성하는 방식

Widget _myListView(BuildContext context) {

      // backing data
  final europeanCountries = ['Albania', 'Andorra', 'Armenia', 'Austria', 
    'Azerbaijan', 'Belarus', 'Belgium', 'Bosnia and Herzegovina', 'Bulgaria',
    'Croatia', 'Cyprus', 'Czech Republic', 'Denmark', 'Estonia', 'Finland',
    'France', 'Georgia', 'Germany', 'Greece', 'Hungary', 'Iceland', 'Ireland',
    'Italy', 'Kazakhstan', 'Kosovo', 'Latvia', 'Liechtenstein', 'Lithuania',
    'Luxembourg', 'Macedonia', 'Malta', 'Moldova', 'Monaco', 'Montenegro',
    'Netherlands', 'Norway', 'Poland', 'Portugal', 'Romania', 'Russia',
    'San Marino', 'Serbia', 'Slovakia', 'Slovenia', 'Spain', 'Sweden', 
    'Switzerland', 'Turkey', 'Ukraine', 'United Kingdom', 'Vatican City'];

  return ListView.separated(
    itemCount: europeanCountries.length,
    itemBuilder: (context, index) {
      return ListTile(
        title: Text(europeanCountries[index]),
      );
    },
    separatorBuilder: (context, index) {
      return Divider();
    },
  );
}

데이터를 만들어 생성하는 방식

리턴쪽에 ListView.separated로 설정해서 separatorBuilder를 넣어주면 구분선을 사용할 수 있다.

구분선이 없이 사용하려면 ListView.builder로 리턴시키면 된다.

 

Infinite List

말그대로 무한 스크롤... 그냥 되는거다 사용하는 방법은 좀더 연구해봐야겠지만...

Widget _myListView(BuildContext context) {
  return ListView.builder(
    itemBuilder: (context, index) {
      return ListTile(
        title: Text('row $index'),
      );
    },
  );
}

구분선을 추가하려면

Widget _myListView(BuildContext context) {
  return ListView.separated(
    itemCount: 1000,
    itemBuilder: (context, index) {
      return ListTile(
        title: Text('row $index'),
      );
    },
    separatorBuilder: (context, index) {
      return Divider();
    },
  );
}

 

Horizontal ListView

가로스크롤 구현이다.

Widget _myListView(BuildContext context) {
  return ListView.builder(
    scrollDirection: Axis.horizontal,
    itemBuilder: (context, index) {
      return Container(
        margin: const EdgeInsets.symmetric(horizontal: 1.0),
        color: Color(0xFFEEEEEE),
        child: Text('$index'),
        width: 50.0,
      );
    },
  );
}

가로 스크롤 리스트

 

리스트 타일 커스터마이즈

플루터는 기본적으로 제공되는 아이콘이 무척 많은듯 하다. 사용하는 방법도 간단함.

Widget _myListView(BuildContext context) {
  return ListView(
    children: ListTile.divideTiles(
      context: context,
      tiles: [
        ListTile(
          leading: Icon(Icons.wb_sunny),
          title: Text('Sun'),
          trailing: Icon(Icons.keyboard_arrow_right),
        ),
        ListTile(
          leading: Icon(Icons.brightness_3),
          title: Text('Moon'),
          trailing: Icon(Icons.keyboard_arrow_right),
        ),
        ListTile(
          leading: Icon(Icons.star),
          title: Text('Star'),
          trailing: Icon(Icons.keyboard_arrow_right),
        ),
      ],
    ).toList(),
  );
}

다양한 아이콘 적용

 

원하는 이미지를 리스트에 넣기

아래코드로 먼저 바꿔준 후,

Widget _myListView(BuildContext context) {
  return ListView(
    children: ListTile.divideTiles(
      context: context,
      tiles: [
        ListTile(
          leading: CircleAvatar(
            backgroundImage: AssetImage('assets/sun.jpg'),
          ),
          title: Text('Sun'),
          trailing: Icon(Icons.keyboard_arrow_right),
        ),
        ListTile(
          leading: CircleAvatar(
            backgroundImage: AssetImage('assets/moon.jpg'),
          ),
          title: Text('Moon'),
          trailing: Icon(Icons.keyboard_arrow_right),
        ),
        ListTile(
          leading: CircleAvatar(
            backgroundImage: AssetImage('assets/stars.jpg'),
          ),
          title: Text('Star'),
          trailing: Icon(Icons.keyboard_arrow_right),
        ),
      ],
    ).toList(),
  );
}

에셋폴더 생성 후 이미지 넣기

프로젝트 폴더에 에셋폴더를 위와같이 만들고 해당 이름으로 이미지를 넣어준다.

에셋 폴더 설정

pubspec.yaml파일을 열어서 

flutter:

  assets:

    - assets/ 

이부분을 추가해 준다.

 

리스트의 이미지 커스터마이징

 

서브타이틀 추가방법

ListTile(
  leading: CircleAvatar(
  	backgroundImage: AssetImage('assets/sun.jpg'),
  ),
  title: Text('Sun'),
  trailing: Icon(Icons.keyboard_arrow_right),
  subtitle: Text('93 million miles away'),
),

서브타이틀 추가

 

카드타입 리스트

 

Widget _myCardTypeList(BuildContext context) {
  final titles = [
    'bike',
    'boat',
    'bus',
    'car',
    'railway',
    'run',
    'subway',
    'transit',
    'walk'
  ];

  final icons = [
    Icons.directions_bike,
    Icons.directions_boat,
    Icons.directions_bus,
    Icons.directions_car,
    Icons.directions_railway,
    Icons.directions_run,
    Icons.directions_subway,
    Icons.directions_transit,
    Icons.directions_walk
  ];

  return ListView.builder(
    itemCount: titles.length,
    itemBuilder: (context, index) {
      return Card(
        //                           <-- Card widget
        child: ListTile(
          leading: Icon(icons[index]),
          title: Text(titles[index]),
        ),
      );
    },
  );
}

카드타입 리스트

 

커스텀 리스트 아이템

위젯 컬럼을 세팅해서 리스트에 집어넣은 경우이다.

Widget _customListItem(BuildContext context) {
  // the Expanded widget lets the columns share the space
  Widget column = Expanded(
    child: Column(
      // align the text to the left instead of centered
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        Card(
          child: ListTile(
            leading: Icon(Icons.computer),
            title: Text("Title"),
            subtitle: Text("SubTitle"),
          ),
        )
      ],
    ),
  );

  return ListView.builder(
    itemBuilder: (context, index) {
      return Card(
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Row(
            children: <Widget>[
              column,
              column,
              column,
            ],
          ),
        ),
      );
    },
  );
}

카드타입에 카드타입을 넣은 경우

 

출처 : https://pusher.com/tutorials/flutter-listviews

반응형
반응형

간혹 빌드가 끝나고나서 특정 이미지를 교체해야 하거나 영상을 바꿔야 되면 해당 비디오 파일 또는 이미지 파일을 교체 후 새롭게 빌드를 시켜야 하는 번거러운 작업을 해야할 경우가 생긴다. 

교체해야할 상황이 빈번하다고 판단되는 프로젝트일 경우 특정 폴더에 교체 할 소스 파일을 넣어두고 해당 소스파일만 바꾸면 새로 빌드할 필요가 없게 미리 처리해 두면 될 것이다. 

using System.Collections.Generic;
using System.IO;
using UnityEngine;

public class FileItemHandler : MonoBehaviour {
    public string ParentFolderName;
    public string TargetFolderName;
    public List<string> FilePathList;
    public List<string> CoverPathList;
    public List<Texture2D> CoverSpriteList;
    string filepath;
    void Awake () { GetPathList (); }

    void GetPathList () {
        string _path = "";

        //타켓 폴더 패스 설정
        if (Application.platform == RuntimePlatform.Android) {
            //android일 경우 //
            _path = AndroidRootPath () + "Download/FH/" + ParentFolderName + "/" + TargetFolderName;
        } else {
            //unity일 경우 //
            _path = System.Environment.GetFolderPath (System.Environment.SpecialFolder.Personal) + "/Desktop/FH/" + ParentFolderName + "/" + TargetFolderName;
        }

        DirectoryInfo Folder = new DirectoryInfo (_path);

        //각 비디오의 패스(URL) 리스트 만들기
        foreach (var file in Folder.GetFiles ()) {
            if (file.Extension != ".meta" && file.Extension != ".DS_Store") { //비디오 이외의 확장자를 가진 파일 제외시키기
                filepath = _path + "/" + file.Name;
                if (!filepath.Contains ("._")) { //파일명 에러 수정해주기
                    // filepath = filepath.Replace ("._", "");
                    if (filepath.Contains (".mp4")) //비디오 파일 add 리스트
                        FilePathList.Add (filepath);
                    else if (filepath.Contains (".jpg")) { //커버이미지 파일 add 리스트
                        CoverPathList.Add (filepath);
                        Texture2D tex = null;
                        byte[] filedata;
                        if (File.Exists (filepath)) {
                            filedata = File.ReadAllBytes (filepath);
                            tex = new Texture2D (2, 2);
                            tex.LoadImage (filedata);
                            // Sprite sp = SpriteFromTexture2D (tex);
                            CoverSpriteList.Add (tex);
                        }
                    }
                }
            }
        }
        Debug.Log(ParentFolderName + "/" + TargetFolderName + ", FileCount : " + FilePathList.Count+ ",, SpriteCount : " + CoverSpriteList.Count);
    }

    string AndroidRootPath () {
        string[] temp = (Application.persistentDataPath.Replace ("Android", "")).Split (new string[] { "//" }, System.StringSplitOptions.None);
        return (temp[0] + "/");
    }

    Sprite SpriteFromTexture2D (Texture2D texture) {
        return Sprite.Create (texture, new Rect (0.0f, 0.0f, texture.width, texture.height), new Vector2 (0.5f, 0.5f), 100.0f);
    }
}

 

 

반응형
반응형

1번 : 이미지 가장자리에 여백이 없고 Filter Mode를 Bilinear로 세팅.

2번 : 이미지 가장자리에 여백이 없고 Filter Mode를 Pointer로 세팅.

3번 : 이미지 가장자리에 4방으로 2px의 여백을 주고 Filter Mode를 Bilinear로 세팅.

4번 : 이미지 가장자리에 4방으로 2px의 여백을 주고 Filter Mode를 pointer로 세팅.

UI Canvas에서 설정 별 이미지 깨짐 현상 비교

보통 Sprite 이미지를 임포트 해서 Canvas 상에 올린 후 로테이션값을 조절해 사용하다보면 위 이미지에서 처럼 가장자리가 깨지거나 혹은 가장자리만 깨지는 현상을 경험할 수 있다. 결론부터 얘기해서 3번처럼 보이게 하기 위해서는 포토샵에서 아래처럼 이미지의 바깥쪽에 1~2px의 여백을 만들어 가져오면 해결된다. 가져온 이미지는 Filtermode를 Bilinear 또는 Trilinear로 선택해주고 Apply시켜준다.

포토샵에서 이미지 가장자리에 강제로 여백을 준다.
Filter Mode

 

 

참고 : https://gamedev.stackexchange.com/questions/139626/is-ui-anti-aliasing-broken-in-unity-5-6

 

Is UI anti-aliasing broken in Unity 5.6?

I have a project that was started in Unity 5.5. When I open it in 5.6, most 2D graphics look like they're not anti-aliased: left is 5.6, right is 5.5 What you see there are UI Images in a Canvas....

gamedev.stackexchange.com

 

반응형
반응형

아무 게임오브젝트에 해당 스크립트를 붙이면 Debug가 출력 될 때 화면에 똑같이 출력해준다.

에디터에서는 필요없겠지만 기기에서 테스트할 때 편리하다.

 

using System.Collections;
using UnityEngine;

public class DebugToScreen : MonoBehaviour {
 	string myLog;
 	Queue myLogQueue = new Queue ();

 	void OnEnable () {
 		Application.logMessageReceived += HandleLog;
 	}

 	void OnDisable () {
 		Application.logMessageReceived -= HandleLog;
 	}

 	void HandleLog (string logString, string stackTrace, LogType type) {
 		myLog = logString;
 		string newString = "\n [" + type + "] : " + myLog;
 		myLogQueue.Enqueue (newString);
 		if (type == LogType.Exception) {
 			newString = "\n" + stackTrace;
 			myLogQueue.Enqueue (newString);
 		}
 		myLog = string.Empty;
 		foreach (string mylog in myLogQueue) {
 			myLog += mylog;
 		}
 	}

 	void OnGUI () {
 		GUILayout.Label (myLog);
	}
}

 

반응형

+ Recent posts