2015年1月23日 星期五

[iOS] Apple XCode 6 初體驗

先把設備說一下:

Apple Mac Mini 2.4G這一款 1TB 8G RAM

系統是  : Yosemite 10.10

編譯程式: XCode 6


首先還是先創立一個Hello World 來熟悉一下介面


Main.storyboard 負責介面,介面上有任何問題就是看這個檔案


   接下來就是像android 一樣 你在xml檔上面建立的東西 要讓程式知道,所以按著control

   鍵拖曳到程式碼那邊就可以完成宣告了


   顯示出來就是長這樣


負責動作的部份是在  ViewController.m ( like onCreate, onPause)

負責宣告的部分則是在ViewController.h ( 介面--程式碼連結)


**這邊紀錄一下一開始在測試的時候模擬器都是黑屏,搞得很煩

最後解決方式是重新建立一個Project,不然一直有thread1:signal sigabrt 錯誤



大概就是這樣, Apple的開發跟Google差很多 習慣中End


2015年1月22日 星期四

[Android] "ClassNotFoundException" / " Binary XML file line # : Error inflating class” / " multiple dex files define"錯誤解決

在寫Android的時候會使用到別人所用的library,

常常會看到ClassNotFound or Binary XML line #數字 Error inflating class

他的意思就是說(如果我沒有會錯意的話)  :他找不到你import的那個library

為什麼呢?

可能性有幾種(我目前知道解決方式也只有兩種,所以就列出兩種)


1) 你沒有正確import Library


請確定這裡面有打勾了,而不是紅色的X (如果沒有正確import就remove掉重新import一次)



通常新建的專案都會有內建android-support-v4.jar 但是你library又有一份,所以就class not found

exception ,因為她不知道要用哪一個(應該是這樣吧?)

這個就簡單一點,把lib資料夾裡面的android-support-v4.jar 刪除就可以了!

當然會造成classnotfoundexception 跟 error inflating class可能原因有很多,只列舉我找到的解決

方式,紀錄一下 End



補充: multiple dex files define 也是有可能有重複的android-support-v4.jar(刪除即可)

2015年1月20日 星期二

[Android] 簡單氣象搜尋 (使用Yahoo Weather api)

氣象主要可以分為兩類:

1)使用地名(自行輸入)搜尋

2)使用座標(GPS)搜尋

這邊實作的部分是(1)

參考資料為:  zh-wang 在 Github上分享的程式碼

不過稍作修改-------下拉式更新天氣 , 跳出視窗式輸入地名

當然介面也有做調整,不過整體架構還是跟著參考資料修改而來的.


----------------------------------------

整個程式就分為3部分

1) 輸入地名(使用AlertDialog技術)

2) 下拉式更新(使用SwipeRefreshLayout技術)

3) 呼叫/解析Yahoo Weather Api 所傳回來的xml(呼叫yahoo Library)


先把MainActivity.class寫出來:

package com.example.weather_practice;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.civetcat.weather.library.WeatherInfo;
import com.civetcat.weather.library.YahooWeather;
import com.civetcat.weather.library.YahooWeather.SEARCH_MODE;
import com.civetcat.weather.library.YahooWeatherInfoListener;

public class MainActivity extends Activity implements YahooWeatherInfoListener {

private ImageView icon_img;
private TextView city_country_txv;
private TextView weather_status1_txv;
private TextView weather_status2_txv;
private TextView temperature_txv;
private AlertDialog dialog;
private static String City_Name;
private SwipeRefreshLayout laySwipe;

private YahooWeather mYahooWeather = YahooWeather.getInstance(5000, 5000, true);


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
        icon_img = (ImageView) findViewById(R.id.icon_img);
        city_country_txv = (TextView) findViewById(R.id.city_country_txv);
        weather_status1_txv = (TextView) findViewById(R.id.weather_status1_txv);
        weather_status2_txv = (TextView) findViewById(R.id.weather_status2_txv);
        temperature_txv = (TextView) findViewById(R.id.temperature_txv);    
       
        search_dialog();

initView();
        //searchByPlaceName("pingtung city");
}

private void search_dialog(){
// -----------取得Layout reference----------
LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
final View view = inflater.inflate(R.layout.input_city, null);      
       
// -----------產生登入視窗--------
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("天氣查詢");
builder.setMessage("輸入查詢天氣城市名稱:(英文)");//"Input Target IP:"
builder.setView(view);
builder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// TODO Auto-generated method stub
EditText edt = (EditText) view.findViewById(R.id.city_edt);
City_Name = edt.getText().toString();
Log.d("show",edt.getText().toString());
searchByPlaceName(edt.getText().toString());
}
});
builder.setNegativeButton("取消", null);
dialog = builder.create();
dialog.show();
}


