欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Flutter Widget

 更新時間:2021年08月27日 17:38:58   作者:阿 T  
本文主要講解了Flutter Widget,它是是描述 Flutter UI 的基本單元,需要進(jìn)一步了解的小伙伴可以參考一下這篇文章

 概述:

所有的一切都可以被稱為widget

在開發(fā) Flutter 應(yīng)用過程中,接觸最多的無疑就是Widget,是『描述』 Flutter UI 的基本單元,通過Widget可以做到:

  • 描述 UI 的層級結(jié)構(gòu) (通過Widget嵌套);
  • 定制 UI 的具體樣式 (如:fontcolor等);
  • 指導(dǎo) UI 的布局過程 (如:padding、center等);

Google 在設(shè)計Widget時,還賦予它一些鮮明的特點:

  • 聲明式 UI —— 相對于傳統(tǒng) Native 開發(fā)中的命令式 UI,聲明式 UI 有不少優(yōu)勢,如:開發(fā)效率顯著提升、UI 可維護(hù)性明顯加強(qiáng)等;
  • 不可變性 —— Flutter 中所有Widget都是不可變的(immutable),即其內(nèi)部成員都是不可變的(final),對于變化的部分需要通過「Stateful Widget-State」的方式實現(xiàn);
  • 組合大于繼承 —— Widget設(shè)計遵循組合大于繼承這一優(yōu)秀的設(shè)計理念,通過將多個功能相對單一的Widget組合起來便可得到功能相對復(fù)雜的Widget。

Widget的本質(zhì):

在Widget源碼中有這樣一段注釋:

請?zhí)砑訄D片描述

這段注釋闡明了Widget的本質(zhì):用于配置Element的,Widget本質(zhì)上是 UI 的配置信息 (附帶部分業(yè)務(wù)邏輯)。

我們通常會將通過Widget描述的 UI 層級結(jié)構(gòu)稱之為「Widget Tree」,但與「Element Tree」、「RenderObject Tree」以及「Layer Tree」相比,實質(zhì)上并不存在「Widget Tree」。為了描述方便,將 Widget 組合描述的 UI 層級結(jié)構(gòu)稱之為「Widget Tree」,也未嘗不可。

分類:

請?zhí)砑訄D片描述

Widget

Widget,所有 Widget 的基類。

請?zhí)砑訄D片描述

如上圖所示,在 Widget基類中有 3 個重要的方法 (屬性):

  • Key key —— 在同一父節(jié)點下,用作兄弟節(jié)點間的唯一標(biāo)識,主要用于控制當(dāng) Widget 更新時,對應(yīng)的 Element 如何處理 (是更新還是新建)。若某 Widget 是其「Parent Widget」唯一的子節(jié)點時,一般不用設(shè)置 key;

GlobalKey 是一類較特殊的 key,在介紹 Element 時會附帶介紹。

  • Element createElement() —— 每個Widget都有一個與之對應(yīng)的Element,由該方法負(fù)責(zé)創(chuàng)建,createElement可以理解為設(shè)計模式中的工廠方法,具體的Element類型由對應(yīng)的Widget子類負(fù)責(zé)創(chuàng)建;
  • static bool canUpdate(Widget oldWidget, Widget newWidget) —— 是否可以用 new widget 修改前一幀用 old widget 生成的 Element,而不是創(chuàng)建新的 Element,Widget類的默認(rèn)實現(xiàn)為:2個WidgetruntimeTypekey都相等時,返回true,即可以直接更新 (key 為 null 時,認(rèn)為相等)。

上述更新流程,同樣在介紹 Element 時會重點分析。

StatelessWidget

無狀態(tài)-組合型 Widget,由其build方法描述組合 UI 的層級結(jié)構(gòu)。在其生命周期內(nèi)狀態(tài)不可變。

/// A widget that does not require mutable state.
///
/// A stateless widget is a widget that describes part of the user interface by
/// building a constellation of other widgets that describe the user interface
/// more concretely. The building process continues recursively until the
/// description of the user interface is fully concrete (e.g., consists
/// entirely of [RenderObjectWidget]s, which describe concrete [RenderObject]s).

