6萬起月銷過1.5萬輛的大氣家轎 性價比高到離譜!_租車

※超省錢租車方案

商務出差、學生出遊、旅遊渡假、臨時用車!GO 神州租賃有限公司!合法經營、合法連鎖、合法租賃小客車!

m的峰值扭矩,1。5L的自然吸氣發動機搭配着CVT以及傳統的手動變速箱。艾瑞澤5的全系定價在5。89-9。79萬元之間,跨度不可為不大,新上市車型並不是傳說中搭載了奇瑞最新的渦輪增壓發動機的動力總成車型,依舊是現款艾瑞澤5的動力配置,只是在細分的配置下新增了這款名為“領跑版”定位中高級配置的車。

艾瑞澤5

要說最近火的一塌糊塗的轎車,除了奔馳的豪華中型車全新E級之外,最熱門的或許就是自主品牌的奇瑞艾瑞澤5了,上個月銷量也接近1.5萬台,10月15日,新的艾瑞澤5又迎來上市,這次儘管沒有出現傳說中的1.5T,但是產品線更豐富的艾瑞澤5該如何選擇,或許又會變成消費者心中的難題,小編這次就來分析分析,這台小車該如何選擇。

先簡單說說艾瑞澤5的身份,艾瑞澤5的外觀設計原創程度非常高,畢竟是作為純正向研發的產品之一,艾瑞澤5的設計並沒有什麼明顯的借鑒風格,這一點是值得觀眾朋友點贊的地方,自主品牌開始擺脫仿製,正向研發的車型代表了中國品牌的汽車正在逐漸成長。

前臉貫穿式的鍍鉻裝飾條簡潔明快而且辨識度極高,整車的線條描繪也非常緊湊,沒有拖泥帶水的設計感,車尾層次感也十分豐富,這也讓艾瑞澤5的外觀顯得簡約而不簡單,相反多了一種精緻感。

往期的艾瑞澤5是以紅色為主打顏色,充滿活力的鮮紅色符合當下年輕購車群體充滿朝氣的形象。新的領跑版上市增加了一款名為“鎏光橙”的配色,同樣是暖色的色調,

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

有別於一般網頁架設公司,除了模組化的架站軟體,我們的營業主軸還包含:資料庫程式開發、網站建置、網頁設計、電子商務專案開發、系統整合、APP設計建置、專業網路行銷。

可以看出艾瑞澤5的目標消費人群指向性很明顯——就是年輕的家用車潛在買家。

內飾的設計也是非常具有活力和運動感,中控按鍵布局非常清晰,在行車過程中的使用具有較為良好的溝通感,座椅的包裹性尚可,但是坐墊較硬,承托性較為欠缺。不過作為一款十萬元以內的轎車,如此的內飾設計當屬難能可貴。

空間布局還算合理,車身尺寸為4572*1825*1482(mm);軸距達到了2670mm,已經達到了主流的緊湊型轎車應有的水準,後排空間實用性尚可,而且車身設計中規中矩,並沒有犧牲多少在後排的頭部空間。一般的家用需求得以很好的滿足。

動力總成並沒有進行更換,發動機的賬面參數是116ps的最大馬力,141N.m的峰值扭矩,1.5L的自然吸氣發動機搭配着CVT以及傳統的手動變速箱。

艾瑞澤5的全系定價在5.89-9.79萬元之間,跨度不可為不大,新上市車型並不是傳說中搭載了奇瑞最新的渦輪增壓發動機的動力總成車型,依舊是現款艾瑞澤5的動力配置,只是在細分的配置下新增了這款名為“領跑版”定位中高級配置的車。

以自動擋車型為例,在領跑版本出來之前,領銳版和領臻版的差價達到了1萬元人民幣,分別為7.79萬和8.79萬,這跨度對於一款主打性價比的車型來說著實大了一些。

編輯總結:如今的領跑版上市定價為8.29萬,無疑增加了此款車的性價比。所以小編主推的細分配置是新上市的CVT領跑版,相較於領銳版加價五千,增加了胎壓監測裝置,中控大屏的GpS導航以及增加了更新的智能互聯繫統,這些配置原來只有在8.79萬元的次頂配中搭載。儘管有人說艾瑞澤5的CVT變速箱調校得過於慵懶,但是作為一台十萬元以內,售價只在七八萬元左右的經濟型家轎來說,艾瑞澤5目前的配置和定價都算是比較親民而且高性價比的存在。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

日本、大陸,發現這些先進的國家已經早就讓電動車優先上路,而且先進國家空氣品質相當好,電動車節能減碳可以減少空污

Caviar 推出奢侈黄金版 AirPods Max 、PlayStation 5 ,前者要價 300 萬元起_網頁設計

網頁設計最專業,超強功能平台可客製化

窩窩以「數位行銷」「品牌經營」「網站與應用程式」「印刷品設計」等四大主軸,為每一位客戶客製建立行銷脈絡及洞燭市場先機。

月初我們才剛分享過 CAVIAR 這間來自俄羅斯的客製化品牌的 iPhone 12 Pro 鈦合金潛行款,隨著今年下半年兩款別具話題的產品 AirPods Max 與 PlayStation 5(PS5)開賣後, CAVIAR 這次也將腦筋動到了這兩款產品上。
一如既往, CAVIAR 選用了黃金和鱷魚皮作為客製化版本的材質,當然價格也不是一般消費者能負擔得起的程度,光是相對便宜的黃金版 AirPods Max 就要價約 300 萬元新台幣。

Caviar 推出奢侈黄金版 AirPods Max 、PlayStation 5 ,前者要價 300 萬元起

Caviar 近期宣布將於 2021 年推出度有純金的 AirPods Max ,售價高達 108,000 美元(約合新台幣 304.2 萬元)。據悉這款 AirPods Max 黃金版的耳罩部分將原本的鋁金屬材質改為 18K 金打造,頭帶部分則以鱷魚皮材質取代原本的網狀材質。

CAVIAR 將推出掰色和黑色兩種顏色的鱷魚皮搭配以黃金為主體的 AirPods Max 。雖然 CAVIAR 官方未公布黃金版本的 AirPods Max 機身重量有多重,不過回顧已經不算輕盈的標準版 AirPods Max  重量就有 384.8 公克,黃金版本的重量肯定沈重不少。

耳罩部分包括控制按鈕和旋鈕都以鍍金處理,更提升了整體的奢華感:

價格方面, AirPods Max 黃金版建議售價為 108,000 美元(約合新台幣 304.2 萬元),大約可等同 164 組標準版 AirPods Max 的價位。

與 AirPods Max 建議售價相當的 PlayStation 5 ,也同樣在 CAVIAR 這次黃金版客製化的名單中,黃金版 PS5 一樣採用 18K 黃金材質打造,總共使用了大約 20 公斤的黃金:

與以往 CAVIAR 客製化產品相同, PS5 黃金版主要在外殼上進行重新設計,不僅在機身換上兩塊 3D 打造的 18K 純金實心外殼:

CAVIAR 設計師表示這款 Golden Rock 的 PS5 靈感源自於金礦石的獨特幾何形狀和優美優美的岩石輪廓:

※推薦評價好的iphone維修中心

擁有專業的維修技術團隊,同時聘請資深iphone手機維修專家,現場說明手機問題,快速修理,沒修好不收錢

除此之外,在 Dual Sense 遊戲控制器除了黃金還有加入鱷魚皮等材質:

PS5 黃金版目前 CAVIAR 尚未公開價格,不過光是以黃金價格來估算就能推測他價格將非常驚人。

圖片/消息來源:CAVIAR

延伸閱讀:
iOS 應用小技巧:自動停止播放影片/音樂,睡前喜愛滑手機的人都必學!

Caviar 發表 iPhone 12 Pro 鈦合金「潛行款」,取消所有相機還加三倍價賣

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

台北網頁設計公司這麼多該如何選擇?

網動是一群專業、熱情、向前行的工作團隊,我們擁有靈活的組織與溝通的能力,能傾聽客戶聲音,激發創意的火花,呈現完美的作品

DQN(Deep Q-learning)入門教程(六)之DQN Play Flappy-bird ,MountainCar_台北網頁設計

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

在DQN(Deep Q-learning)入門教程(四)之Q-learning Play Flappy Bird中,我們使用q-learning算法去對Flappy Bird進行強化學習,而在這篇博客中我們將使用神經網絡模型來代替Q-table,關於DQN的介紹,可以參考我前一篇博客:DQN(Deep Q-learning)入門教程(五)之DQN介紹

在這篇博客中將使用DQN做如下操作:

  • Flappy Bird
  • MountainCar-v0

再回顧一下DQN的算法流程:

項目地址:Github

MountainCar-v0

MountainCar的訓練好的Gif示意圖如下所示,汽車起始位置位於山的底部,最終目標是駛向右邊山的插旗的地方,其中,汽車的引擎不能夠直接駛向終點,必須藉助左邊的山體的重力加速度才能夠駛向終點。

MountainCar-v0由OpenAI提供,python包為gym,官網網站為https://gym.openai.com/envs/MountainCar-v0/。在Gym包中,提供了很多可以用於強化學習的環境(env):

在MountainCar-v0中,狀態有2個變量,car position(汽車的位置),car vel(汽車的速度),action一共有3種 Accelerate to the Left Don't accelerateAccelerate to the Right,然後當車達到旗幟的地方(position = 0.5)會得到\(reward = 1\)的獎勵,如果沒有達到則為\(-1\)。但是如果當你運行步驟超過200次的時候,遊戲就會結束。詳情可以參考源代碼(ps:官方文檔中沒有這些說明)。

下面介紹一下gym中幾個常用的函數:

  • env = gym.make("MountainCar-v0")
    

    這個就是創建一個MountainCar-v0的遊戲環境。

  • state = env.reset()
    

    重置環境,返回重置后的state

  • env.render()
    

    將運行畫面展示在屏幕上面,當我們在訓練的時候可以不使用這個來提升速度。

  • next_state, reward, done, _ = env.step(action)
    

    執行action動作,返回下一個狀態,獎勵,是否完成,info。

初始化Agent

初始化Agent直接使用代碼說明吧,這個還是比較簡單的:

import keras
import random
from collections import deque

import gym
import numpy as np
from keras.layers import Dense
from keras.models import Sequential


class Agent():
    def __init__(self, action_set, observation_space):
        """
        初始化
        :param action_set: 動作集合
        :param observation_space: 環境屬性,我們需要使用它得到state的shape
        """
        # 獎勵衰減
        self.gamma = 1.0
        # 從經驗池中取出數據的數量
        self.batch_size = 50
        # 經驗池
        self.memory = deque(maxlen=2000000)
        # 探索率
        self.greedy = 1.0
        # 動作集合
        self.action_set = action_set
        # 環境的屬性
        self.observation_space = observation_space
        # 神經網路模型
        self.model = self.init_netWork()

    def init_netWork(self):
        """
        構建模型
        :return: 模型
        """
        model = Sequential()
        # self.observation_space.shape[0],state的變量的數量
        model.add(Dense(64 * 4, activation="tanh", input_dim=self.observation_space.shape[0]))
        model.add(Dense(64 * 4, activation="tanh"))
        # self.action_set.n 動作的數量
        model.add(Dense(self.action_set.n, activation="linear"))
        model.compile(loss=keras.losses.mean_squared_error,
                      optimizer=keras.optimizers.RMSprop(lr=0.001))
        return model

我們使用隊列來保存經驗,這樣的話新的數據就會覆蓋遠古的數據。此時我們定義一個函數,專門用來將數據保存到經驗池中,然後定義一個函數用來更新\(\epsilon\)探索率。

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

def add_memory(self, sample):
    self.memory.append(sample)

def update_greedy(self):
    # 小於最小探索率的時候就不進行更新了。
    if self.greedy > 0.01:
        self.greedy *= 0.995

訓練模型

首先先看代碼:

def train_model(self):
    # 從經驗池中隨機選擇部分數據
    train_sample = random.sample(self.memory, k=self.batch_size)

    train_states = []
    next_states = []
    for sample in train_sample:
        cur_state, action, r, next_state, done = sample
        next_states.append(next_state)
        train_states.append(cur_state)

    # 轉成np數組
    next_states = np.array(next_states)
    train_states = np.array(train_states)
    # 得到next_state的q值
    next_states_q = self.model.predict(next_states)

    # 得到state的預測值
    state_q = self.model.predict_on_batch(train_states)

    # 計算Q現實
    for index, sample in enumerate(train_sample):
        cur_state, action, r, next_state, done = sample
        if not done:
            state_q[index][action] = r + self.gamma * np.max(next_states_q[index])
        else:
            state_q[index][action] = r
    
    self.model.train_on_batch(train_states, state_q)

大家肯定從上面的代碼發現一些問題,使用了兩個for循環,why?首先先說一下兩個for循環分別的作用:

  • 第一個for循環:得到train_statesnext_states,其中next_states是為了計算Q現實。
  • 第二個for循環:計算Q現實

可能有人會有一個疑問,為什麼我不寫成一個for循環呢?實際上寫成一個for循環是完全沒有問題的,很,但是寫成一個for循環意味着我們要多次調用model.predict_on_batch,這樣會耗費一定的時間(親身試驗過,這樣會比較慢),因此,我們寫成了兩個for循環,然後只需要調用一次predict

執行動作與選擇最佳動作

執行動作的代碼如下所示:

def act(self, env, action):
    """
    執行動作
    :param env: 執行環境
    :param action: 執行的動作
    :return: ext_state, reward, done
    """
    next_state, reward, done, _ = env.step(action)

    if done:
        if reward < 0:
            reward = -100
        else:
            reward = 10
    else:
        if next_state[0] >= 0.4:
            reward += 1

    return next_state, reward, done

其中,我們可以修改獎勵以加快網絡收斂。

選擇最好的動作的動作如下所示,會以一定的探索率隨機選擇動作。

def get_best_action(self, state):
    if random.random() < self.greedy:
        return self.action_set.sample()
    else:
        return np.argmax(self.model.predict(state.reshape(-1, 2)))

開始訓練

關於具體的解釋,在註釋中已經詳細的說明了:

if __name__ == "__main__":
    # 訓練次數
    episodes = 10000
    # 實例化遊戲環境
    env = gym.make("MountainCar-v0")
    # 實例化Agent
    agent = Agent(env.action_space, env.observation_space)
    # 遊戲中動作執行的次數(最大為200)
    counts = deque(maxlen=10)

    for episode in range(episodes):
        count = 0
        # 重置遊戲
        state = env.reset()

        # 剛開始不立即更新探索率
        if episode >= 5:
            agent.update_greedy()

        while True:
            count += 1
            # 獲得最佳動作
            action = agent.get_best_action(state)
            next_state, reward, done = agent.act(env, action)
            agent.add_memory((state, action, reward, next_state, done))
            # 剛開始不立即訓練模型,先填充經驗池
            if episode >= 5:
                agent.train_model()
            state = next_state
            if done:
                # 將執行的次數添加到counts中
                counts.append(count)
                print("在{}輪中,agent執行了{}次".format(episode + 1, count))

                # 如果近10次,動作執行的平均次數少於160,則保存模型並退出
                if len(counts) == 10 and np.mean(counts) < 160:
                    agent.model.save("car_model.h5")
                    exit(0)
                break

訓練一定的次數后,我們就可以得到模型了。然後進行測試。

模型測試

測試的代碼沒什麼好說的,如下所示:

import gym
from keras.models import load_model
import numpy as np
model = load_model("car_model.h5")

env = gym.make("MountainCar-v0")

for i in range(100):
    state = env.reset()
    count = 0
    while True:
        env.render()
        count += 1
        action = np.argmax(model.predict(state.reshape(-1, 2)))
        next_state, reward, done, _ = env.step(action)
        state = next_state
        if done:
            print("遊戲的次數:", count)
            break

部分的結果如下:

Flappy Bird

FlappyBird的代碼我就不過多贅述了,裏面的一些函數介紹可以參照這個來看:DQN(Deep Q-learning)入門教程(四)之Q-learning Play Flappy Bird,代碼思想與訓練Mountain-Car基本是一致的。

import random
from collections import deque

import keras
import numpy as np
from keras.layers import Dense
from keras.models import Sequential
from ple import PLE
from ple.games import FlappyBird


class Agent():
    def __init__(self, action_set):
        self.gamma = 1
        self.model = self.init_netWork()
        self.batch_size = 128
        self.memory = deque(maxlen=2000000)
        self.greedy = 1
        self.action_set = action_set

    def get_state(self, state):
        """
        提取遊戲state中我們需要的數據
        :param state: 遊戲state
        :return: 返回提取好的數據
        """
        return_state = np.zeros((3,))
        dist_to_pipe_horz = state["next_pipe_dist_to_player"]
        dist_to_pipe_bottom = state["player_y"] - state["next_pipe_top_y"]
        velocity = state['player_vel']
        return_state[0] = dist_to_pipe_horz
        return_state[1] = dist_to_pipe_bottom
        return_state[2] = velocity
        return return_state

    def init_netWork(self):
        """
        構建模型
        :return:
        """
        model = Sequential()
        model.add(Dense(64 * 4, activation="tanh", input_shape=(3,)))
        model.add(Dense(64 * 4, activation="tanh"))
        model.add(Dense(2, activation="linear"))

        model.compile(loss=keras.losses.mean_squared_error,
                      optimizer=keras.optimizers.RMSprop(lr=0.001))
        return model

    def train_model(self):
        if len(self.memory) < 2500:
            return

        train_sample = random.sample(self.memory, k=self.batch_size)
        train_states = []
        next_states = []

        for sample in train_sample:
            cur_state, action, r, next_state, done = sample
            next_states.append(next_state)
            train_states.append(cur_state)
        # 轉成np數組
        next_states = np.array(next_states)
        train_states = np.array(train_states)

        # 得到下一個state的q值
        next_states_q = self.model.predict(next_states)
        # 得到預測值
        state_q = self.model.predict_on_batch(train_states)

        for index, sample in enumerate(train_sample):
            cur_state, action, r, next_state, done = sample
            # 計算Q現實
            if not done:
                state_q[index][action] = r + self.gamma * np.max(next_states_q[index])
            else:
                state_q[index][action] = r
        self.model.train_on_batch(train_states, state_q)

    def add_memory(self, sample):
        self.memory.append(sample)

    def update_greedy(self):
        if self.greedy > 0.01:
            self.greedy *= 0.995

    def get_best_action(self, state):
        if random.random() < self.greedy:
            return random.randint(0, 1)
        else:
            return np.argmax(self.model.predict(state.reshape(-1, 3)))

    def act(self, p, action):
        """
        執行動作
        :param p: 通過p來向遊戲發出動作命令
        :param action: 動作
        :return: 獎勵
        """
        r = p.act(self.action_set[action])
        if r == 0:
            r = 1
        if r == 1:
            r = 100
        else:
            r = -1000
        return r


if __name__ == "__main__":
    # 訓練次數
    episodes = 20000
    # 實例化遊戲對象
    game = FlappyBird()
    # 類似遊戲的一個接口,可以為我們提供一些功能
    p = PLE(game, fps=30, display_screen=False)
    # 初始化
    p.init()
    # 實例化Agent,將動作集傳進去
    agent = Agent(p.getActionSet())
    max_score = 0
    scores = deque(maxlen=10)

    for episode in range(episodes):
        # 重置遊戲
        p.reset_game()
        # 獲得狀態
        state = agent.get_state(game.getGameState())
        if episode > 150:
            agent.update_greedy()
        while True:
            # 獲得最佳動作
            action = agent.get_best_action(state)
            # 然後執行動作獲得獎勵
            reward = agent.act(p, action)
            # 獲得執行動作之後的狀態
            next_state = agent.get_state(game.getGameState())
            agent.add_memory((state, action, reward, next_state, p.game_over()))
            agent.train_model()
            state = next_state
            if p.game_over():
                # 獲得當前分數
                current_score = p.score()
                max_score = max(max_score, current_score)
                scores.append(current_score)
                print('第%s次遊戲,得分為: %s,最大得分為: %s' % (episode, current_score, max_score))
                if len(scores) == 10 and np.mean(scores) > 150:
                    agent.model.save("bird_model.h5")
                    exit(0)
                break

該部分相比較於Mountain-Car需要更長的時間,目前的我還沒有訓練出比較好的效果,截至寫完這篇博客,最新的數據如下所示:

emm,我又不想讓我的電腦一直開着,。

總結

上面的兩個例子便是DQN最基本最基本的使用,我們還可以將上面的FlappyBird的問題稍微複雜化一點,比如說我們無法直接的知道環境的狀態,我們則可以使用CNN網絡去從遊戲圖片入手(關於這種做法,網絡上有很多人寫了相對應的博客)。

項目地址:Github

參考

  • openai-gym
  • MountainCar-v0 ——src code
  • DQN(Deep Q-learning)入門教程(四)之Q-learning Play Flappy Bird

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

UWP開發入門(25)——通過Radio控制Bluetooth, WiFi_網頁設計公司

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

回顧寫了許久的UWP開發入門,竟然沒有講過通過Windows.Devices.Radios.Radio來控制Bluetooth和WiFi等功能的開關。也許是因為相關的API設計的簡單好用,以至於被我給忽略了。最近工作中有涉及這塊的內容,不妨一起來回顧下,順便看看一些新的發現。

在Windows 10以前,想要控制Bluetooth,WiFi等功能,那麻煩大了。得操作ManagementBaseObject,ManagementEventWatcher 等一系列WMI提供的API,寫出來的代碼又臭又長。其間還夾着複雜的WMI query字符串,十分難用。

升級到Windows 10后,我們通過Windows.Devices.Radios.Radio可以方便的獲取控制Bluetooth和WiFi的對象。

