捐贈眾籌分析:GoFundMe

https://www.01caijing.com/blog/7936.htm

10月21日,美國著名眾籌網站Indiegogo將旗下主打慈善、捐贈等以個人募資活動為主的眾籌板塊Indiegogo Life獨立出來,成立了新的捐贈眾籌平台Generosity,突出捐贈眾籌方向。在業內人士看來,這不是一次簡單的業務調整,而是Indiegogo向捐贈眾籌老大GoFundMe發起挑戰的標誌,後者在2014年底一舉超越Kickstarter,已經成為世界上最大的眾籌平台。

捐贈眾籌平台代言人--GoFundMe

GoFundMe是一家美國眾籌網站,於2010年上線。不同於專注、精緻的Kickstarter和開放包容的Indiegogo,GoFundMe從運營伊始就選擇了一條與眾不同的道路。 GoFundMe的目標是建成一個為個人需求、個人活動或是個人目標提供眾籌募資服務的平台,它的服務範圍十分廣泛,例如為患病的親友募捐,為一場體面的葬禮募捐,為社區的橄欖球隊募捐,或是為一場旅行募捐等等。目前,GoFundMe接受來自於美國、英國、加拿大、澳大利亞和一些使用歐元的歐盟國家的眾籌項目,全世界各地的人都可以在GoFundMe上進行捐贈。

與行業大佬Kickstarter和Indiegogo相比,在GoFundMe上發布的項目更接地氣兒,更貼近個人生活。 GoFundMe將項目分為21個大類,包括重大災難、醫療、志願者、緊急事項、教育、紀念、體育、動物、生意、慈善、社區、競賽、創意、節日、信仰、家庭、重大新聞、婚嫁、旅行、心願和其他等。先鋒金融綜合研究所數據顯示,截至2013年8月30日,GoFundMe上有約17%為醫療眾籌項目,11%為籌集學費項目,10%為籌集旅行費用項目。

GoFundMe要求發起人使用實名,保證項目的真實和信息的透明,但捐贈人可以保持匿名。一般情況下,眾籌項目通過社交媒體分享後,所受捐贈基本都來自於發起人的親友、同事、同學、鄰居等生活中的熟人。對於項目的真實性,GoFundMe不予以百分之百的保證,僅是鼓勵捐贈者只對認識和信任的熟人進行捐贈。除此之外,GoFundMe還要求發起人保證個人信息與Facebook信息一致。

在GoFundMe上發起眾籌項目十分簡便,項目可以不設定時間限制和目標籌款金額,這意味著受贈人可以隨時提現而不會影響眾籌進程;捐贈者進行捐贈也很容易,還可支持月捐。

但值得注意的是:在GoFundMe上進行眾籌並不免費,平台會從每個項目的募得資金裡抽取5%作為手續費,第三方支付機構也會收取一定的手續費。

GoFundMe對收費原因的解釋是:GoFundMe所收費用主要是運營費用,用於網站維持、人員工資等。 GoFundMe的收費政策使其具有很強的盈利能力,無需外部資金輸血。所以它直到2015年4月末才傳出準備融資的新聞,那時其估值已超5億美元。

福布斯中文網數據顯示,按現有收費政策測算,GoFundMe在最近12個月內實現營收5,000萬美元,其中大部分是利潤,而Kickstarter的年利潤僅在500萬到1,000萬美元之間。 2011年至今,GoFundMe取得的數據在眾籌行業內十分亮眼:

1、騰訊科技數據顯示,2013年至2014年9月,GoFundMe平台上共發起了近15萬個教育類眾籌項目,總籌資額達到1,777萬美元。 2011年至2014年,有關學費的眾籌項目已增長了約45倍;

2、2014年,GoFundMe為一個絕症女孩籌集了183萬美元的醫療費用,這是GoFundMe平台上籌資最多的項目;

3、2014年底,GoFundMe在籌款額上一舉超越Kickstarter,成為世界上最大的眾籌平台;

4、2015年5月18日,GoFundMe平台上的籌款額已經達到10億美元,這些籌款來自於100多萬個募資活動的1,100多萬捐贈者;

5、2015年7月,GoFundMe的聯合創始人向Accel Partners和Technology Crossover Ventures等投資機構出售了多數股份,完成了首輪融資,估值達6億美元。

GoFundMe在眾籌行業內一直都不能算是明星企業,沒有像Kickstarter和Indiegogo們那樣備受關注,可以說是一直在“悶聲發大財”。然而,隨著業績的突飛猛進,GoFundMe的行業地位開始凸顯,也越來越多的受到業內同行的關注和效仿。這也正是Indiegogo將聚焦於個人募資活動的Indiegogo Life板塊獨立出來,推出Generosity的主要原因。

“悶聲發大財”的秘訣

GoFundMe的追隨者們包括Generosity(Indiegogo Life)和Tilt(原Crowdtilt)等,他們都採取了各種方式與GoFundMe展開競爭。新成立的Generosity表示他們不會向個人募資活動收取費用(支付手續費除外),將以較低的價格進行競爭。而Tilt自更名之後,對原有網站進行了重新設計,希望通過順暢的用戶體驗來吸引用戶。

然而,這些舉措在短期內似乎無法撼動GoFundMe在捐贈眾籌領域的老大地位,因為GoFundMe擁有獨到的“發財秘訣”。

為了一切眾籌