具體是兩個方法:

  • StatelessElement createElement() ——「Stateless Widget」對應(yīng)的 Element 為StatelessElement,一般情況下StatelessWidget子類不必重寫該方法,即子類對應(yīng)的 Element 也是StatelessElement
@override
StatelessElement createElement() => StatelessElement(this);
  • Widget build(BuildContext context) —— 算是 Flutter 體系中的核心方法之一
@protected
Widget build(BuildContext context);

以『聲明式 UI』的形式描述了該組合式 Widget 的 UI 層級結(jié)構(gòu)及樣式信息,也是開發(fā) Flutter 應(yīng)用的主要工作『場所』。該方法在 3 種情況下被調(diào)用:

  • Widget 第一次被加入到 Widget Tree 中 (更準(zhǔn)確地說是其對應(yīng)的 Element 被加入到 Element Tree 時,即 Element 被掛載『mount』時);
  • 「Parent Widget」修改了其配置信息;
  • 該 Widget 依賴的「Inherited Widget」發(fā)生變化時。

當(dāng)「Parent Widget」或 依賴的「Inherited Widget」頻繁變化時,build方法也會頻繁被調(diào)用。因此,提升build方法的性能就顯得十分重要,F(xiàn)lutter 官方給出了幾點建議:

  • *減少不必要的中間節(jié)點,即減少 UI 的層級,*如:對于「Single Child Widget」,沒必要通過組合「Row」、「Column」、「Padding」、「SizedBox」等復(fù)雜的 Widget 達(dá)到某種布局的目標(biāo),或許通過簡單的「Align」、「CustomSingleChildLayout」即可實現(xiàn)。又或者,為了實現(xiàn)某種復(fù)雜精細(xì)的 UI 效果,不一定要通過組合多個「Container」,再附加「Decoration」來實現(xiàn),通過 「CustomPaint」自定義或許是更好的選擇;
  • *盡可能使用const Widget,*為 Widget 提供const構(gòu)造方法;

關(guān)于 const constructor 可以看看我這篇文章。

  • 必要時,*可以將「Stateless Widget」重構(gòu)成「Stateful Widget」,*以便可以使用「Stateful Widget」中一些特定的優(yōu)化手法,如:緩存「sub trees」的公共部分,并在改變樹結(jié)構(gòu)時使用GlobalKey;
  • *盡量減小 rebuilt 范圍,*如:某個 Widget 因使用了「Inherited Widget」,導(dǎo)致頻繁 rebuilt,可以將真正依賴「Inherited Widget」的部分提取出來,封裝成更小的獨立 Widget,并盡量將該獨立 Widget 推向樹的葉子節(jié)點,以便減小 rebuilt 時受影響的范圍。

StatefulWidget

有狀態(tài)-組合型 Widget,但要注意的是StatefulWidget本身還是不可變的,其可變狀態(tài)存在于State中。

/// A widget that has mutable state.
///
/// State is information that (1) can be read synchronously when the widget is
/// built and (2) might change during the lifetime of the widget. It is the
/// responsibility of the widget implementer to ensure that the [State] is
/// promptly notified when such state changes, using [State.setState].

具體有兩個方法:

  • StatefulElement createElement() ——「Stateful Widget」對應(yīng)的 Element 為StatefulElement,一般情況下StatefulWidget子類不用重寫該方法,即子類對應(yīng)的Element 也是StatefulElement;
@override
StatefulElement createElement() => StatefulElement(this);
  • State createState() —— 創(chuàng)建對應(yīng)的 State,該方法在StatefulElement的構(gòu)造方法中被調(diào)用。可以簡單地理解為當(dāng)「Stateful Widget」被添加到 Widget Tree 時會調(diào)用該方法。
@protected
@factory
State createState(); // ignore: no_logic_in_create_state, this is the original sin
StatefulElement(StatefulWidget widget)
     : _state = widget.createState(),
       super(widget) {
   _state._element = this;
   _state._widget = widget;
 }