var radios = await Radio.GetRadiosAsync();
Bluetooth = radios.FirstOrDefault(r => r.Kind == RadioKind.Bluetooth);
WiFi = radios.FirstOrDefault(r => r.Kind == RadioKind.Bluetooth);

在拿到上面的Bluetooth和WiFi的Radio實例后,就可以通過

Public event TypedEventHandler<Radio, object> StateChanged;

來監聽Radio實例的狀態改變,可以說通過寥寥幾行代碼,就可以替代以往大量繁瑣的操作。

而設置Bluetooth和WiFi設備On/Off的狀態,也非常簡單。

public IAsyncOperation<RadioAccessStatus> SetStateAsync(RadioState value);

RadioState枚舉如同字面的意思:

    public enum RadioState
    {
        //
        // Summary:
        //     The radio state is unknown, or the radio is in a bad or uncontrollable state.
        Unknown = 0,
        //
        // Summary:
        //     The radio is powered on.
        On = 1,
        //
        // Summary:
        //     The radio is powered off.
        Off = 2,
        //
        // Summary:
        //     The radio is powered off and disabled by the device firmware or a hardware switch
        //     on the device.
        Disabled = 3
    }

這裏需要提一下的是,在第一次更改狀態前,UWP APP需要向用戶申請權限。

慢着慢着,貌似忘記給UWP APP向Windows要權限了,我們要編輯Package.aaxmanifest文件,在Capabilities節點加上DeviceCapability這一行才行。

  <Capabilities>
    <Capability Name="internetClient" />
    <DeviceCapability Name="radios"></DeviceCapability>
  </Capabilities>

 

這回運行起來,才真的可以操作Bluetooth和WiFi了。

是不是覺得幾行代碼就能寫出一個控制Bluetooth和WiFi的APP了?事實也確實如此。

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

如果人生只如初見那般美好,UWP的處境就不會如此難堪了。對於某軟提供了完善UWP API的功能,開發起來那是一個爽快。但要是沒有或是沒來得及提供,UWP就顯得頗為尷尬了。

我們不妨看下RadioKind的枚舉,很顯然如果想操作FM radio就得另尋他法。而MobileBoardband即Cellular也是從1703版本才開始得到支持。

那是不是意味這MobileBroadband就可以像Bluetooth和WiFi一樣通過

public static IAsyncOperation<IReadOnlyList<Radio>> GetRadiosAsync();

來獲取實例對象了,還真不是,欲知如何操作,且聽下回《UWP開發入門(26)——通過Radio控制Cellular》。

實際是我Sample code還沒整理好。所以分成了兩篇來寫。

有感日前MS Store里的網易雲音樂UWP也被替換成Win32版本,可嘆國產的UWP APP越來越少。某軟畫了個好餅,可惜不能讓人在Windows生態上通過UWP掙到錢。好技術生不逢時出不了頭,真是可惜。

同時也能感覺到某軟的妥協和進步,現如今的UWP,結合desktop extension以及desktop bridge技術。只要公司的APP能通過某軟的審核,功能方面已經無限接近傳統desktop APP了。可惜一個Windows平台做Win32和UWP兩個產品,燒的錢可不是小數目。總不能用愛發電吧。

希望Win7早日被淘汰,WinUI 3.0能進一步融合UWP和Win32。距離上一次某軟說要重振desktop開發已經過去蠻久了。

本篇提到的相關Sample code在GitHub:

https://github.com/manupstairs/UWPSamples/tree/master/UWPSamples/RadioDevice

 

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

為什麼國產品牌SUV能贏合資品牌?你買車會選誰?_網頁設計

網頁設計最專業,超強功能平台可客製化

窩窩以「數位行銷」「品牌經營」「網站與應用程式」「印刷品設計」等四大主軸,為每一位客戶客製建立行銷脈絡及洞燭市場先機。

從是否引入全新車型,合資品牌內部便要經過長時間的項目討論。出於商業上的原因,合資品牌的外資方對於新車型的引入,是持極其謹慎的態度的。所以,儘管合資品牌的中方人員已經意識到這一問題,但往往也是處於干著急的情況,畢竟中方在大部分的情況下,是沒有獨立開發新車型的權力的。

根據乘聯會公布的數據显示,2016年上半年,國內SUV銷量共計391.5萬輛。而中國自主品牌以56.6%的絕對性優勢,成功稱霸了這個時下國內最為火熱的汽車細分市場。在上半年SUV銷量前10排名中,自主品牌共佔到了6個席位。這就不禁讓人有一個疑問:合資品牌SUV為什麼會一敗塗地?

SUV市場的火熱

是合資品牌做夢都沒有想到的

2003年,國內的SUV銷量僅為9.74萬輛,連如今哈弗H6半年的銷量都達不到。但十年過後的2013年,國內的SUV銷量迅速膨脹至266.13萬輛,堪稱是火箭式的增長。對於多年來一直注重發展轎車市場的合資品牌來說,SUV市場誇張式的增長以及市場規模的龐大程度一直是一件讓它們難以相信的事情。這種對市場形勢的誤判,為合資品牌在SUV市場上的糟糕市場表現埋下了深深的伏筆。

十個手指頭能數完的合資SUV

早在1994年的日內瓦車展上,豐田便發布了被譽為“城市SUV鼻祖”的SUV車型—RAV4。比越野車更時尚的外觀,比普通轎車能寬裕的空間,比轎車略為優秀的通過能力,從全世界的範圍來說,SUV都是一種具有深深吸引力的車型。但可惜的是,消費者對於SUV的追捧,並沒有讓合資品牌加深在SUV車型上的研發,特別是針對中國市場。

直至8年之後,也就是2002年,才有了第一款國產的合資SUV—東風本田CRV的出現。這8年間,竟然沒有一家合資品牌在中國市場推出一款SUV車型,這是一件如今讓人無法相信的事情。而即便有了第一款國產合資SUV的出現,但合資品牌對於中國的SVU市場依舊沒有太多的重視。即便是在中國汽車市場具有絕對品牌影響力的大眾汽車,把途觀引入國內生產的時間已經是2009年的事情。

自主品牌已經贏在了起跑線上

相反,不少的自主品牌已經在SUV真槍實彈地幹了起來。譬如,大家眾所周知的雙環汽車(沒錯,就是那家被本田告上法庭,還反坑本田1600萬元賠償的雙環汽車),在2004年便山寨本田的CRV,推出了大名鼎鼎的雙環SRV。而如今國內SUV的銷量冠軍—長城汽車,在2002年也依靠皮卡的平台基礎,生產出了自家的第一款SUV—長城賽弗。更不要說具有傳奇色彩,賣到南美市場的奇瑞瑞虎。所以說,從第一步棋開始,

※推薦評價好的iphone維修中心

擁有專業的維修技術團隊,同時聘請資深iphone手機維修專家,現場說明手機問題,快速修理,沒修好不收錢

合資品牌便已經輸在了起跑線上。

合資品牌龜速一樣的產品研發

意識到落後的合資品牌開始奮力直追,但要知道合資車企的內部運營遠沒有自主品牌靈活。從是否引入全新車型,合資品牌內部便要經過長時間的項目討論。出於商業上的原因,合資品牌的外資方對於新車型的引入,是持極其謹慎的態度的。