與Kickstarter只關注創意項目相比,人們在GoFundMe上幾乎可以為了一切眾籌--或者說任何什麼人都可以因為任何理由在GoFundMe上眾籌。 2013年時,曾有一位美國女職員為了償還從主管處盜取的錢,在GoFundMe上發起了眾籌,最終得到了一定數額的捐贈。她表示,眾籌的目的只是為了說明“自己並非是一位壞公民,只是一時鬼迷心竅走錯了路而已”。另一則事件發生在今年,美國一家“反同”披薩店為彌補因堅持立場而遭受的財務損失,在GoFundMe上發起了眾籌,兩天時間就籌集到約84萬美元。除此之外,GoFundMe上還發起過為殺害黑人少年的警官達倫o威爾遜提供支持的籌資活動,雖然該活動最終因為爭議太大而被發起人關閉,但籌資總額已高達43萬美元。

在對眾籌原因的接受程度上,GoFundMe顯得更加開放,它一直強調平台的中立地位,認為“最開放的平台將擁有最大的影響力”,正如Facebook、Twitter們做的一樣。

病毒式傳播

GoFundMe要求每個發起人都具有真實的Facebook信息,在發起項目之後可以將項目信息分享到Facebook、Twitter等社交網站,讓自己的親人、朋友、同事、鄰居等熟人都參與其中。同時,GoFundMe強調故事真實、信息透明,一個真實感人的故事往往能快速吸引人們的注意--人們即使不直接進行捐贈,也會願意通過社交網絡把項目分享給其他可能進行捐贈的人,畢竟點擊分享按鈕只是“隨手之勞”。基於以上兩點,再與時下熱點或敏感話題相結合,很容易造就病毒式傳播的募資活動。

2013年12月,美國佛羅里達州居民Curtis Shannon在社交網絡上曝光了一段自己被警察暴力威脅的視頻,該視頻在社交網絡上迅速傳播開來。人們在對Curtis Shannon表示同情的同時,也在GoFundMe上用於支持其法律費用的眾籌項目上慷慨捐款,使籌款金額很快達到了3700美元。除此之外,上文中提到的捐贈“反同”披薩店的眾籌活動和警官達倫o威爾遜的眾籌活動都是利用熱點事件和敏感話題進行病毒式營銷的典型案例。

在病毒式營銷的過程中,GoFundMe實際上完成了對平台的品牌推廣,讓越來越多的人知道了GoFundMe和其從事的工作。

去XX的規則限制

與Kickstarter繁瑣的規則限制相比,在GoFundMe上發起眾籌項目顯得十分簡單。 “發起-募集-收款-管理”四步便捷的流程,項目沒有時間限制和目標籌款金額限制,受贈人可隨時提現又不影響眾籌進程,沒有雜亂無章的廣告,這些使得用戶幾乎無需花費太多時間成本和學習成本即可輕而易舉的發起一項屬於自己的眾籌活動。

即使與其他捐贈眾籌網站相比,GoFundMe也有其獨特優勢。頁面風格上,同類網站Generosity和Tilt雖然更加酷炫但不夠接地氣兒,強調發起項目而不是展示項目;GoFundMe頁面簡潔清晰、分類明確,強調展示項目而不是發起項目。發起流程上,Tilt需要設定籌款時間(最長60天)和目標籌款金額等,對發起項目的原因也有所限制(不允許發起與虛擬產品有關的項目)。 Generosity發起項目則需要8個步驟,比GoFundMe更加複雜,並且它推薦發起人優先使用Email而不是社交網站分享項目信息。

總體來說,GoFundMe拋開了眾籌平台應有的大部分規則限制,無論是從頁面設計還是從用戶體驗上看,它都顯得平實又貼近生活,使人人都可參與,沒有距離感。

超越眾籌本身

成立於2010年的GoFundMe與Generosity(前身Indiegogo Life成立於2014年)和Tilt(前身CrowdTilt成立於2012年)相比,具有一定的先發優勢,形成了大量的用戶沉澱和網站流量,使其成為了個人募資活動發起者的首選網站。現如今,在GoFundMe上發起眾籌項目已經不只為尋求資金了,人們或是為了引起他人對某些事件的關注,或是為了推廣某些產品或品牌,或是為了宣傳某些理念,這已經超越了眾籌本身。

2015年2月,一名波士頓男子在GoFundMe上發起了一項目標金額為300億美元的眾籌,目的是要用籌集來的資金修繕波士頓的交通系統,使其變得更加安全舒適。 300億美元幾乎是不可能完成的目標,該男子發起眾籌的真正目的只是為了引起政府和公眾對交通系統老化問題的關注。

通過GoFundMe發起眾籌項目越來越多地成為人們尋求幫助、傳播信息的一種生活方式,而並非眾籌本身。這種趨勢引起的結果很可能是使GoFundMe成為如Facebook、Twitter、LinkedIn之類在其領域擁有世界性影響力的網站。

在GoFundMe奠定了用戶基礎、產生了一定的業務壁壘之後,收取費用成為了水到渠成的事情。並且,從發起方考慮,大部分個人募資活動都具有急迫性(如醫療費用項目和學費項目等),在發起人急需資金時,少量的費用與時間相比就已不在考慮範圍之內了。

當然,GoFundMe的強勢並不意味著其他捐贈眾籌平台沒有機會,據GoFundMe的首席執行官Rob Solomon表示,美國每年至少有3,000億美元的資金投入到非營利組織上,這表明其中與個人捐贈相關的市場仍具有很大潛力。



錦鯉女王的生意經驗分享