實際上是「Stateful Widget」對應(yīng)的「Stateful Element」被添加到 Element Tree 時,伴隨「Stateful Element」的初始化,createState方法被調(diào)用。從后文可知一個 Widget 實例可以對應(yīng)多個 Element 實例 (也就是同一份配置信息 (Widget) 可以在 Element Tree 上不同位置配置多個 Element 節(jié)點),因此,createState方法在「Stateful Widget」生命周期內(nèi)可能會被調(diào)用多次。
另外,需要注意的是配有GlobalKey的 Widget 對應(yīng)的 Element 在整個 Element Tree 中只有一個實例。

State

有狀態(tài)小部件 的邏輯和Stateful Widget

State 用于處理「Stateful Widget」的業(yè)務(wù)邏輯以及可變狀態(tài)
由于其內(nèi)部狀態(tài)是可變的,故 State 有較復(fù)雜的生命周期:

請?zhí)砑訄D片描述

如上圖,State 的生命周期大致可以分為 8 個階段:

  • 在對應(yīng)的「Stateful Element」被掛載 (mount) 到樹上時,通過StatefulElement.constructor –> StatefulWidget.createState創(chuàng)建 State 實例;

StatefulElement.constructor中的_state._element = this;可知,State._emelent指向了對應(yīng)的 Element 實例,而我們熟知的State.context引用的就是這個_elementBuildContext get context => _element;。
State實例與Element實例間的綁定關(guān)系一經(jīng)確定,在整個生命周期內(nèi)不會再變了 (Element 對應(yīng)的 Widget 可能會變,但對應(yīng)的 State 永遠(yuǎn)不會變),期間,Element可以在樹上移動,但上述關(guān)系不會變 (即「Stateful Element」是帶著狀態(tài)移動的)。

  • StatefulElement 在掛載過程中接著會調(diào)用State.initState,子類可以重寫該方法執(zhí)行相關(guān)的初始化操作 (此時可以引用context、widget屬性);
  • 同樣在掛載過程中會調(diào)用State.didChangeDependencies,該方法在 State 依賴的對象 (如:「Inherited Widget」) 狀態(tài)發(fā)生變化時也會被調(diào)用,*子類很少需要重寫該方法,*除非有非常耗時不宜在build中進(jìn)行的操作,因為在依賴有變化時build方法也會被調(diào)用;
  • 此時,State 初始化已完成,其build方法此后可能會被多次調(diào)用,在狀態(tài)變化時 State 可通過setState方法來觸發(fā)其子樹的重建;
  • 此時,「element tree」、「renderobject tree」、「layer tree」已構(gòu)建完成,完整的 UI 應(yīng)該已呈現(xiàn)出來。此后因為變化,「element tree」中「parent element」可能會對樹上該位置的節(jié)點用新配置 (Widget) 進(jìn)行重建,當(dāng)新老配置 (oldWidget、newWidget)具有相同的「runtimeType」&&「key」時,framework 會用 newWidget 替換 oldWidget,并觸發(fā)一系列的更新操作 (在子樹上遞歸進(jìn)行)。同時,State.didUpdateWidget方法被調(diào)用,子類重寫該方法去響應(yīng) Widget 的變化;

上述 3 棵樹以及更新流程在后續(xù)文章中會有詳細(xì)介紹

  • 在 UI 更新過程中,任何節(jié)點都有被移除的可能,State 也會隨之移除,(如上一步中「runtimeType」||「key」不相等時)。此時會調(diào)用State.deactivate方法,由于被移除的節(jié)點可能會被重新插入樹中某個新的位置上,故子類重寫該方法以清理與節(jié)點位置相關(guān)的信息 (如:該 State 對其他 element 的引用)、同時,不應(yīng)在該方法中做資源清理;

重新插入操作必須在當(dāng)前幀動畫結(jié)束之前

  • 當(dāng)節(jié)點被重新插入樹中時,State.build方法被再次調(diào)用;
  • 對于在當(dāng)前幀動畫結(jié)束時尚未被重新插入的節(jié)點,State.dispose方法被執(zhí)行,State 生命周期隨之結(jié)束,此后再調(diào)用State.setState方法將報錯。子類重寫該方法以釋放任何占用的資源。