所以,儘管合資品牌的中方人員已經意識到這一問題,但往往也是處於干著急的情況,畢竟中方在大部分的情況下,是沒有獨立開發新車型的權力的。在確定要引入全新的SUV車型以後,還要進行一定的本土化適配、車輛測試等長時間的流程。比如國內著名的合資品牌–X安X特的一款SUV,整車試驗的流程,便有4000多項。所以,目前合資品牌的SUV研發以及生產的速度,完全可以用緩慢去形容。

自主品牌的地頭蛇優勢

但相比合資品牌,自主品牌完全就是地頭蛇一般的靈活。依靠國外成熟的SUV進行逆向研發,大大縮小研發所需的研發。再通過三菱、愛信等成熟的零部件供應商,完成最核心的動力組裝。當然,自主品牌不但在產品的設計、製造有着相當的速度優勢。在推出全新車型的決策上,同樣具有優勢。譬如國內的某知名的自主品牌,自今年3月推出緊湊型SUV以來,依次又在5月、8月,相繼發布了兩款全新的緊湊型SUV。新品推出的速度之快,不僅讓業內人士感到詫異,消費者同樣感到詫異。

神一般的速度

更著名的,如漢騰汽車,今年的5月份才宣布完成品牌的發布。僅僅過了4月的時候,旗下的首款緊湊型SUV—漢騰X7便騰空出世。從品牌的構建,到產品的設計研發,再到生產線的投產,漢騰僅用了4個月的時間。這幾乎是世界上任何一家合資品牌都無法完成的事情。

不過,有部分的自主品牌存在過於追求投產速度,希望更早地享受到SUV市場的紅利,而在生產、製造環節存在把控不嚴的情況。也正是這個原因,談到自主SUV,許多的消費者第一時間都會拋出諸如“耐用性怎麼樣?”“小問題多不多”的疑問。這也是這種運作的靈活性給自主品牌帶來的負面影響。

不過儘管合資品牌SUV在產品的投放速度不如自主品牌,但根據相關的數據显示,截止2015年底,17萬以上區間的SUV市場,98%的市場份額依然由合資品牌所垄斷。而自主品牌主要活躍在中端(13-17萬)、次中端(9-13萬)、低端(9萬以下)等SUV市場。也就是說,儘管自主品牌佔據了SUV的大部分市場份額,但更具有盈利能力的高端SUV市場依然是合資品牌的天下。如何在保障銷量漂亮的同時,改善產品的質量,以及提高自身品牌在高端SUV市場的影響力,是目前自主品牌亟待需要思考的問題。

本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

台北網頁設計公司這麼多該如何選擇?

網動是一群專業、熱情、向前行的工作團隊,我們擁有靈活的組織與溝通的能力,能傾聽客戶聲音,激發創意的火花,呈現完美的作品

火樹銀花_台北網頁設計

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

本站聲明:網站內容來http://www.societynews.cn/html/wh/fq/,如有侵權,請聯繫我們,我們將及時處理

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

南澗跳菜為節日添彩_網頁設計公司

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

  跳菜之猴子嬉鬧。
  適志宏攝

  跳菜之空手疊塔。
  適志宏攝

  “南澗跳菜”又被叫做“抬菜舞”或者“捧盤舞”,將舞蹈、音樂與雜技、飲食融為一體,是雲南南澗彝族自治縣群眾流傳已久的習俗。彝族跳菜2008年被列入第二批國家級非物質文化遺產名錄。

  “跳菜有‘宴席跳菜’和‘表演跳菜’兩種形式。‘表演跳菜’主要是在舞台上,菜不是真菜,主要是通過舞蹈和音樂來表現。我們日常做的主要是‘宴席跳菜’,抬的是真菜,這是每一次宴席慶典的必備儀式,往往是我們接待賓客的最高禮節。”跳菜隊隊長張玉香說。

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

  音樂聲響,張玉香和另一位隊員從廚房跳出,一人在前面引舞護菜,另一人在後面舞着托盤,兩人踏着節拍登場。輕快敏捷的舞步,幽默逗人的扮相,混着激昂的嗩吶聲,引起現場陣陣歡笑。

  “口功送菜”和“空中送菜”是張玉香的拿手絕技。在村裡跳菜,還有許多套路,張玉香說:“不管採用什麼樣的形式,最關鍵的就是保證把這些寓意吉祥的菜平平穩穩地上到桌上。”

  在舞姿的變化中,跳菜隊員們利落地把菜擺放到桌上。不僅跳舞有講究,擺菜的形式也很講究。“梅花形是我們常用的擺法,等這些農家菜上齊了,大家就可以一起享受這些美味佳肴啦。”張玉香說。

  版式設計:蔡華偉 張丹峰

本站聲明:網站內容來http://www.societynews.cn/html/wh/fq/,如有侵權,請聯繫我們,我們將及時處理

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

Sony Mobile 新旗艦 Xperia 1 III 爆料規格曝光:將搭載 S888 處理器、4K HDR 螢幕亮度提升_網頁設計

網頁設計最專業,超強功能平台可客製化

窩窩以「數位行銷」「品牌經營」「網站與應用程式」「印刷品設計」等四大主軸,為每一位客戶客製建立行銷脈絡及洞燭市場先機。

在首款搭載高通 Snapdragon 888 處理器的小米11 推出後,接下來在 2021 年包括華碩、黑鯊、聯想、LG、魅族、motorola、nubia、realme、OnePlus、OPPO、Sharp、vivo 與 ZTE 都確定將成為首批搭載的的手機品牌。而近期網傳 Sony Mobile  接下來的 Xperia 1 系列新旗艦 Xperia 1 III 也可能會搭載此處理器。

▲示意圖,圖為 Xperia 1 II

Sony Mobile 新旗艦 Xperia 1 III 爆料規格曝光:將搭載 S888 處理器、4K HDR 螢幕亮度提升

Sony Mobile 今年在台灣推出包括 Xperia 1 II 以及 Xperia 5 II 兩款旗艦級手機,而根據往年在 MWC(Mobile World Congress)也都會發表新機。然而受到疫情影響,接下來在 2021 年也還有許多變數。不過最近在 Twitter 也有人開始爆料 Xperia 1 系列下一代旗艦新機 Xperia 1 III(暫稱)的規格。

▲示意圖,圖為 Xperia 1 II

爆料指出 Xperia 1 III 將一樣採用 6.5 吋 4K OLED HDR 螢幕,不過螢幕亮度部分將比起 Xperia 1 II 提升 15% 。硬體規格方面,也機搭載高通 Snapdragon 888  5G 處理器、配備 8GB RAM 和 256GB ROM 。指紋辨識也延續採用側邊指紋辨識的方式,全機也支持 IP65/IP68 防塵防水等級。

▲示意圖,圖為 Xperia 1 II

而爆料尚未提到 Sony 一直以來強調的相機拍攝功能,若沒意外這次應繼續和蔡司認證的鏡頭,在相機鏡頭搭配、拍攝穩定性、夜拍方面進行升級。

▲示意圖,圖為 Xperia 1 II

不過爆料則有提到 Xperia 1 III 可能的售價,傳聞為 1,199 美元起(約合新台幣 33,770 元)。

▲圖片來源:Anthony (Twitter/@TheGalox_)

消息來源:Anthony (Twitter/@TheGalox_)

台北網頁設計公司這麼多該如何選擇?

網動是一群專業、熱情、向前行的工作團隊,我們擁有靈活的組織與溝通的能力,能傾聽客戶聲音,激發創意的火花,呈現完美的作品