https://tw.appledaily.com/life/20210604/4DJAUJWGFVH63DLFNNI4543XUA/

【鍾瑩瑩臉書全文 】

偶爾我會收到一些國外臉友給我的私訊,他會跟我說:

1.) 我有很多錢

2.) 我想買你的錦鯉

3.) 願望清單一份

4.) 請給我報價

5.) 什麼時候可以寄給我


然後,我會回覆他,麻煩提供我一下資料,我好給你報價單。

1.) 進口國際機場及代號

2.) 本國營業執照影本

3.) 進口核准函影本

4.) 隔離檢疫飼養環境的照片

5.) 門店銷售環境照片 + google Maps 定位

6.) 目前已採購的錦鯉照片

然後,80% 會已讀不回,20% 會繼續溝通:


1.) ABC 機場

有航班可以抵達,繼續討論。

沒有航班可以抵達,很抱歉我們供應不了。


2.) 營業執照

有營業執照,認真做生意來的。

沒營業執照,你是在家放幾個魚桶網路買賣嗎?


3.) 進口核准函

有核准函,有經驗來的。

沒有核准函,沒經驗的小白。


4.) 隔離設備環境

有設備,老手來的,折損率低。

沒設備,新手來的,死了病了都可能怪原產地品質不好⋯⋯


5.) 門店狀況+定位

看門店陳設就可以判定他會不會照顧魚、銷售狀況如何,有定位可以看當地城市概況商業活動概況。

然後我會幫他算機場到他的門店多長距離,正常交通時間多長,這樣可以決定包裝密度應該多少氧氣供應時間。包裝密度跟進貨成本息息相關,密度高運輸成本平均低,但密度高耗氧快,如果沒算好開箱時間,客人打開的時候可能都是缺氧的死魚的。

然後還要注意當地氣候溫度,氣溫高水溫高,我從產地要如何控制運輸期間的溫度,到了他開箱的時候落差不要太大,這樣魚兒才會蘇蘇糊糊的到新家。


6.) 目前商品狀況

可以判斷他的銷售對象大約什麼級別,可以判斷他需要的產品我們能不能提供類似的。也可以討論他目前商品的進貨成本,再換算在我們這邊採購成本會多少。也可以討論魚病他一般怎麼治療處理。

以上,了解對方的採購條件、運輸條件、飼養條件、銷售條件、專業經驗等等,我才可以放心的把產品賣給他,因為我不希望他出狀況的時候,千錯萬錯都推給賣方的錯。

大部分來回溝通,有的成為長期合作的客戶,有的只是同行要看報價單,有的是小白想創業發財,有的純粹詐騙集團來亂的。


有的還會跟我說:

可以不要這麼複雜嗎?我現在跟你訂!你就給我報價單,然後我會給你匯款,你用 DHL 寄給我就好啦!

這時候我會無語⋯⋯

你要我的報價做什麼呢?

就算你真的會給我匯款,DHL也不能寄魚啊!

國際空運帶水的活動物,都有一定規範,要走海關檢疫檢查才能放行,空運期間也要訂特殊溫控倉位,包裝方式也要符合國際規定。

你該不會淘寶買習慣了,覺得買一隻活的海豚跟買一隻卡通海綿寶寶一樣簡單吧?

然後對方會堅持讓我給他做報價單,也要我拍一些魚的照片給他看⋯⋯⋯有的還要我站在魚池邊上拍一些照片給他⋯⋯

這時候,我大約就理解了⋯⋯

果然詐騙⋯


他會拿著我的報價單、魚照片,然後跟別人說他跟我買過魚,這些魚都是他買的⋯⋯

我站在魚池旁的照片他還可以把自己P圖上去,假裝來過魚場跟我合照。

至於他這麼做的目的是為啥?

阿知,基本上創意大概是這樣⋯⋯

騙當地買家,他手上有的魚是我賣給他的。

騙國際賣家,他是有經驗的進口商。

騙他朋友投資,他是成功的錦鯉商人。

騙他老爸⋯⋯我是有出息的好孩子⋯⋯⋯⋯


總之,錦鯉買賣不是你給我寫信,我就可以賣給你。 我要考量我的產品賣給誰有合理的利潤,我的產品賣給誰可以有好的品牌效益,我的產品賣給誰可以有好的當地售後服務⋯⋯⋯


啊買一隻魚這麼麻煩?

嘿啊⋯⋯⋯

還有動物健康檢驗檢疫呢!


這又是一段長長的過程,不過這裡不需要說明可以跳過,大家也沒必要看太多跟自己生活不相干的產業內容。


啊所以,不是有錢就可以跨國跟產地買魚。

不是有錢我就會賣給你。

你可以許願,但不一定會實現。

專業合作才能雙贏。

感恩~~~


PS. 買一隻魚都這麼麻煩了,以此類推⋯


WHAT IS A CO-FOUNDER? 什麼是共同創始人?

https://slidebean.com/blog/startups-what-is-a-cofounder


What are the most important points in a co-founder agreement for a startup?

And finally, our last answer in this read. A co-founder agreement is essential to establish terms in a founder/co-founder team. It clarifies specific areas and business tasks and settles them according to a binding document we call an agreement. 

Transport all your needs to that record to avoid misunderstandings. Include in it everyone’s company ownership percentage along with the names of everyone in the founding and co-founding team. Add company goals along with each person’s roles and responsibilities. And outline how you’ll make the most significant decisions. Include equity breakdown, salary, compensation, intellectual property, and exit clauses. 