請?zhí)砑訄D片描述

至此,State 中的核心方法基本都已在上述過程中介紹了,下面重點看一下setState方法:

void setState(VoidCallback fn) {
  assert(fn != null);
  assert(() {
    if (_debugLifecycleState == _StateLifecycle.defunct) {
      throw FlutterError.fromParts(<DiagnosticsNode>[...]);
    }
    if (_debugLifecycleState == _StateLifecycle.created && !mounted) {
      throw FlutterError.fromParts(<DiagnosticsNode>[...]);
    }
    return true;
  }());
  final dynamic result = fn() as dynamic;
  assert(() {
    if (result is Future) {
      throw FlutterError.fromParts(<DiagnosticsNode>[...]);
    }
    return true;
  }());
  _element.markNeedsBuild();
}
  • 從上述源碼可以看到,關(guān)于setState方法有幾點值得關(guān)注:
  • State.dispose后不能調(diào)用setState (第 4 行);
  • 在 State 的構(gòu)造方法中不能調(diào)用setState (第 7 行);
  • setState方法的回調(diào)函數(shù) (fn) 不能是異步的 (返回值為Future),原因很簡單,因為從流程設(shè)計上 framework 需要根據(jù)回調(diào)函數(shù)產(chǎn)生的新狀態(tài)去刷新 UI (第 14 行);
  • 通過setState方法之所以能更新 UI,是在其內(nèi)部調(diào)用_element.markNeedsBuild()實現(xiàn)的 (具體過程在介紹 Element 時再詳細(xì)分析)。

關(guān)于 State 最后再強(qiáng)調(diào) 2 點:

  • 若State.build方法依賴了自身狀態(tài)會變化的對象,如:ChangeNotifier、Stream或其他可以被訂閱的對象,需要確保在initState、didUpdateWidget、dispose

等 3 方法間有正確的訂閱 (subscribe) 與取消訂閱 (unsubscribe) 的操作:

initState中執(zhí)行 subscribe;

如果關(guān)聯(lián)的「Stateful Widget」與訂閱有關(guān),在didUpdateWidget中先取消舊的訂閱,再執(zhí)行新的訂閱;

dispose中執(zhí)行 unsubscribe。

  • State.initState方法中不能調(diào)用BuildContext.dependOnInheritedWidgetOfExactType,但State.didChangeDependencies會隨之執(zhí)行,在該方法中可以調(diào)用。

ParentDataWidget

ParentDataWidget以及下面要介紹的InheritedElement都繼承自ProxyWidget,由于ProxyWidget作為抽象基類本身沒有任何功能,故下面直接介紹ParentDataWidgetInheritedElement。

/// Base class for widgets that hook [ParentData] information to children of/// [RenderObjectWidget]s.

ParentDataWidget作為 Proxy 型 Widget,其功能主要是為其他 Widget 提供ParentData信息。雖然其 child widget 不一定是 RenderObejctWidget 類型,但其提供的ParentData信息最終都會落地到 RenderObejctWidget 類型子孫 Widget 上。

ParentData 是『parent renderobject』在 layout『child renderobject』時使用的輔助定位信息,詳細(xì)信息會在介紹 RenderObject 時介紹。

void attachRenderObject(dynamic newSlot) {
	assert(_ancestorRenderObjectElement == null);
	_slot = newSlot;
	_ancestorRenderObjectElement = _findAncestorRenderObjectElement();
	_ancestorRenderObjectElement?.insertChildRenderObject(renderObject, newSlot);
	final ParentDataElement<RenderObjectWidget> parentDataElement = _findAncestorParentDataElement();
	if (parentDataElement != null)  
	                                          _updateParentData(parentDataElement.widget);
}
ParentDataElement<RenderObjectWidget> _findAncestorParentDataElement() {
	Element ancestor = _parent;
	while (ancestor != null && ancestor is! RenderObjectElement) 
	                                          {
		if (ancestor is ParentDataElement<RenderObjectWidget>) 
		                                          return ancestor;
		ancestor = ancestor._parent;
	}
	return null;
}
void _updateParentData(ParentDataWidget<RenderObjectWidget> parentData) 
                                          {
	parentData.applyParentData(renderObject);
}