private void initView(){
laySwipe = (SwipeRefreshLayout) findViewById(R.id.laySwipe);
laySwipe.setOnRefreshListener(onSwipeToRefresh);
laySwipe.setColorSchemeResources(
           android.R.color.holo_red_light,
           android.R.color.holo_blue_light,
           android.R.color.holo_green_light,
           android.R.color.holo_orange_light);
}

private OnRefreshListener onSwipeToRefresh = new OnRefreshListener(){

@Override
public void onRefresh() {
// TODO Auto-generated method stub
laySwipe.setRefreshing(true);
new Handler().postDelayed(new Runnable(){

@Override
public void run() {
// TODO Auto-generated method stub
laySwipe.setRefreshing(false);
searchByPlaceName(City_Name);
Toast.makeText(getApplicationContext(), "Refresh done!", Toast.LENGTH_SHORT).show();
}},5000);
}};

private void searchByPlaceName(String location) {
mYahooWeather.setNeedDownloadIcons(true);
mYahooWeather.setSearchMode(SEARCH_MODE.PLACE_NAME);
Log.d("searchByPlaceName","searchByPlaceName");
mYahooWeather.queryYahooWeatherByPlaceName(getApplicationContext(), location, MainActivity.this);
}

@Override
public void gotWeatherInfo(WeatherInfo weatherInfo) {
// TODO Auto-generated method stub
// 屏東代碼2306213 or TWXX0015
Log.d("got weather info","got weather info");
        if (weatherInfo != null) {
        city_country_txv.setText(City_Name+ ", "+ weatherInfo.getWOEIDCountry());

        weather_status1_txv.setText(weatherInfo.getCurrentConditionDate());
        weather_status2_txv.setText(weatherInfo.getCurrentText());
       
        temperature_txv.setText(weatherInfo.getCurrentTempC()+"℃");

        Log.d("weather info",weatherInfo.getCurrentText());
if (weatherInfo.getCurrentConditionIcon() != null) {
//設定icon

switch(weatherInfo.getCurrentText()){
//不全部列舉,有些不會發生
case "Freezing Drizzle":
break;
case "Drizzle":
break;
case "Freezing Rain":
break;
case "Light Rain":
icon_img.setImageResource(R.drawable.rain_wh);
break;
case "Showers":
break;
case "Blustery":
break;
case "Windy":
break;
case "Cold":
break;
case "Cloudy":
break;
case "Mostly Cloudy":
icon_img.setImageResource(R.drawable.double_cloud_wh);
break;
case "Partly Cloudy":
icon_img.setImageResource(R.drawable.cloud_wh);
break;
case "Clear": //night
break;
case "Sunny":
break;
case "Fair": //day or night
icon_img.setImageResource(R.drawable.night_wh);
break;
case "Hot":
break;
case "Isolated Thunderstorms":
break;
case "Scattered Thunderstorms":
break;
case "Scattered Showers":
break;
case "Thundershowers":
break;
case "Isolated Thundershowers":
break;
case "Haze":
icon_img.setImageResource(R.drawable.haze_wh);
break;
case "Fog":
icon_img.setImageResource(R.drawable.haze_wh);
break;
case "not available":
break;
}
}
        } else {
        }
}



@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}


********在這邊特別註明一下,yahoo有些天氣狀態還沒更新上去,所以switch case的部分要自行做調整(不過不影響整個程式碼運行)*******


search_dialog()函式就是負責跳出視窗讓使用者可以輸入地名,查詢天氣

initView() 則是初始化下拉式更新的元件

OnRefreshListener() 就監聽 沒別的 onRefresh()裡面就寫你更新時要做的動作,至於handler只是

因為要show toast而已,沒太大用處:)

searchByPlaceName() 這個很重要,他會呼叫到yahoo library 透過

SEARCH_MODE.PLACE_NAME 這方式來搜尋天氣

然後因為我們一開頭有implement YahooWeatherInfoListener 所以他會自己監聽,(裡面有一個函式gotWeatherInfo,就是listener 實作的方法)


詳細的就請大家自己看一下囉,應該不難才對(?)


Activity_main.xml:

<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/laySwipe"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#87CEFA"
    android:orientation="vertical"
    tools:context="ah.hathi.simpleweather.WeatherActivity"
    tools:ignore="MergeRootFrame" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/city_country_txv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/activity_vertical_margin"
            android:gravity="center"
            android:text="城市,國家"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <ImageView
            android:id="@+id/icon_img"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:src="@drawable/sun_wh" />

        <TextView
            android:id="@+id/weather_status1_txv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="天氣狀態1"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <TextView
            android:id="@+id/weather_status2_txv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text="天氣狀態2"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_weight="0.5" >
        </FrameLayout>

        <TextView
            android:id="@+id/temperature_txv"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="@dimen/activity_vertical_margin"
            android:gravity="center"
            android:text="溫度"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textSize="@dimen/temperature_text_size" />
    </LinearLayout>