遠距工作注意事項

https://igoamazing.com/remote-work/


工作的契約型態主要分 2 大類:

(1) 外包、自由工作者(freelancer),簽的是以「承攬關係」連結的合約,不受雇於他人,可自由決定是否接受委託外包的專案、自由簽約,完全支配自己的時間,但通常要自己打理一切合約條款、發票、稅務,接案若不穩定,收入也會不穩定。

(2) 全職、兼職或約聘的遠距 / 遠端工作者(Remote full-time or part-time job, or contractor),簽的是有「雇傭關係」的合約,受僱於他人,必須遵守企業規範,能享有相關的勞工權益,不需進辦公室工作,工作時間可以是約定或彈性的。

簡單地說,第(1)類通常不管你是怎麼完成專案工作,只看最後交出的結果;而第(2)類仍是一個團隊進行工作,只是團隊成員不在同一個區域空間。


簽合約前須注意什麼?

首先,需瞭解契約型態,是委託外包以案計價?還是全職、兼職或約聘?相關稅務由哪一方來付?

接著,估算自己還要多花什麼成本,比如外包的合約通常比較像公司對公司的合作,「你」就是一人公司,所以其他財務作業如發票等需自行處理,有的公司甚至會要求你成立個人公司。

另外,大部分開出遠端工作職缺的公司,都是新創或外商,如果你受雇的是外商,比如美國,就必須簽 w8 表單,否則要繳稅給美國,還需考慮你必須自己負擔勞健保,以及從國外轉帳回國的手續費也不少。

https://www.reddit.com/r/digitalnomad/comments/94en4c/got_a_remote_job_from_the_usa_need_some_help_with/


如何跟其他人溝通合作、保持良好的互動?

在遠距工作中,最常用的溝通工具就是 Skype,或者有的會使用 Google Meet。由於對話時不一定會見到臉,無法觀察臉部表情,可能只有語音,所以不要害怕頻繁溝通,聽不懂的要主動詢問,不要吝嗇主動解答。

真的不誇張,我每天的 Skype meeting 裡,出現最多的一句話就是「Do you understand?」。如果每個人都願意花一點點溝通成本,就能避免誤會,減少浪費時間,推前工作進度。


https://m.facebook.com/FedTaxNote/posts/1229291071124591?comment_id=1229308887789476&reply_comment_id=1229312804455751

如果員工在台灣超過 183 天,會構成常設機構,美國公司可能需要到台灣報稅,看員工執行業務而定。


美國軟體工程師找實習與實習心得

https://chipaohong.medium.com/418c9eba4ade

Summer Intern, 是拿到公司正職最快且最不麻煩的方法。面一間公司的正職(Full-time)工作,可能要經過

OA(Online Assessment) → HR Phone Interview → Technical Phone Interview → Technical Phone Interview II(optional) → Onsite Interview (一整天面四五組人) → Team Match (optional) → Offer

相較來說,Summer Intern 的流程就簡單多了,少了困難的Onsite Interview,且可能只有一輪Technical Phone Interview,另外一輪只是聊聊天,分享自己的 Project 經驗。

OA(Online Assessment) → HR Phone Interview → Technical Phone Interview → Technical Phone Interview II(optional) → Team Match (optional) → Offer

Return Offer

公司收你當Intern,就是希望你畢業後能回來這裡工作,透過這幾個月的暑期實習,觀察這位候選人的表現。

如果候選人表現不錯,在實習結束前後一個月,會發 return offer 給候選人,據我所知,很多大公司的 return rate 都很高,甚至 90% 以上或是100% return 的。

Salary

美國 SDE Intern 的薪水還有福利可是很優渥的。


緯創事件點出印度管理問題,鴻海等台廠如何克服挑戰?

 緯創位於印度的 Narasapura 廠上週發生暴動事件,震驚業界。事件發生後,緯創現已解僱印度高級業務主管,同時重組團隊,並設立 24 小時的電話供員工匿名投訴。此次事件,雖說因工資爭議而引起,卻同時點出台廠在印度製造所面臨的「種姓制度」管理難題。

種姓制度是超級管理難題

緯創位在印度卡納塔卡省的 Narasapura 廠發生暴動,起因主要是工資爭議,有部分工人沒有按時得到報酬或獲得適當酬勞;然而,階級分明的種姓管理制度,或許才是本次暴動的潛藏禍根。印度「種姓」社會制度階級分明,社會地位低落的工人容易與管理人產生矛盾。

根據香港經濟日報報導,台灣企業在各國經營時,為了融入當地環境維持長期經營,多會推動人事在地化的策略。但是,印度的種姓制度,往往使得台商在實踐本土化管理時,要更小心處理階級問題;避免高階級的主管與低階級的員工出現矛盾或衝突。

對此,供應鏈人士也透露,台灣主管向來較常採用「搏感情」方式,與工人一起用餐、一起同歡,主管與工人間的階級沒有那麼明顯,做法也比較平等。但隨著在地化成趨勢,台灣製造廠開始聘用在地主管;由於印度有種姓制度,所以印度高階主管上任後,往往會一改過去台灣主管的平等作法或人事、勞務安排。這或許是緯創本次發生暴動的主要因素之一,使原本在緯創工作或已與緯創簽訂合約的勞務公司受影響,種下不滿因素。

也因此當地警方同時也在調查,是否有人為了宣洩不滿,鼓動基層工人暴動砸廠;卡納塔卡省工業廳長也表示,這起暴力事件可能是緯創與勞務公司和工人之間溝通不良所致。