上面這段代碼來自RenderObjectElement,可以看到在其attachRenderObject方法第 6 行從祖先節(jié)點找ParentDataElement,如果找到就用其 Widget(ParentDataWidget) 中的 parentData 信息去設(shè)置 Render Obejct。在查找過程中如查到RenderObjectElement (第 13 行),說明當(dāng)前 RenderObject 沒有 Parent Data 信息。
最終會調(diào)用到ParentDataWidget.applyParentData(RenderObject renderObject),子類需要重寫該方法,以便設(shè)置對應(yīng)RenderObject.parentData

來看個例子,通常配合Stack使用的Positioned(繼承自ParentDataWidget):

void applyParentData(RenderObject renderObject) {
	assert(renderObject.parentData is StackParentData);
	final StackParentData parentData = renderObject.parentData;
	bool needsLayout = false;
	if (parentData.left != left)
	  {
		parentData.left = left;
		needsLayout = true;
	}
	...  if (parentData.width != width) 
	  {
		parentData.width = width;
		needsLayout = true;
	}
	...  if (needsLayout) {
		final AbstractNode targetParent = renderObject.parent;
		if (targetParent is RenderObject)    
		      targetParent.markNeedsLayout();
	}
}

可以看到,Positioned在必要時將自己的屬性賦值給了對應(yīng)的RenderObject.parentData (此處是StackParentData),并對「parent render object」調(diào)用markNeedsLayout(第 19 行),以便重新 layout,畢竟修改了布局相關(guān)的信息。

abstract class ParentDataWidget<T extends RenderObjectWidget> extends ProxyWidget

如上所示,ParentDataWidget在定義上使用了泛型<T extends RenderObjectWidget>,其背后的含義是:
從當(dāng)前ParentDataWidget節(jié)點向上追溯形成的祖先節(jié)點鏈(『parent widget chain』)上,在 2 個ParentDataWidget類型的節(jié)點形成的鏈上至少要有一個『RenderObject Widget』類型的節(jié)點。因為一個『RenderObject Widget』不能接受來自 2 個及以上『ParentData Widget』的信息。

/// Base class for widgets that efficiently propagate information down the tree.
// To obtain the nearest instance of a particular type of inherited widget from
///a build context, use [BuildContext.dependOnInheritedWidgetOfExactType].

InheritedWidget 用于在樹上向下傳遞數(shù)據(jù)。
通過BuildContext.dependOnInheritedWidgetOfExactType可以獲取最近的「Inherited Widget」,需要注意的是通過這種方式獲取「Inherited Widget」時,當(dāng)「Inherited Widget」?fàn)顟B(tài)有變化時,會導(dǎo)致該引用方 rebuild。

具體原理在介紹 Element 時會詳細(xì)分析。

通常,為了使用方便會「Inherited Widget」會提供靜態(tài)方法of,在該方法中調(diào)用BuildContext.dependOnInheritedWidgetOfExactTypeof方法可以直接返回「Inherited Widget」,也可以是具體的數(shù)據(jù)。

有時,「Inherited Widget」是作為另一個類的實現(xiàn)細(xì)節(jié)而存在的,其本身是私有的(外部不可見),此時of方法就會放到對外公開的類上。最典型的例子就是Theme,其本身是StatelessWidget類型,但其內(nèi)部創(chuàng)建了一個「Inherited Widget」:_InheritedTheme,of方法就定義在上Theme上:

static MediaQueryData of(BuildContext context, {
	bool nullOk = false })
	{
		final MediaQuery query = context.dependOnInheritedWidgetOfExactType<MediaQuery>();
		if (query != null)    
		  return query.data;
		if (nullOk)    return null;
	}

