Marek Chrenko & Tomáš Vondráček
1
Představení
• Marek Chrenko & Tomáš Vondráček
• Android developers ve společnosti Inmite.
2
Kam smeruje mobilný svet?
3
Internet of Things
• inteligentné domy
• autá bez vodiča
• RFID náramky
4
Kontextové aplikácie
• dopĺňajú realitu
• silné využitie senzorov
• špecifické UI (napr. hlasová navigácia)
• jednoducho dostupné
5
Wearables
• smartfón? such oldschool
• hodinky, náramky, oculus rift
• airbond od Inmite
• Google Glass
6
Google Glass
7
Google Glass
• snažia sa určiť smer vo wearables
• aktuálne developer preview
• OS Android 4.x
• spolupracujú s Android a iOS zariadeniami
8
Technické okienko
• CPU 1.2 GHz, dual-core
• RAM 1 GB
• 16 GB Flash
• displej 640x360
• zvuk skrz kosti pri uchu
• 5MPix fotoaparát s HD videom
• wifi, bluetooth, microUSB
9
Používanie
• demo hlasového vstupu a pohybu v systéme
10
Vývoj
11
• Android SDK od API 15
• Mirror API (REST)
• natívne GDK
Mirror API
12
• REST prístup, Glass API backend
• komunikácia cez JSON
• karty sú hlavná UI zložka
• všetko ide do timeline
• demo
Statické karty
13
Statické karty
14
POST /mirror/v1/timeline HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer {auth token}
Content-Type: application/json
Content-Length: 26
!
{ "text": "Hello world" }
Mirror API toho vie viac
15
• vytvárať menu items
• zdieľať karty
• interagovať s kartami
• bundlovať karty
• je Google cloud based
Glass Development Kit
16
• beží priamo na Glass HW
• od API level 19
• rozširuje Android SDK o Cards, Voice
(triggers), Gesture Detector
• interakcia s používateľom v reálnom čase
• funguje offline
• prístup k HW
Aplikačné prvky GDK
17
• live cards
• immersions
• UI Widgety a preddefinované štýly
• prístup k senzorom
Demo
• trochu bankovej teórie
• a viac hernej zábavy
• viac info - David Vávra / destil.cz
18
Marek Chrenko & Tomáš Vondráček
Android UI
25.4.2014
19
Agenda
• View hierarchy
• Layouts
• ListView
• Canvas
• Custom View
• Animace
• Styly
20
View hierarchy
21
View hierarchy
22
23
24
View
• základní stavební blok
• View vs ViewGroup
• každé View má layoutParams pro svého
parenta
25
Layouts (ViewGroup)
• Definují strukturu UI
• Mohou se vnořovat, ale čím hlubší
hierarchie, tím pomalejší měření a layout
26
Views
• v xml
• v kódu
TextView txt = new TextView(context);
txt.setText(R.string.text)
txt.setLayoutParams(new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT));
27
Views
• view vytvořené v xml se“nahustí”do
hierarchie
LayoutInflater inflater = LayoutInflater.from(ctx)
View v = inflater.inflate(R.layout.fragment_commits,
container, false);
28
Views
• na jednotlivá view se přistupuje přes ID
TextView title = view.findViewById(R.id.title);
29
View hierarchy
• perform traversal (asynchronní)
• measure
• layout
• draw
30
Layouts
• Základní layouty z frameworku:
• FrameLayout, LinearLayout,
RelativeLayout, TableLayout, GridLayout
• Vlastní layout
• AdapterView
• ListView, GridView
31
FrameLayout
• Nejjednodušší
• Nejefektivnější
!
• layout_margin
• layout_gravity
32
FrameLayout
!
!
!
33
LinearLayout
• Horizontální nebo vertikální
!
• layout_weight - potomci mohou mít váhu
• layout_gravity
• layout_margin
34
LinearLayout
35
LinearLayout
!
36
RelativeLayout
• Jednotlivá View jsou pozicována vůči sobě
nebo vůči předkovi
• Umožňuje vytvořit plochou hierarchii
37
RelativeLayout
38
RelativeLayout
!
!
39
ListView & GridView
• vytvářejí kolekci View na základě dat z
adaptéru
• recyklace View
• vždy je vytvořeno pouze tolik view kolik
je zobrazeno (+ 1 či 2)
40
ListView & GridView
41
ListView
42
ListView
43
• nasledovné postupy platia aj pre GridView
• zobrazujú veľké počty záznamov
• náročné na CPU/pamať - pri akciách ako
scroll a fling
• použitie adaptérov
ListView
44
• view sú ťažké objekty (1-2 kb)
• recyklujú sa
• naplnenie view obsahom sa deje v
getView(position, convertView, parent)
getView so sekaním
45
public View getView(int position, View convertView, ViewGroup parent)
{ !
View item = mInflater.inflate(R.layout.list_item_icon_text, null);!
!
((TextView) item.findViewById(R.id.text)).setText(DATA[position]); !
((ImageView) item.findViewById(R.id.icon)).setImageBitmap( !
(position & 1) == 1 ? mIcon1 : mIcon2);!
return item; !
}
getView klasicky
46
public View getView(int position, View convertView, ViewGroup parent)
{ !
if (convertView == null) { !
! convertView = mInflater.inflate(R.layout.item, parent, false); !
! } !
!
((TextView)convertView.findViewById(R.id.text))!
.setText(DATA[position]); !
!
((ImageView) convertView.findViewById(R.id.icon))!
.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2);!
!
return convertView; !
}
getView plynulo
47
public View getView(int position, View convertView, ViewGroup parent)
{ !
ViewHolder holder;!
if (convertView == null) { !
! convertView = mInflater.!
! ! ! ! inflate(R.layout.list_item_icon_text, parent, false);!
holder = new ViewHolder(); !
holder.text = (TextView) convertView.findViewById(R.id.text); !
holder.icon = (ImageView) convertView.findViewById(R.id.icon); !
convertView.setTag(holder); } !
else { !
holder = (ViewHolder) convertView.getTag(); !
} !
!
holder.text.setText(DATA[position]); !
holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2); !
return convertView; !
}
Adaptér
48
• nerobiť si lokálnu view cache!
• nesnažiť sa vybabrať s ListView
• nemeniť štruktúru convertView - to sa
vracia typu, ktorý určí komponenta a je
vždy správny
• notifyDataSetChanged()
• notifyDataSetInvalidated()
Typy View
49
• vstavané typy (jednoduché texty)
• ak chceme viac typov view, preťažíme
getViewTypeCount(),
getItemViewType(position)
Typy View
50
@Override!
public int getViewTypeCount() {!
! return super.getViewTypeCount() + 1; // activate view type!
}
@Override!
public int getItemViewType(int position) {!
! if (getItem(position) instanceof CardTO) {!
! ! return VIEW_TYPE_ACTIVATE;!
! }!
! return super.getItemViewType(position);!
}
Properties
51
• enabled / disabled položky
• single / multiple choice mode
• hasStableIds() = = true ako optimalizácia
Header & Footer view
52
• skrolujú s položkami listview
• Quick Return pattern
Problémy
53
• čierny list počas skrolovania - nastaviť
cacheColorHint na transparentnú farbu
• nevkladať listview do scrollview a naopak
• potrebujeme listview? nestačí layout
generovať?
CustomView
54
• možnosť odlíšenia od davu
• zapúzdrenie kódu
• optimalizácia
• prístup k protected metódam
• demo: ClipboardEditText
Život View
55
• pridanie / odobranie z window
• meranie, pozicovanie a vykreslenie
• perzistencia stavu
pridanie / odobranie
56
• po volani ViewGroup.addView
• zavolá sa onAttachedToWindow()
• idealne miesto na nastavenie listenerov,
zresetovanie stavu
• pri odoberaní - onDetachFromWindow()
• o svojich zmenách view informuje okolie
cez rozhrania a callbacky (nemá
onCreate,..)
odmeraj, rozlož, nakresli
57
• všetky view sa dokážu odmerať (pevné
šírky, príp. LayoutParams)
• requestLayout() sa stará o prepočet
layoutu rekurzívne, preto treba držať
plochý view strom
• onMeasure() rozhoduje o veľkosti view a
jeho potomkov - musí volať
setMeasuredDimension() pred návratom
• následne sa prevedie layout - paddingy,…
a uchovaj stav
58
• pri rotácií obrazovky dochádza k
zahodeniu views a znovuvytvoreniu UI
• onSaveInstanceState(),
onRestoreInstanceState()
• vytvoriť potomka triedy BaseSavedState
Canvas
• přímé kreslení pomocí primitiv
• můžeme přes něj vykreslit obsah View
nebo si můžeme kreslit do bitmapy
• umožňuje základní transformace
• translace, rotace, scale
59
Canvas - pojmy
• Canvas - malíř, pamatuje si draw calls
• Bitmap - pixely, na které se aplikují draw
calls
• Paint - štětec, určuje barvu a styl
60
Canvas primitiva
• drawText(),
• drawBitmap(),
• drawLine(),
• drawPath()
• drawRect(),
• …
61
Canvas - stav
• uložení/obnovení stavu pro aplikování
transformací
62
Canvas - stav
canvas.save();
canvas.translate(textX, 0);
!
canvas.drawText(text, x, y, mPaint);
canvas.restore();
63
Canvas - tip
Bitmap bmp =
Bitmap.createBitmap(view.getWidth(),
view.getHeight(),
Bitmap.Config.ARGB_8888);
!
Canvas canvas = new Canvas(bmp);
view.draw(canvas);
64
Canvas - tip
Bitmap bmp =
Bitmap.createBitmap(view.getWidth()/4,
view.getHeight()/4, Bitmap.Config.ARGB_8888);
!
Canvas canvas = new Canvas(bmp);
canvas.setScale(0.25, 0.25)
view.draw(canvas);
65
Animace
• “Anima”= duše
66
Souřadný systém
67
Property animation
• Animace čehokoli na jakémkoli objektu.
• Včetně vlastních objektů a vlastních
property.
68
Property animation:
• Animator: tiká
• Interpolator: y = f(t)
• y začíná na 0, končí na 1
• Evaluator: x0 + y * (x1 - x0)
69
Property animation
• ObjectAnimator
• Typicky volá nad view:
• setRotationX, setRotationY
• setTranslationX, setTranslationY
• setScaleX, setScaleY
• setAlpha
70
Property animation
ObjectAnimator animator =
ObjectAnimator.ofFloat(view,
View.ROTATION_X, 0f, 180f);
animator.setDuration(1000L);
animator.start();
71
Property animation
view.animate()
.rotationX(180f)
.setDuration(1000L);
72
Property animation
view.animate()
.rotationX(180f)
.translationY(100f)
.alpha(0.5f)
.scaleY(0f)
.setDuration(1000L);
73
Property animation
view.animate()
.rotationX(180f)
.setDuration(1000L)
.withLayer();
74
Tipy a triky
• LayoutTransition
• LayoutAnimationController
• ViewPager Transformer
• Window Animation
75
Layout Transition
• v xml: android:animateLayoutChanges=”true”
• final LayoutTransition transition = new
LayoutTransition();
view.setLayoutTransition(transition);
76
Layout Animation Controller
• Animace itemů ListView/GridView.
• Využívá api level 1 animace.
77
Layout Animation controller
Animation anim =
AnimationUtils.loadAnimation(getActivity(),
R.anim.slide_bottom_top);
!
LayoutAnimationController c =
new LayoutAnimationController(anim);
!
getListView().setLayoutAnimation(c);
78
ViewPager Transformer
• Transformace každé stránky podle
současné pozice.
• ViewPager.setPageTransformer(...)
79
Window animation
ActivityOptions options =
ActivityOptions.makeScaleUpAnimation(view,
0, 0, view.getWidth(), view.getHeight());
!
Intent intent = new Intent(getActivity(),
MyActivity.class);
startActivity(intent, options.toBundle());
80
Window animation
overridePendingTransition(android.R.anim.fade_in,
android.R.anim.fade_out);
81
Styly a témata
• Style
• sada vlastností které určují vzhled a
formát okna nebo konkrétního view
• Theme
• styl aplikovaný na celou aplikaci
82
Inline vs Style vs Theme
• Level 0 - inline
• Level 1 - style
• Level 2 - theme
83
Inline vs Style vs Theme
• Level 0 - inline
84
layout.xml
Inline vs Style vs Theme
• Level 1 - style
85
Styles.xml
layout.xml
Inline vs Style vs Theme
• Level 2 - theme
86
layout.xml
themes.xml
Výhody
• Šetří čas
• Neopakuje se stále stejný kód
• Oddělení vzhledu od struktury UI
• je vyměnitelný
87
Přepínání témat
• Plné využití themes jak jsme si ukázali
• Navíc:
• Vlastní view
• Ikonky
• Různé styly pro text
88
Attribute
• V layout.xml nepřiřadíme přímo style, ale
attribute
• Hodnotu attributu nastavíme v tématu
• Attribute se vyhodnotí v runtimu podle
aktuálního tématu
89
Attribute
90
attrs.xml
Attribute
91
theme.xml
Attribute
92
theme.xml
Attribute
93
layout.xml
Přepínání témat
94
public abstract class BaseActivity extends Activity {
!
private SkinManager mManager;
private int mCurrentThemeId;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
!
final int themeId = this.mManager.getSelectedThemeId();
mCurrentThemeId = themeId;
this.setTheme(themeId);
}
!
...
!
}
Přepínání témat
95
@Override
protected void onResume() {
if (mCurrentThemeId != mManager.getSelectedThemeId()) {
Log.d(Utils.TAG, "new theme selected, restarting activity");
Intent starterIntent = this.getIntent();
starterIntent.setAction(null);
!
startActivity(starterIntent);
finish();
super.onResume();
return;
}
}
Přepínání témat
96
Díky.
Otázky?
97