如何管理維持穩定,女性員工或成一大關鍵

然而,緯創印度廠發生暴動後,並未影響台灣電子製造業者前進印度的計畫。像是和碩表示,大趨勢不受影響,會按先前規劃,印度廠最快明年下半年量產。鴻海也稱清奈擴產進度不會受此事件影響,同時鴻海與集團旗下富智康持續向印度政府申請生產獎勵。

這些持續實施印度製造策略的業者,究竟該如何因應種姓制度,維持管理、營運穩定?或許,鴻海去年已先實施關鍵策略,就是以女性員工為主。

2015 年,鴻海集團旗下富士康首座印度廠在印度安德拉省斯里市(Sri City)啟用;富士康印度工廠聘用將近 1.5 萬名勞工,女性約占九成,為多家公司組裝手機。第二座印度手機廠 2017 年在泰米爾納德省的斯利柏倫菩德(Sriperumbudur)開張,距第一座廠約 2 小時車程;這座廠聘用 1.2 萬人,廠房作業局部自動化。

在印度主管 Josh Foulger 領導下,印度富士康已成為重要的製造基地,未來也持續有擴廠計畫。那麼,為何會選擇以女性員工為主?Foulger 表示,事實上,他打從一開始就決定聘用女性勞工,因為執教鞭的母親說服他給婦女機會。

Foulger 透露,在印度,工廠女工不像中國那麼常見,鄉村婦女往往無酬做家事或進行農務;原本安德拉省斯里市甚至禁止女性輪值工廠夜班,直到當地政府和法院介入才改變;同時,也由於印度製造商大多偏好僱用男性,所以很輕鬆就達到招聘目標。

Foulger 強調,儘管必須增加保全、接駁巴士、宿舍等開銷,但這一切很值得,因為女性員工對獲得工作機會十分知足感恩,所以工作都十分賣力;同時多數印度女性工作時,心中都會有具體目標,像是償還家裡債務、讓小孩上更好學校等。

雖然此作法不能說是克服種姓制度的唯一解方,但鴻海印度廠以女性員工為主的特色,確實在營運管理保持一定穩定,並有利於未來擴產計畫;或許緯創事件發生後,此策略能供日後前進印度製造的台廠參考。


Progressive Web App 會是未來趨勢嗎?

https://blog.techbridge.cc/2016/07/23/progressive-web-app/


何謂 Progressive Web App (PWA)

先講結論,Progressive Web App 是希望能夠讓 Web application 盡可能的在各種環境(網路環境、手機作業系統等)下都能順暢且不減功能性的運作,並讓你的 Web App 可以:

  1. 直接被使用者安裝到桌面
  2. offline 使用
  3. 擁有推播功能
  4. 開啟時看不到 URL Bar(類 Native app 的使用經驗)
  5. 開啟時有 Splash Screen

而要做到這些事情,整個 PWA 的設計要點就會包含以下特性:

  • Progressive - 漸進增強:在越完善的環境下,能執行更加完整的服務,若環境不許可,能夠優雅降級,運行最基本的功能。

  • Responsive - 響應式介面:能夠在各種螢幕尺寸下顯示、能夠因應多種輸入方式與設備回饋(震動、音頻等)。

  • App-like - 類原生程式的操作模式與使用者介面:採用原生平台(Native App)的 Style 與資料更新方式(利用 service worker 存取快取資源)。

  • Fresh - 持續更新:使用 Service worker API 來自動更新應用程式(無需透過 App store, Google Play 等)。

  • Safe - 應全面採用 HTTPS 提供最基本的安全防護。

  • Discoverable - 透過設置 manifest 檔案,一樣能進行 SEO 優化,讓搜尋引擎找得到你的 APP。

  • Re-engageable - 透過推播,能主動與使用者互動。

  • Installable - 可安裝:透過 Add To Home 等方式,將 Web App 放在手機桌面,並且能在應用程式中單獨列出與切換,就像一般的 App 一樣,但完全不用透過應用程式商店下載。

  • Linkable - 透過 URL 可以隨時分享你的 App。

上面是官網所列出的,而紅色是我認為較為重點的特徵,而在這些重點特徵下,最大要點就是 Service worker。有了 Service worker 的幫助,你可以實作出離線可用的 Web App,讓 User 操作起來有更佳的使用體驗。

iOS 中 UITableView 和 自定義 UITableViewCell 的使用方法

使用纯代码自定义UItableviewcell实现一个简单的微博界面布局:https://www.cnblogs.com/wendingding/p/3761730.html


https://www.youtube.com/watch?v=2rd0FKN9XH8&list=PLzKtnppOmiXAYGqXEU_owKS-TH6FEZYeE&index=79


https://www.jianshu.com/p/f30eab24401f  頁庫存檔:

本文的重点并不仅是UITableView的基本使用方法,而是强调有关UITableView和UITableViewCell开发过程中的一些具体细节问题。基本信息请参阅Apple开发文档《Table View Programming Guide for iOS》。


概述