延伸閱讀:
realme 7 5G 開箱動手玩|天璣 800U 處理器、5G+5G 雙卡雙待、120Hz 更新率螢幕、5000mAh大電量與 30W Dart 閃充,萬元內 5G 超值選擇

小米11 Pro 傳聞規格首次曝光:預計 2021 上半年推出, Redmi K11 將為同期最便宜 S888 旗艦新機之一

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※推薦評價好的iphone維修中心

擁有專業的維修技術團隊,同時聘請資深iphone手機維修專家,現場說明手機問題,快速修理,沒修好不收錢

Node.js躬行記(2)——文件系統和網絡_台北網頁設計

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

一、文件系統

  fs模塊可與文件系統進行交互,封裝了常規的POSIX函數。POSIX(Portable Operating System Interface,可移植操作系統接口)是UNIX系統的一個設計標準。fs模塊提供了多個操作目錄和文件的方法,大多會有同步和異步兩種版本,同步的方法名稱會以Sync為後綴。

1)目錄處理

  fs模塊的readdir()方法可異步的讀取目錄內容,回調函數包含兩個參數,第一個是錯誤對象,第二個是一個包含文件名稱的數組,對應的同步方法是readdirSync()。在下面的示例中,當前目錄包含兩個文件,上一級目錄包含一個目錄名稱。

const fs = require('fs');
fs.readdir('./', (err, files) => {
  console.log(files);        //[ 'demo.txt', 'index.js' ]
});
fs.readdir('../', (err, files) => {
  console.log(files);        //[ '1' ]
});

  其它處理目錄的方法還有opendir()、mkdir()等。

2)讀寫文件

  在fs模塊中,可使用批量方法readFile()將文件內容一次性的加載到內存中,如下所示。

const fs = require('fs');
fs.readFile('./origin.txt', (err, buf) => {
  console.log(buf.toString());        //"hello Node.js"
});

  對應的寫入方法是writeFile(),如下所示,文件路徑、寫入內容和回調函數是必傳的參數。如果文件不存在,那麼會自動創建。

fs.writeFile('./target.txt', 'hello Node.js', (err) => {
  if (err) throw err;
  console.log('文件已被保存');
});

  當文件很大時,像上面這樣直接讀取會有問題,可以改用流式方法createReadStream(),分批次的讀取文件,如下所示,每次只讀7個字節的內容。

const readable = fs.createReadStream('./origin.txt', {highWaterMark: 7});
readable.on("data", (chunk) => {
  /*************/
  /* "hello N"
  /* "ode.js"
  /************/
  console.log(chunk.toString());
});

  通過管道方法pipe()將origin.txt中的內容寫入到target-stream.txt中,如下所示,對於不存在的文件,也會自動創建。

const writable = fs.createWriteStream('./target-stream.txt');
readable.pipe(writable);

3)文件描述

  fs模塊的stat()方法可讀取文件的描述信息,如下所示。

fs.stat('./demo.txt', (err, stats) => {
  console.log(stats);
});

  回調函數中的stats參數是一個fs.Stats對象,其屬性如下所示。它還包含一些判斷方法,例如isDirectory()、isFile()等。

Stats {
  dev: 195650,
  mode: 33206,
  nlink: 1,
  uid: 0,
  gid: 0,
  rdev: 0,
  blksize: undefined,
  ino: 36873221949682120,
  size: 13,
  blocks: undefined,
  atimeMs: 1586227933993.0217,
  mtimeMs: 1585882949091.0166,
  ctimeMs: 1586227933995.0222,
  birthtimeMs: 1586227933993.0217,
  atime: 2020-04-07T02:52:13.993Z,
  mtime: 2020-04-03T03:02:29.091Z,
  ctime: 2020-04-07T02:52:13.995Z,
  birthtime: 2020-04-07T02:52:13.993Z
}

  fs模塊還提供了fstat()方法,在功能上與stat()等價,只是fstat()方法的第一個參數是文件描述符。在POSIX系統中,文件描述符是一個正整數,它實際上是一個索引值,指向內核為每一個進程所維護的該進程打開文件的記錄表。當打開或創建一個文件時,就會被分配一個文件描述符。

  在下面的示例中,open()方法的回調函數中包含一個fd參數(即文件描述符),搭配fstat()方法就能讀取文件信息。

fs.open('./demo.txt', 'r', (err, fd) => {
  fs.fstat(fd, (err, stats) => {
    console.log(stats);
  });
});

4)監控文件

  fs模塊提供了兩種方法來監控文件:watch()和watchFile(),前者能監控文件或目錄的更改,後者只能監控文件的更改。

  watch()方法的監聽器回調包含兩個參數,第一個是事件類型(包括rename和change),第二個是觸發事件的文件名稱,如下所示。

fs.watch('./demo.txt', (eventType, filename) => {
  console.log(eventType, filename);
});

  執行node命令后,每次更改demo.txt文件,就會在控制台打印出下面這條語句。

$ node index.js
change demo.txt

  雖然watch()方法的性能優於watchFile()方法,但是watch()不是一個跨平台的方法,其表現在各個平台中並非百分百一致(例如filename參數不能保證提供),而watchFile()是跨平台的。

5)異步文件

  fs.promises是Node提供的一組備用的異步文件系統方法,它們會返回Promise對象而不是通過回調來處理結果。例如以Promise的方式使用stat()方法,如下所示。

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

const fsPromises = require('fs').promises;
fsPromises.stat('./demo.txt').then(stats => {
  console.log(stats);
});

二、網絡

  Node可以處理的網絡協議包括HTTP、TCP、HTTPS等,本節將會重點分析HTTP協議。Node中的http模塊基於net、stream、events等模塊,提供了一系列的網絡傳輸的底層API,可創建HTTP服務器和客戶端,包含重定向、代理、上傳數據等功能。

1)HTTP服務器

  通過http.createServer()方法就能創建HTTP服務器,其內部會調用net.Server()方法,返回一個http.Server實例。當服務被創建后,就能通過server.listen()方法監聽一個端口。

  在下面的示例中,監聽的端口是8000,createServer()的回調函數包含兩個參數:req和res,分別表示HTTP的請求和響應,前者是IncomingMessage類(一個可讀流)的實例,後者是ServerResponse類(一個可寫流)的實例。__dirname是一個全局變量,保存着當前文件所處的路徑。

const http = require('http'); 
const fs = require('fs'); 
const server = http.createServer(function (req, res) {
  fs.readFile(__dirname + "/index.html", function (err, data) {
    if (err) {
      res.statusCode = 500;
      res.end(String(err));
    } else {
      res.end(data);
    }
  });
}).listen(8000);

  在回調函數中,可修改或解析響應報文,例如像上面當發生錯誤時,將狀態碼改成500。在瀏覽器中訪問http://localhost:8000,就能通過end()方法在頁面中輸出index.html的文件內容。

  注意,必須調用響應對象的end()方法結束此次響應,如果省略,那麼頁面將會一直處於加載中,阻塞內容渲染。

  http.Server包含一組事件,例如connection和request,如下所示。前者會在建立新的TCP流時觸發,後者會在每次請求服務器時觸發。

server.on("connection", function (socket) {
  console.log(connection");
});
server.on("request", function (req, res) {
  console.log('request');
});

2)重定向

  3XX格式的狀態碼用於重定向,例如在Node中實現302跳轉,如下所示。