of方法返回的是ThemeData類型的具體數(shù)據(jù),并在其內(nèi)部首先調(diào)用了BuildContext.dependOnInheritedWidgetOfExactType。

我們經(jīng)常使用的「Inherited Widget」莫過于MediaQuery,同樣提供了of方法:

請?zhí)砑訄D片描述

  • InheritedElement createElement() ——「Inherited Widget」對應(yīng)的 Element 為InheritedElement,一般情況下InheritedElement子類不用重寫該方法;
  • bool updateShouldNotify(covariant InheritedWidget oldWidget) —— 在「Inherited Widget」rebuilt 時判斷是否需要 rebuilt 那些依賴它的 Widget;

如下是MediaQuery.updateShouldNotify的實現(xiàn),在新老Widget.data 不相等時才 rebuilt 那依賴的 Widget。

bool updateShouldNotify(MediaQuery oldWidget) => data != oldWidget.data;

RenderObjectWidget

真正與渲染相關(guān)的 Widget,屬于最核心的類型,一切其他類型的 Widget 要渲染到屏幕上,最終都要回歸到該類型的 Widget 上。

  • RenderObjectElement createElement() ——「RenderObject Widget」對應(yīng)的 Element 為RenderObjectElement,由于RenderObjectElement也是抽象類,故子類需要重寫該方法;
  • RenderObject createRenderObject(BuildContext context) —— 核心方法,創(chuàng)建 Render Widget 對應(yīng)的 Render Object,同樣子類需要重寫該方法。該方法在對應(yīng)的 Element 被掛載到樹上時調(diào)用(Element.mount),即在 Element 掛載過程中同步構(gòu)建了「Render Tree」(詳細(xì)過程后續(xù)文章會詳細(xì)分析);
@overrideRenderFlex createRenderObject(BuildContext context) {
	return RenderFlex(  
	  direction: direction,    
	  mainAxisAlignment: mainAxisAlignment,    
	  mainAxisSize: mainAxisSize,    
	  crossAxisAlignment: crossAxisAlignment,   
	  textDirection: getEffectiveTextDirection(context),    
	  verticalDirection: verticalDirection,    
	    textBaseline: textBaseline,  
	  )
	;
}

上面是Flex.createRenderObject的源碼,真實感受一下 (還是代碼更有感覺)。可以看到,用Flex的信息(配置)初始化了RenderFlex。

FlexRow、Column的基類,RenderFlex繼承自RenderBox,后者繼續(xù)自RenderObject

  • void updateRenderObject(BuildContext context, covariant RenderObject renderObject) —— 核心方法,在 Widget 更新后,修改對應(yīng)的 Render Object。該方法在首次 build 以及需要更新 Widget 時都會調(diào)用;
@overridevoid updateRenderObject(BuildContext context, covariant RenderFlex renderObject) 
{
	renderObject   
	  ..
	direction = direction   
	  ..mainAxisAlignment = mainAxisAlignment   
	  ..
	mainAxisSize = mainAxisSize   
	  ..
	crossAxisAlignment = crossAxisAlignment  
	  ..
	textDirection = getEffectiveTextDirection(context) 
	  ..
	verticalDirection = verticalDirection   
	  ..
	textBaseline = textBaseline;
}

Flex.updateRenderObject的源碼也很簡單,與Flex.createRenderObject幾乎一一對應(yīng),用當(dāng)前Flex的信息修改renderObject。

  • void didUnmountRenderObject(covariant RenderObject renderObject) —— 對應(yīng)的「Render Object」從「Render Tree」上移除時調(diào)用該方法。

RenderObjectWidget的幾個子類:LeafRenderObjectWidget、SingleChildRenderObjectWidget、MultiChildRenderObjectWidget只是重寫了createElement方法以便返回各自對應(yīng)的具體的 Element 類實例。

小結(jié)