Table可能是最擅长于展示数据的一种UI部件。因此UITableView这个类是iOS App开发中除button和Label之外最常用的控件类型。几乎任何一个App都离不开tableView。使用UITableView很简单,核心就是要实现两个protocol。这是由于tableView在MVC中只是V这一环,所以它需要额外的支持提供另外的MC两个环节的功能才能让一个table完整的工作。而这种支持实现的途径就是protocol,Apple要求开发者提供实现** UITableViewDataSource** 和UITableViewDelegate 这两个protocol的支持类来协同对应的UITableView的工作。一般情况下,实现delegate protocol的类是UITableViewController,而data source protocol 可以是controller负责,也可以是其他helper类完成。但更多情况下,我更倾向于单独的modal wrapper类来完成。现在很多的建议data source尽可能不要放在controller中,这样有利于解决mass controller的问题。可以参考objc.io这篇文章:《Lighter View Controllers》


鉴于UITableView是如此的重要,iOS替我们定制化了两种类型的tableView:static和dynamic。前者适用于表格内容相对固定的场景,更多的使用在诸如Setting panel,Detail panel的地方;而后者适用于表格内容不固定,行数动态变化的场景,更多的使用在网络请求返回后,将动态的数据进行内容展示等。虽然Apple内置了几种(确切的说到目前为止是4种)table的style,但是对于App开发而言,大多数情况下都需要自行定制table对数据的展示方式,因此相对应的,table cell的定制化成为App开发的必修课题。


那么下文将介绍一下Static table的使用中需要注意的一些地方和dynamic table中cell开发的方法总结。


关于Static Table的报错

static table的设置方法很简单,在Xcode中设置UITableView的类型为static即可。

这里着重强调一个问题,绝大多数使用static table view的人都会遇到xcode报出的一个莫名其妙的错误:

error.png

而这个问题的原因是:放置static table的View Controller <u> ** 必须为iOS内置的UITableViewController类型 ** </u>

据说这是xcode的一个bug,但是到目前为止还没有被“修复”的迹象,总而言之,造成的结果就是,如果你想在某个页面放置一个static table view,你必须单独放在UITableViewController中,而且仅仅手动将自己的viewController的类继承自UITableViewController或者在xib中强制改成UITableViewController都不行,必须是原生的UITableViewController。可是很多情况下我们确实需要在自己的viewcontroller中添加一个static table view。怎么办?解决方法是使用Container View。


在你自己的ViewController中拖入一个Container View

删除这个Container View自动创建的segue和对应的target view controller

containerView.png

拖入一个新的UITableViewController,加入一个table view,修改类型为static;

Ctrl-drag container view到这个UITableViewController,在弹出的segue类型中选择Embed:

statictable.gif

当然,这种方式只适用于storyboard操作并且要求支持Container VC的iOS版本。在其他情况下,可以直接使用addSubView:,将UITableViewController的view(当然就是tableView)加到自己的“container”view之下。


UITableViewCell的使用方法

下文的重点是总结UITableView和UITableViewCell的核心方法。更多详情可以参考Apple的官方文档。


1. 预定义Cell

iOS自定义了4种常见的Cell格式,在UITableViewCell.h中的注释中Apple给了一些明确的提示这些预置的style一般都适用于什么场景:

typedef enum {
  UITableViewCellStyleDefault,  // Simple cell with text label and optional image view (behavior of UITableViewCell in iPhoneOS 2.x)
  UITableViewCellStyleValue1,  // Left aligned label on left and right aligned label on right with blue text (Used in Settings)
  UITableViewCellStyleValue2,  // Right aligned label on left with blue text and left aligned label on right (Used in Phone/Contacts)
  UITableViewCellStyleSubtitle  // Left aligned label on top and left aligned label on bottom with gray text (Used in iPod).
} UITableViewCellStyle

4种类型在Xcode中对应的选项为:Basic, Right Detail, Left Detail和Subtitle。在iOS8下测试,对应的示例图如下:

Basic:

Basic.png

Right Detail有图时:

rightdetail1.png

Right Detail无图时:

rightdetail2.png

Left Detail:

leftdetail.png

Subtitle:

subtitle.png

在这4种格式都统一有3个property可以供你使用:

textLabel:一个主标题

detailTextLabel:一个副标题

imageView:一张详情缩略图片

实际上这些预置类型就是把这3种元素做了些取舍然后在不同的位置组合了一下。我觉得在设计App的时候,在任何情况下,设计师和工程师都应当首先考虑这些预置的类型能不能满足需求,除非有足够的必要,否则不要轻易的浪费经历在重复构造定制化的View上。个人觉得Subtile模式已经适用于绝大多数对UI要求不高的场合。你完全可以自己修改这3个控件的一些属性来对UI进行微调。比如你可以尝试将imageView的大小放大一些。


2. 自定义Cell

UITableView是通过调用UITableViewDataSource中的tableView:cellForRowAtIndexPath:方法来获取每一行所需要的Cell的,所以绝大多自定义Cell的处理过程都是在这一步完成,另外由于UITableViewCell本身也是一个UIView,所以你也可以在UITableViewDelegate中的tableView:willDisplayCell:forRowAtIndexPath: 方法中对Cell的view做最后的定制化。


注意: Apple明确指出,在tableView:willDisplayCell:forRowAtIndexPath:中应当只修改“state-based properties”,比如selection和background color等等,但是不应该是内容(content),也就是不要在这里进行任何数据处理。


2.1 自定义Cell的创建

有以下几种方法:

方法1:使用Code继承预定义的cell样式,然后再手动添加自己的view