http.createServer(function (req, res) {
  if(req.url == '/strick') {
    res.writeHead(302, {'Location': 'http://www.pwstrick.com'});
  }
  res.end();
}).listen(8000);

  當瀏覽器訪問http://localhost:8000/strick時,才會執行重定向。writeHead()方法可一次性設置響應的狀態碼和所有的首部。如果只想設置單個響應首部,可以使用setHeader()方法。

3)上傳數據

  在實際的業務開發中,免不了上傳數據的需求,例如表單提交、圖像上傳等。下面是一張form表單,包含一個文本框和一個提交按鈕。

<form action="http://localhost:8000" method="post">
  <input type="text" name="name" />
  <button type="submit">提交</button>
</form>

  點擊提交按鈕,會將整張表單提交到HTTP服務器(代碼如下所示),假設文本框中輸入的內容為“咖啡機strick”。

const http = require('http');
const querystring = require('querystring');

const server = http.createServer(function (req, res) {
  //聲明Content-Type響應首部,以免中文亂碼
  res.setHeader("Content-Type", "application/json; charset=utf-8");
  const arr = [];
  req.on("data", chunk => {
    arr.push(chunk);
  });
  req.on("end", () => {
    const buf = Buffer.concat(arr);        //拼接Buffer數據
    const params = querystring.decode(buf.toString());
    console.log(params.name);             //"咖啡機strick"
    res.write(JSON.stringify(params));    //響應數據
    res.end();
  });
}).listen(8000);

  在data事件中接收數據並添加到arr數組中,然後在end事件中由Buffer.concat()方法拼接Buffer數據。querystring模塊的decode()方法可將查詢字符串解析成一個對象。write()方法會將響應數據發送給客戶端。

4)客戶端服務

  http模塊提供了request()方法,可讓客戶端向服務器發起請求。在下面的示例中,postData變量是要發送的數據,options變量是各種配置參數,包括請求首部的信息。

const http = require('http'); 
const querystring = require('querystring');

const postData = querystring.stringify({
  'name': '咖啡機strick'
});
const options = {
  hostname: 'localhost',
  port: 8000,
  path: '/',
  method: 'POST',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
    'Content-Length': Buffer.byteLength(postData)
  }
};
const req = http.request(options, (res) => {
  const code = res.statusCode;                    //狀態碼
  const headers = JSON.stringify(res.headers);       //響應首部
  res.setEncoding('utf8');         //為可讀流設置字符編碼
  res.on('data', (chunk) => {
    console.log(chunk);            //響應數據
  });
  res.on('end', () => {
    console.log('響應中已無數據');
  });
});
req.write(postData);
req.end();

  注意,在請求最後需要調用end()方法,結束本次請求。Node還提供了一個基於request()的便捷方法:get(),它會自動調用req.end()方法,並且請求方法是GET。

5)代理

  代理是一種特殊的網絡服務,允許一個客戶端通過這個服務與目標服務器進行間接的連接,也就是在它們之間建立了一層中轉,可用來過濾廣告、控制內部資源的訪問權限、保障終端的隱私或安全等。

  http模塊可搭建出一個簡易的HTTP代理服務器,下面示例引用自《Node.js硬實戰》技巧52一節。

const http = require('http');
const url = require('url');
http.createServer(function (req, res) {
  const options = url.parse(req.url);  //一個URL對象
  options.headers = req.headers;
  
  req.on('data', chunk => {            //將請求的原始數據發送給代理
    proxyRequest.write(chunk);
  });
  req.on('end', chunk => {             //完成原始請求
    proxyRequest.end();
  });
  
  //複製原始請求
  const proxyRequest = http.request(options, proxyResponse => {
    proxyResponse.on('data', chunk => {    //將響應的原始數據發送給客戶端
      res.write(chunk);
    });
    proxyResponse.on('end', chunk => {     //完成代理請求
      res.end();
    });
    //將響應報文發送給客戶端
    res.writeHead(proxyResponse.statusCode, proxyResponse.headers);
  });
}).listen(8000);

  url模塊的parse()方法能將字符串轉換成一個URL對象。在綁定請求對象的data事件后,就能將客戶端的請求數據發送給代理。通過http.request()方法發起一次代理請求,並將服務器的響應數據發送給客戶端。

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

第四篇-用Flutter手擼一個抖音國內版,看看有多炫_網頁設計公司

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

前言

這次對布局進行優化,主要包含了首頁tabview pageview 以及添加幾個按鈕的操作過程.主要使用到stack層疊布局,tabpview和pageview,tabview兩個頁面,一個關注,一個推薦,左右切換,pageview被包含在tabview裏面.

布局優化

抖音的頂部appbar 是懸浮層疊展示,而flutter的層疊組件是stack, 因此最外面採用stack, 其次中間是tabview,分別是關注和推薦兩個選項卡,關注在沒有登錄的時候會彈出一個提示需要認證登錄的頁面,這裏加了兩個頁面,subscriptionScreen.dart,另外一個是loginScreen.dart

 @override
  Widget build(BuildContext context) {
    return Scaffold(
      //backgroundColor: Colors.transparent,
      body: Stack(
        //fit: StackFit.expand,
        children: <Widget>[
          TabBarView(
            controller: _tabController,
            children: <Widget>[
              Subscription(),
              PageView(
                allowImplicitScrolling: true,
                controller: _pageController,
                children: <Widget>[
                  Trending(),
                ],
                onPageChanged: (int index) {
                  setState(() {
                    currentIndex = index;
                  });
                },
              ),
            ],
          ),
          Column(
            children: [
              AppBar(
                backgroundColor: Colors.transparent,
                elevation: 0,
                centerTitle: true,
                leading: IconButton(
                    icon: Icon(Icons.tv),
                    onPressed: () {
                      print('點擊了直播按鈕');
                    }),
                actions: <Widget>[
                  //導航欄右側菜單
                  IconButton(
                      icon: Icon(Icons.search),
                      onPressed: () {
                        print('點擊了搜索按鈕');
                      }),
                ],
                title: TabBar(
                  indicator: UnderlineTabIndicator(
                      borderSide: BorderSide(width: 2.0, color: Colors.white),
                      insets: EdgeInsets.symmetric(horizontal: 18.0)),
                  labelStyle: TextStyle(fontSize: 18),
                  isScrollable: true,
                  controller: _tabController,
                  tabs: toptabs,
                  onTap: (index) {
                    print(index);
                  },
                ),
              )
            ],
          ),
        ],
      ),
      bottomNavigationBar: bottomItems(),
    );
  }

  

底部彈出提示認證頁面

在 onTap 方法里

Scaffold.of(context).showBottomSheet<void>((BuildContext context) {
          return Login();
        });

BottomSheet 是一個底部滑出的組件

new BottomSheet(
    onClosing: () {},
    builder: (BuildContext context) {
        return new Text('aaa');
    },
),

通常很少直接使用 BottomSheet 而是使用 showModalBottomSheet。直接時候的時候看到的知識 builder 里的內容。

Future<T> showModalBottomSheet <T>({
    @required BuildContext context,
    @required WidgetBuilder builder
});

看一個示例