至此,重要的基礎(chǔ)型 Widget 基本介紹完了,總結(jié)一下:

  • Widget 本質(zhì)上是 UI 的配置信息 (附加部分業(yè)務(wù)邏輯),并不存在一顆真實的「Widget Tree」(與「Element Tree」、「RenderObject Tree」以及「Layer Tree」相比);
  • Widget 從功能上可以分為 3 類:「Component Widget」、「Proxy Widget」以及「Renderer Widget」;
  • Widget 與 Element 一一對應(yīng),Widget 提供創(chuàng)建 Element 的方法 (createElement,本質(zhì)上是一個工廠方法);
  • 只有「Renderer Widget」才會參與最終的 UI 生成過程(Layout、Paint),只有該類型的 Widget 才有與之對應(yīng)的「Render Object」,同樣由其提供創(chuàng)建方法(createRenderObject)。

到此這篇關(guān)于詳解Flutter Widget的文章就介紹到這了,更多相關(guān)Flutter Widget內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 五分鐘教你Android-Kotlin項目編寫

    五分鐘教你Android-Kotlin項目編寫

    本篇文章主要介紹了五分鐘教你Android-Kotlin項目編寫,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • Android 實現(xiàn)錨點定位思路詳解

    Android 實現(xiàn)錨點定位思路詳解

    本篇文章就使用tablayout、scrollview來實現(xiàn)android錨點定位的功能。通過<a href="#head" rel="external nofollow" > 去設(shè)置頁面內(nèi)錨點定位跳轉(zhuǎn)。具體實現(xiàn)思路大家跟隨腳本之家小編一起通過本文看下吧
    2018-07-07
  • Android編程之控件ListView使用方法

    Android編程之控件ListView使用方法

    這篇文章主要介紹了Android編程之控件ListView使用方法,實例分析了ListView控件的相關(guān)使用技巧,非常具有實用價值,需要的朋友可以參考下
    2015-04-04
  • Android入門之畫圖詳解

    Android入門之畫圖詳解

    這篇文章主要介紹了Android入門之畫圖,對Android初學(xué)者有很好的學(xué)習(xí)借鑒價值,需要的朋友可以參考下
    2014-08-08
  • Android仿知乎懸浮功能按鈕FloatingActionButton效果

    Android仿知乎懸浮功能按鈕FloatingActionButton效果

    前段時間在看屬性動畫,恰巧這個按鈕的效果可以用屬性動畫實現(xiàn),下面通過本文給大家分享adroid仿知乎懸浮功能按鈕FloatingActionButton效果,需要的朋友參考下吧
    2017-04-04
  • android使用mysql的方法總結(jié)

    android使用mysql的方法總結(jié)

    在本篇文章中小編給大家整理了關(guān)于android使用mysql的具體方法和實例代碼步驟,需要的朋友們學(xué)習(xí)下。
    2019-05-05
  • Android?Camera1實現(xiàn)預(yù)覽框顯示

    Android?Camera1實現(xiàn)預(yù)覽框顯示

    這篇文章主要為大家詳細(xì)介紹了Android?Camera1實現(xiàn)預(yù)覽框顯示,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Android自定義LinearLayout布局顯示不完整的解決方法

    Android自定義LinearLayout布局顯示不完整的解決方法

    這篇文章主要給大家介紹了關(guān)于Android自定義LinearLayout但布局顯示不完整的解決方法,文中通過示例代碼介紹的非常詳細(xì),對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11
  • Android封裝的http請求實用工具類

    Android封裝的http請求實用工具類

    提供一個Android封裝的http請求實用工具類,在做ANDROID網(wǎng)絡(luò)開發(fā)中這個經(jīng)常要用到,大家可以參考下面的工具類修改成自己的工具
    2013-11-11
  • Android應(yīng)用中圖片瀏覽時實現(xiàn)自動切換功能的方法詳解

    Android應(yīng)用中圖片瀏覽時實現(xiàn)自動切換功能的方法詳解

    這篇文章主要介紹了Android應(yīng)用中圖片瀏覽時實現(xiàn)自動切換功能的方法,文中還講解了一個觸摸大圖進(jìn)行圖片切換的深入功能,需要的朋友可以參考下
    2016-04-04

最新評論