这是Apple官方文档中的示例,它通过调用initWithStyle:reuseIdentifier:使用UITableViewCellStyleDefault参数来创建一个Cell,为了方便期间,我对代码稍做了些改动,一个是简化了数据加载,另一个是用NSTextAlignment替换了废弃的UITextAlignment:

  #define MAINLABEL_TAG 1
  #define SECONDLABEL_TAG 2
  #define PHOTO_TAG 3
  
  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        static NSString *CellIdentifier = @"ImageOnRightCell";
        static int i = 0;
        UILabel *mainLabel, *secondLabel;
        UIImageView *photo;

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

        if (cell == nil) {
              cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
              cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;

              mainLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 220.0, 15.0)];
              mainLabel.tag = MAINLABEL_TAG;
              mainLabel.font = [UIFont systemFontOfSize:14.0];
              mainLabel.textAlignment = NSTextAlignmentRight;
              mainLabel.textColor = [UIColor blackColor];
              mainLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
              [cell.contentView addSubview:mainLabel];
  
              secondLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 20.0, 220.0, 25.0)];
              secondLabel.tag = SECONDLABEL_TAG;
              secondLabel.font = [UIFont systemFontOfSize:12.0];
              secondLabel.textAlignment = NSTextAlignmentRight;
              secondLabel.textColor = [UIColor darkGrayColor];

              secondLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
              [cell.contentView addSubview:secondLabel];
  
              photo = [[UIImageView alloc] initWithFrame:CGRectMake(225.0, 0.0, 80.0, 45.0)];
              photo.tag = PHOTO_TAG;
              photo.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight;
              [cell.contentView addSubview:photo];
        } else {
              mainLabel = (UILabel *)[cell.contentView viewWithTag:MAINLABEL_TAG];
              secondLabel = (UILabel *)[cell.contentView viewWithTag:SECONDLABEL_TAG];
              photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];
        }

        mainLabel.text = [NSString stringWithFormat:@"Title_%d", i];
        secondLabel.text = [NSString stringWithFormat:@"Description_%d", i];
        i++;
        NSString *imagePath = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"jpg"];
        photo.image = theImage;

        return cell;
  }

最终效果如下:

CustomCell1.png

这里有两个重点:

Cell的重用机制

重用机制对于UITableView而言是非常重要的概念,这能够显著提高滑动TableView时的性能。如果不使用重用,那么每次新的Cell出现在屏幕上时都需要新创建一个,这对快速滑动而言是非常影响用户体验,并且会占用系统大量的内存开销。iOS的TableView使用的重用机制在原理上很简单,就是系统自动维护一个queue,这个队列放着一定数量的准备好的Cell UI object,滑出屏幕范围之外一定“距离”的Cell都会被回收到这个queue里,给马上要滑入屏幕范围内的Cell复用。

使用重用的方法核心是两个概念:Cell Identity和dequeue。前者是标识一种具体的Cell的id,后者是将Cell从复用队列中取出的实际操作。首先你需要用这个id告诉系统你将要用于重用的Cell是谁(注册),然后你使用这个id从重用的队列里取出来(复用)。具体到本例中的API就是如下两个:initWithStyle:reuseIdentifier:和dequeueReusableCellWithIdentifier:。后面将看到,对于不同情况下创建的Cell,注册和复用的调用也并不相同。

必须把自定义的控件添加在cell的contentView上,而不是view上,也就是:

 cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
 ...
 // Correct!
 [cell.contentView addSubview:yourCustomComponetView];
 // Wrong!
 // [cell.view addSubview:yourCustomComponentView];

再次强调一点,Cell的Content View不是自己的root view。关于Cell View的结构可以参考这篇文章:《制作一个可以滑动操作的 Table View Cell》

这里只摘出最终结论,能够让你对一个Cell的view有直观的理解。

对于一个如图所示的Table而言:

sample.png


它的TableViewCell的View层级结构是:

<UITableViewCell; frame = (0 396; 320 44);> //1
   | <UITableViewCellScrollView; frame = (0 0; 320 44); > //2
   |    | <UIButton; frame = (302 16; 8 12.5)> //3
   |    |    | <UIImageView; frame = (0 0; 8 12.5);> //4
   |    | <UITableViewCellContentView; frame = (0 0; 287 44);> //5
   |    |    | <UILabel; frame = (15 0; 270 43);> //6

这个Cell 里有六个视图:

* UITableViewCell 这是最高层的视图。 Frame 显示它有 320 点宽和 44 点高——宽度和高度都和预期的一致,因为它和屏幕一样宽,而高度就是 44 点。

* UITableViewCellScrollView 虽然你不能直接使用这个私有类,但它的名字很好地暗示了它的功能。它的 Size 和 Cell 的一样。

* UIButton 它在 Cell 的最右边,就是 Disclosure Indicator 按钮。

* UIImageView 是上面 UIButton 的子视图,装载着 Disclosure Indicator 的图像。

* UITableViewCellContentView 另外一个私有类,它包含 Cell 的内容。这个类对于开发者来说就是 UITableViewCell 的 contentView 属性。但它只作为一个 UIView 来暴露在外,这就意味着你只在其上调用使用公开的 UIView 方法;而不能使用任何与这个类关联的任何私有方法。

* UILabel 显示 “Item #” 文本。


很显然,这里cell.contentView并不是cell.view。


方法2:使用xib绘制Custom Cell View

这是自定义Cell最常见也是最省力的方法:


首先在xcode中创建custom xib,拖拽需要的控件到xib上,并做好布局和限制;

2)新建自己的custom class,定义对应的outlet properties;

3)将xib的class设置成对应的custom class,然后将outlet和控件连接起来;