new MaterialButton(
    color: Colors.blue,
    child: new Text('點我'),
    onPressed: () {
        showModalBottomSheet(
            context: context,
            builder: (BuildContext context) {
                return new Container(
                    height: 300.0,
                    child: new Image.network(this.imgurl),
                );
            },
        ).then((val) {
            print(val);
        });
 

 

 具體詳細介紹參考官網.

 

 

關注頁面

 

 整個頁面布局,左右都有邊距,頂部也有邊距,所有採用Container包含,邊距使用padding: EdgeInsets.only(top: 150.0, left: 65.0, right: 65.0),  背景顏色 color: Color.fromRGBO(14, 15, 26, 1),依次image,另外使用sizebox佔用空間,

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

其他的中間層都是居中,所以採用center都是居中,另外登錄按鈕是佔滿屏幕的,所以也採用SizeBox,並且把width:設置為double.infinity,這樣就佔滿屏幕,button採用默認的RaisedButton,在button的onpressed事件調用showBottomSheet

import 'package:flutter/material.dart';
import 'package:flutter_app/Screens/loginScreen.dart';

class Subscription extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _SubscriptionState();
}

class _SubscriptionState extends State<Subscription>
    with TickerProviderStateMixin {
  final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.only(top: 150.0, left: 65.0, right: 65.0),
      color: Color.fromRGBO(14, 15, 26, 1),
      child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Image(image: AssetImage("assets/images/int_1581491273221.png")),
            SizedBox(height: 20),
            Center(
              child: Text(
                '你還沒有登錄',
                style: TextStyle(
                    color: Colors.white,
                    fontSize: 20.0,
                    fontWeight: FontWeight.w400),
              ),
            ),
            SizedBox(height: 10),
            Center(
              child: Text(
                '登錄賬號,查看你關注的精彩內容',
                style: TextStyle(
                    color: Color.fromRGBO(253, 253, 253, 0.6),
                    fontSize: 14.0,
                    fontWeight: FontWeight.w400),
              ),
            ),
            SizedBox(height: 20),
            SizedBox(
              width: double.infinity,
              child: RaisedButton(
                color: Color.fromRGBO(252, 1, 86, 1),
                child: Text(
                  '登錄',
                  style: TextStyle(color: Colors.white),
                ),
                onPressed: () {
                  Scaffold.of(context)
                      .showBottomSheet<void>((BuildContext context) {
                    return Login();
                  });
                },
              ),
            ),
          ]),
    );
  }
}

 

登錄頁面

布局如下圖:

 

 

這個頁面整體布局頂部,左右都有邊距,因此使用Container比較合適,設置背景顏色為color: Colors.white, 邊距設置為padding:EdgeInsets.only(top: 25.0, left: 25.0, right: 25.0, bottom: 50.0),整體布局採用Column,因為是上下布局,因此Column 設置

crossAxisAlignment: CrossAxisAlignment.start,頂部的布局是左邊一個clear圖標按鈕,右邊一個幫助按鈕,所以使用
Row布局,並且設置Row的mainAxisAlignment: MainAxisAlignment.spaceBetween,這樣就左右布局了,其他依次採用SizeBox佔位, 中間則採用Center來展示文字控件,底部的登錄部分因為包含標籤 超鏈接,所有採用RichText比較合適,包含TextSpan即可.

全部代碼如下:

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';

class Login extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _LoginState();
}

class _LoginState extends State<Login> {
  TapGestureRecognizer _myTapGestureRecognizer;
  @override
  void initState() {
    super.initState();
    _myTapGestureRecognizer = TapGestureRecognizer()
      ..onTap = () {
        launch('https://open.douyin.com/platform');
      };
  }

  @override
  void dispose() {
    _myTapGestureRecognizer.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      padding:
          EdgeInsets.only(top: 25.0, left: 25.0, right: 25.0, bottom: 50.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              IconButton(
                icon: Icon(Icons.clear),
                onPressed: () {
                  Navigator.pop(context);
                },
                color: Colors.black,
              ),
              Text('幫助', style: TextStyle(color: Colors.black)),
            ],
          ),
          SizedBox(
            height: 150.0,
          ),
          Center(
            child: Text('180****2520',
                style: TextStyle(color: Colors.black, fontSize: 38)),
          ),
          Center(
            child: Text('認證服務由中國電信提供',
                style: TextStyle(
                    color: Color.fromRGBO(53, 53, 53, 1), fontSize: 12)),
          ),
          SizedBox(
            height: 50.0,
          ),
          SizedBox(
            width: double.infinity,
            child: RaisedButton(
              color: Color.fromRGBO(252, 1, 86, 1),
              child: Text(
                '本機號碼一鍵登錄',
                style: TextStyle(color: Colors.white),
              ),
              onPressed: () {
                showBottomSheet(
                    context: context, builder: (context) => Login());
              },
            ),
          ),
          SizedBox(
            height: 2.0,
          ),
          SizedBox(
            width: double.infinity,
            child: OutlineButton(
              color: Color.fromRGBO(252, 1, 86, 1),
              child: Text(
                '其他手機號碼登錄',
                style: TextStyle(color: Colors.black),
              ),
              onPressed: () {
                showBottomSheet(
                    context: context, builder: (context) => Login());
              },
            ),
          ),
          SizedBox(
            height: 5.0,
          ),
          Center(
              child: RichText(
            text: TextSpan(
              children: [
                TextSpan(
                  text: '登錄即表明同意',
                  style: TextStyle(color: Color.fromRGBO(53, 53, 53, 0.8)),
                ),
                TextSpan(text: '  '),
                TextSpan(
                  text: '用戶協議',
                  style: TextStyle(color: Color.fromRGBO(0, 164, 219, 0.8)),
                ),
                TextSpan(text: '  '),
                TextSpan(
                  text: '和',
                  style: TextStyle(color: Color.fromRGBO(53, 53, 53, 0.8)),
                ),
                TextSpan(text: '  '),
                TextSpan(
                  text: '隱私政策',
                  style: TextStyle(color: Color.fromRGBO(0, 164, 219, 0.8)),
                ),
              ],
            ),
          )),
          Center(
              child: RichText(
            text: TextSpan(
              children: [
                TextSpan(
                  text: '以及',
                  style: TextStyle(color: Color.fromRGBO(53, 53, 53, 0.8)),
                ),
                TextSpan(text: '  '),
                TextSpan(
                    text: '《中國電信認證服務條款》',
                    style: TextStyle(color: Color.fromRGBO(0, 164, 219, 0.8)),
                    recognizer: _myTapGestureRecognizer),
              ],
            ),
          )),
          Expanded(
              flex: 1,
              child: Center(
                  heightFactor: 25.0,
                  child: Text('其他方式登錄',
                      style:
                          TextStyle(color: Color.fromRGBO(0, 164, 219, 0.8))))),
        ],
      ),
    );
  }
}

變更記錄

本次變更主要體現在首頁的選項卡設計,需要層疊展示,並且透明的採用appbar显示出頂部的關注、推薦按鈕,另外新增了關注頁,登錄頁,並且把底部按鈕以及右邊的按鈕都加上了觸發時間

 

接下來要完成的雙擊心形按鈕點贊,評論頁面,分享頁面,這些都可以採用showmodalbottomsheet方法打開一個底部抽屜頁面

 

還有底部的首頁刷新,消息頁面,拍短視頻頁面,消息頁面,我的個人信息頁面

 

結語

請繼續關注本博客,其他頁面持續更新完成,源碼地址:https://github.com/WangCharlie/douyin,歡迎fork和star,謝謝!!!

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