</android.support.v4.widget.SwipeRefreshLayout>


input_city.xml:

<?xml version="1.0" encoding="utf-8"?>
<EditText xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/city_edt"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

</EditText>

然後再values/dimens.xml 還有宣告一個

<resources>

    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
    <dimen name="temperature_text_size">30dp</dimen>

</resources>

修改這邊就可以方便修改溫度的字型大小




附上完整檔案,以上 


End


2015年1月14日 星期三

[Android] 基礎Google Map教學

終於把這個很煩人的google map弄出一點樣子

寫在這邊紀錄一下

可能會產生的錯誤會有幾種

1)  INSTALL_FAILED_MISSING_SHARED_LIBRARY Error

2) API Key failed

3) Permission denied



第一種很顯然你刷機(flash ROM)時候法google libary沒有匯入

第二種則是API Key你沒有用你專屬的key ->請到 https://console.developers.google.com/ 申請一

個,申請詳細辦法






切記!!! 你的package name要正確,不正確會無法顯示地圖!!

就把SHA1;package.name輸入在空格中,建立,然後就有API key了

第三種解決方式就是檢查你的AndroidManifest.xml是否有加入適當的permission


-------------------------------------------------------------------------------------------------------------------


以下為三項基礎

1.google play library

首先開啟SDK Manager ->檢查google play service (以下用圖來表示)








有錯誤一定是沒有import正確 / 沒有加入external jar files

然後



這部分需要開啟權限




最後原本的網址載點在這邊

https://github.com/googlemaps/hellomap-android

程式碼跟layout可以上去下載來看看

layout:

<?xml version="1.0" encoding="utf-8"?>
<!--
See this page for more XML attribute options
https://developers.google.com/maps/documentation/android/map#using_xml_attributes
-->
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:map="http://schemas.android.com/apk/res-auto"
          android:id="@+id/map"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:name="com.google.android.gms.maps.SupportMapFragment"
          map:mapType="normal"/>




MainActivity:

package com.example.hellomap;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;

public class MainActivity extends FragmentActivity {
    private GoogleMap mMap;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}


就這樣! 

完成圖 End

2015年1月8日 星期四

[Android] 長按切換2個Activity-----intent.setClass錯誤排除-----onGestureListener監聽手勢


為了讓兩個activity能夠順利切換,花了一些時間研究,

當然中間也遇到一些問題,在這邊紀錄一下.


首先切換Activity是使用intent->startActivity()來做切換

觸發則是長按畫面任意地方


首先先看如何監聽手勢(gesture):

OnGestureListener listener = new OnGestureListener(){

@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
// TODO Auto-generated method stub
return false;
}

@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
       Intent intent = new Intent();
       intent.setClass(MainActivity.this, switch_target.class);
       startActivity(intent);
       overridePendingTransition(R.anim.in_from_right, R.anim.out_to_left);
       MainActivity.this.finish();
}

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
// TODO Auto-generated method stub
return false;
}

@Override
public void onShowPress(MotionEvent e) {
// TODO Auto-generated method stub

}

@Override
public boolean onSingleTapUp(MotionEvent e) {
// TODO Auto-generated method stub
return false;
}};


別忘記要import 所需要的東西

import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;



動畫的部分,首先要在res/anim裡面新增兩個xml檔

第一個檔,檔名隨意設定
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:interpolator="@android:anim/linear_interpolator"
        android:fromXScale="0.0"
        android:toXScale="1.0"
        android:fromYScale="0.7"
        android:toYScale="1.0"
        android:fillAfter="false"
        android:startOffset="200"
        android:duration="200" />
    <translate
        android:fromXDelta="50%"
        android:toXDelta="0"
        android:startOffset="200"
        android:duration="200"/>
</set>


第二個檔也是檔名隨意設定


有了動畫xml檔 + 手勢(觸發事件),我們還缺一樣東西,就是切換activity


       Intent intent = new Intent();
       intent.setClass(MainActivity.this, switch_target.class);
       startActivity(intent);
       overridePendingTransition(R.anim.in_from_right, R.anim.out_to_left);
       MainActivity.this.finish();

切換Activity需要的就是intent,注意這邊

intent.setClass(MainActivity.this, switch_target.class);

是MainActivity.this, switch_target.class兩者是不一樣的,請不要搞錯了(搞錯他就會一直報錯)

 

The method setClass(Context, Class<?>) in the type Intent is not applicable for the arguments...............


這樣的錯誤訊息


另一端切換回來則是:

       Intent intent = new Intent();
       intent.setClass(switch_target.this,MainActivity.class);
       startActivity(intent);
       overridePendingTransition(R.anim.in_from_right, R.anim.out_to_left);
       switch_target.this.finish();


當然為了避免還是有人看了以後還是出錯,這邊也附上source code 方便大家看

這次的教學就到此囉 End