4)在适当的位置(一般为初始化的地方)调用registerNib:forCellReuseIdentifier:注册Cell;

5)在tableView:cellForRowAtIndexPath:中调用dequeueReusableCellWithIdentifier:forIndexPath:复用cell

下面的这个示例演示了上述步骤。在这个示例中,首先创建Custom Cell和xib的界面,其中有一张大图,下面有两个独立的label,然后我使用了tableView:willDisplayCell:forRowAtIndexPath:对每一行Cell的背景颜色做出最终设置,而在tableView cellForRowAtIndexPath:中对Cell的内容进行填充:


Custom View:

@interface MyTableCellView : UITableViewCell
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@property (weak, nonatomic) IBOutlet UILabel *name;
@property (weak, nonatomic) IBOutlet UILabel *date;
@end


Custom Xib:

CustomXib.png

在table View Controller中:

- (void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup here ...

...

// register the cell to tell the system preparing to reuse it.

[self.tableView registerNib:[UINib nibWithNibName:@"TableCellView" bundle:nil] forCellReuseIdentifier:cellId];

}

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        // always reuse the cell
        MyTableCellView *cell = [tableView dequeueReusableCellWithIdentifier:cellId forIndexPath:indexPath];
        
        cell.frame = CGRectMake(0, 0, [[UIScreen mainScreen] bounds].size.width, 250);
        NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"jpg"];
        cell.imageView.image = [UIImage imageWithContentsOfFile:path];
        NSDate *object = self.objects[indexPath.row];
        cell.date.text = [object description];
        return cell;
    }

    - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
    {
        NSLog(@"indexpath = %ld", indexPath.row);
        if ( indexPath.row % 2 == 0) {
          cell.backgroundColor = [UIColor redColor];
        }
        else {
          cell.backgroundColor = [UIColor greenColor];
        }
    }

Demo:

CustomCell2.png

方法3:使用code定义一个Custom Cell Class

这个在本质上和上一种使用xib的方法是一样的,只不过一个是用代码完全定制,一个是借助xib操作。但是在Cell重用的方式上有一定区别。上一种方法中,需要调用registerNib:forCellReuseIdentifier:来注册重用的Cell,在这里就需要用registerClass:forCellReuseIdentifier:方法来注册。与之对应的,获取重用的Cell的时候,调用dequeueReusableCellWithIdentifier:forIndexPath:方法。

Class myClass = [MyTableCellView class]; 
[self.tableView registerClass: myClass forCellReuseIdentifier:@"CustomCell"];
...
...
MyTableCellView *cell = [self.tableView dequeueReusableCellWithIdentifier:@"CustomCell" forIndexPath:path];
cell.label.text = @"text";
...

注意 dequeueReusableCellWithIdentifier:和dequeueReusableCellWithIdentifier:forIndexPath:的区别!!


如果你注册过Cell,在没有可用的cell时,前者会返回nil;而后者永远都会从注册的nib或者class中替你创建一个可用的Cell。也就是说,前者调用你需要手动检查nil,而后者不需要;

如果你从没有注册过cell,在没有可用的cell时,前者会返回nil,后者……直接崩溃!也就是说,调用后者你 必须确保注册过cell 。

2.2 访问Cell中的控件:

xib中使用outlet

这个应该不用多说,在Cell的原型中(不管是Static cell还是Dynamic cell)定义outlet properties,然后在xib中拖拽连接对应的控件即可;Apple官方文档上的示意图:


connect_outlet.jpg


connect_static_objects.jpg

代码中使用viewWithTag:

这个是获取parent view上某个特定view的快捷方法,首先需要设置一个sub view的tag,然后使用viewWithTag:来访问这个sub view。设置时可以通过xcode在xib中设置tag标签,也可以直接通过tag property手动设置:

创建时:

mainLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 220.0, 15.0)];
mainLabel.tag = MAINLABEL_TAG;
// customize the label here...
[cell.contentView addSubview:mainLabel];

访问时:

 mainLabel = (UILabel *)[cell.contentView viewWithTag:MAINLABEL_TAG];

有关Table和Cell的性能需要注意的问题

关于这个话题,Apple并没有用过多的篇幅介绍,但是在官方开发文档中明确提出了3点意见:


注意重用(Reuse Cell)

这点我们已经在上文中着重强调过了。


避免反复的调整Cell的布局(Avoid relayout of content)

只在创建每一个Cell的时候布局一次,而不要每一次获取Cell的时候都去重新布局。


避免透明的subviews (Use opaque subviews)

自定义cell的时候,尽可能避免使用透明的控件,因为透明控件在table滑动时将增大渲染开销。


总结

本文主要从Static table和Dynamic table两方面总结了UITableView和UITableViewCell的核心使用方法和问题,并着重介绍了Custom Cell的几种方法和注意事项。


另外,有兴趣的话,UITableView还有另外几个比较关键的功能可以继续研究,一个是Editing mode,一个是Table Index,还有一个相对也很重要的功能自定义Header和Footer View。有空的话可以再总结一下。希望此篇能帮助到您。


2016年4月5日,完稿于南京。


程式語言編年史

程式語言編年史原文 下面這張圖片描繪了整個程式語言的歷史。包括各種程式語言的發明人、程式語言的特點和適用領域、被什麼網站或公司使用等 (檢視 完整高清圖 )。 之所以會有那麼多不同的程式語言是因為設計程式語言的初衷不同、對語言學習曲線的追求不同、不同程式之間的執行成本差異...