2012年3月22日 星期四

SQL Spatial學習_SQL Geometry From Text with Parameters

我們會為了安全性(註:使用 Parameters 集合,會將輸入視為常值,而不是可執行的程式碼。),在組合SQL語法時使用參數的方式傳入,直觀的想在geometry欄位上,寫法應該類似:

string SQLString = " insert into CPAttribute(Geom) values (@xyValue)";
sds.InsertParameters.Add("xyValue", "geometry::STPointFromText('POINT(" + EValue + " " + NValue + ")',0)");

但會出現下面這個錯誤訊息。
***********************************************************************
執行使用者自訂常式或彙總 "geometry" 時,發生 .NET Framework 錯誤:
System.FormatException: 24114: 在輸入的 well-known text (WKT) 中的標籤 geometry::STPointFro 無效。有效的標籤為 POINT、LINESTRING、POLYGON、MULTIPOINT、MULTILINESTRING、MULTIPOLYGON 或 GEOMETRYCOLLECTION。
***********************************************************************

正確的寫法應該是:

string SQLString = " insert into CPAttribute(Geom) values (geometry::STPointFromText(@xyValue,@spatial_ref))";
sds.InsertParameters.Add("xyValue", "POINT(" + EValue + " " + NValue + ")");
sds.InsertParameters.Add("spatial_ref", "0");


完整測試程式碼

System.Web.UI.WebControls.SqlDataSource sds = new System.Web.UI.WebControls.SqlDataSource();
sds.ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
string EValue = "123";
string NValue = "45";
string SQLString = " insert into CPAttribute(Geom) values (geometry::STPointFromText(@xyValue,@spatial_ref))";

sds.InsertParameters.Add("xyValue", "POINT(" + EValue + " " + NValue + ")");
sds.InsertParameters.Add("spatial_ref", "0");

sds.InsertCommand = SQLString;
sds.Insert();

2012年3月15日 星期四

iOS學習_Log問題(中文,消失,亂碼,LLDB)

今早不小心更新了iPad、Xcode、MAC,經過兩小時左右的奮鬥,終於在一點前完成更新,立刻進入接資料的相關實作,習慣很好的先log出接近來的內容,免得後來出錯找錯地方,但就在按下Run之後,慘絕人寰的事情又發生了:

不管是接WebService、GET接網頁、POST接網頁、網頁轉碼、iOS裡面轉碼,看到的不是亂碼、就是直接消失,不然就是被截斷的亂七八糟,就在兩個多小時的編碼奮鬥後,做了一個簡單到自己覺得很笨的測試:

NSLog(@"%@",@"喔喔");

不測還好,一測這個“喔喔”就像是擺在我桌上的食物一樣消失了,接著我又做了一個更蠢的事情:

NSLog(@"%@",@"ola");
NSLog(@"%@",@"羊肉爐");
NSLog(@"%@",@"ola");

很好,兩個ola疊在log列表,沒有看到“羊肉爐”,所以....前兩個小時的亂七八糟測試方向都錯了!!!!!!!

接著,放棄NSLog直接把接進來的資料顯示在iPad上:OK~~~~

所以問題就是log列表,沒辦法正確顯示出中文,這個原因真的讓人感到很好笑,用來檢查結果的工具竟然自己就有問題,這就像在百慕達要指北一樣有趣。

總之,問題出在log列表,原因是在Xcode更新為4.3後,預設的Debugger的模式為LLDB,可能因為剛推出來,沒有測到中文顯示的部分,所以可以把該模式改回之前使用的GDB模式。

更改位置:


然後重新啓動Xcode。

恭喜你~~博大精深的中文回來了!!!!YA~~

iOS學習_更新iPad到iOS5.1這一更新不得了

昨天整理程式碼到好晚,想說今天早上就開始iOS吧,結果就在認真三小時後,因為手抖了一下,把測試用的iPad升級到iOS5.1,結果慘絕人寰的事情發生了...

xcode找不到ipad

總之就是版本問題,原本是:
iPad:iOS5.0
MAC OS:10.7.2
Xcode:4.2

現在因為把iPad升級成iOS5.1,所以就必須一併升級Xcode,又因為要升級Xcode所以必須一併把MAC OS升級,要變成:
iPad:iOS5.1
MAC OS:10.7.3
Xcode:4.3

這邊就不得不說在更新上,Android的模式似乎比較讚喔!

2012年3月14日 星期三

Android小品_以ArcGIS Server SDK for Android建立圖台架構

前陣子為了轉換回Android,整理了快一星期iOS的程式碼,沒想到計畫趕不上變化,現在又要整理Android的程式碼,好險當時決定先做圖台架構,重構兩次後也有個樣子了?

使用:
1. Android4.03
2. ArcGIS Server SDK for Android 1.01

底圖切換:

定位查詢:

屬性查詢:

其實也就是之前iOS平台上的圖台架構,變成Android版本。

心得:Android真的很妙,幾乎所有預設的內容都不符合需求,幾乎所有的東西都需要經過重製,甚至ESRI所提供的範例也都非常的陽春,能夠想像最後沒有秀出屬性的Identify範例嗎?ㄎ

總之,要開始過著今天Android,明天iOS的生活,看我的左右戶搏。

Android學習_Imitate iOS's delegate callback

在iOS裡面最重要的傳值莫過於delegate,雖然在Android的架構中,delegate類似的概念並不是非常重要(Activity間傳值使用Bundle),但在稍微複雜的介面上,類似delegate的概念,將可以讓程式架構切的更清楚。

所以,就在Android實作一個自己的delegate吧。
架構:


1. 建立一個interface(同等於iOS內的protocol)

package delegate;
public interface oladelegate {
public void putData(String info);
}


2. 於觸發該delegate的類別中定義一個公開變數,並且呼叫步驟一delegate定義的方法。

public class SomeClass{
public oladelegate mdelegate;

public void SomeMethod(String info) {
mdelegate.putData(info);
}
}


3. 於介面上實現delegate定義的方法。

public class OlaActivity extends Activity implements oladelegate{

private SomeClass someclass;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
someclass.selegate=this;
}
public void putData(String info)
{
//做需要的動作
}
}

如果有在iOS實作過自己delegate的人,應該會覺得非常的熟悉。

2012年3月13日 星期二

Android學習_PopupWindow的使用

轉換回Android後,花最多時間的就是PopupWindow,因為在iOS中UIPopoverController是一個很完整的控制項,不但可以任意放入想要顯示的UIView、也可以選擇要出現的位置、視窗的箭頭方向、視窗的標題,甚至可以放入UINavigationController快速地進行不同View的切換。


註:iOS中我想要不點掉PopoverView的情況下,操作後面的內容,似乎無法做到?但整體還是瑕不掩瑜。

對應Android則為PopupWindow,在官網的說明為:"A popup window that can be used to display an arbitrary view. The popup windows is a floating container that appears on top of the current activity.",總之,他說PopupWindow是一個可以隨心所欲放入任何View的浮動視窗,所以我們可以馬上實做一個。

1. 建立一個想要在PopupWindow顯示的Layout
很單純的只在裡面加入一個Button與ListView。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#2B5D0E"
>
<Button android:id="@+id/btn_close"
android:text="@string/closepop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>

<EditText android:id="@+id/lab"
android:hint="@string/lab_hint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>

<ListView
android:id="@+id/lv"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
></ListView>
</LinearLayout>


2. 建立一個繼承於PopupWindow的類別

並且在按鈕的OnClickListener加上解散的語法

dismiss();


3. 把PopupWindow叫出來

private void pop()
{
Context mContext = OlaTeach_popupwindowActivity.this;
LayoutInflater mLayoutInflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE);
View v_pop = mLayoutInflater.inflate(R.layout.pop_identifyinfo, null);
popup_ola popOlaWindow = new popup_ola(v_pop, 400,600,this);
popOlaWindow.setContentView(v_pop);
popOlaWindow.update();
popOlaWindow.showAtLocation(findViewById(R.id.activityRoot), Gravity.LEFT|Gravity.TOP, 10, 70);
}

註:PopupWindow不能在onCreate的時候叫出來,若是想達到類似的效果,必須由一個Thread來執行。

我們可以在介面上以一個佈滿整個APP的按鈕呼叫剛剛建立的PopupWindow。

按一下按鈕,可以看到PopupWindow出現在視窗上。

這時心中應該是覺得,YES,完成了?

但是去點擊close的按鈕時,卻會發現Popup雖然有正確的執行OnClickListener內的程式碼,但卻沒有做出應有的動畫反應,也就是沒有變色;ListView也會有一樣的情況,雖然可以上下滾動,但點擊時Item卻不會變色;至於EditText更慘,點擊後不會出現小鍵盤供使用者輸入。

*這時點擊下方的大按鈕,可以發現仍舊可以操作。

---------------------------------------------------
**解決PopupWindow內Button、ListView沒對應動畫,EditText不會彈出小鍵盤

popOlaWindow.setFocusable(true);

很直觀的,我們設定Focus為true,讓Android知道應該要將焦點擺在PopupWindow上。
可以看到,Button與ListView現在都會顯示對應的動畫EditText也可以順利彈出虛擬鍵盤,但是PopupWindow卻沒辦法像一般認知的點擊外部時,直接隱藏,而必須要點擊close按鈕。

**解決點擊PopupWindow外時,自動隱藏PopupWindow

popOlaWindow.setBackgroundDrawable(new BitmapDrawable());

增加這句完全搞不懂原因的設定,將可以讓PopupWindow在兩種情況下隱藏:
1. 點擊PopupWindow以外的地方。
2. 點擊左下的Back按鈕。

正當高興時,點擊EditText跳出的虛擬鍵盤卻會造成另一個問題。
虛擬鍵盤的彈出,讓PopupWindow超出了螢幕的範圍,造成要輸入的EditText看不到。

**解決點擊EditText,PopupWindow移動問題。
最正確的解決方法應該是,當鍵盤彈出時,動態改變PopupWindow的高度,待鍵盤收起時再恢復(也就是iOS內建的解決方案),但查了很多方式,都沒辦法完整的實現,所以後來採取其他方式。
1. 把PopupWindow變矮:雖然感覺很蠢,但卻是最直接的方法。

2. 讓虛擬鍵盤彈出時,PopupWindow不要上移。

popOlaWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);

這也是我後來使用的方式。

------完整的呼叫程式碼-------

private void pop()
{
Context mContext = OlaTeach_popupwindowActivity.this;
LayoutInflater mLayoutInflater = (LayoutInflater) mContext.getSystemService(LAYOUT_INFLATER_SERVICE);
View v_pop = mLayoutInflater.inflate(R.layout.pop_identifyinfo, null);
popup_ola popOlaWindow = new popup_ola(v_pop, 400,600,this);
popOlaWindow.setFocusable(true);
popOlaWindow.setBackgroundDrawable(new BitmapDrawable());
popOlaWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
popOlaWindow.setContentView(v_pop);
popOlaWindow.update();
popOlaWindow.showAtLocation(findViewById(R.id.activityRoot), Gravity.LEFT|Gravity.TOP, 10, 70);
}


最後,我們可以稍微套一下版,做一個簡單的箭頭,

就可以完成擁有幾個特性的PopupWindow:
1. 可以放置其他View進去
2. 點擊PopupWindow內的元件可以做出應有之反應
3. 點擊外部或是返回鍵將可隱藏PopupWindow
4. 鍵盤的彈跳不會影響PopupWindow的操作
*. 但是沒辦法完成,PopupWindow一切操作正常,又可以操作後面控制項的方式。

如果照著做,恭喜你,關於PopupWindow的相關測試就花了三個整天。

後記--------------------------------------
這樣子的PopupWindow已經可符合許多應用的場合,但觀察Android內的Google Map可以發現:

在地圖上呈現了一個類似PopupWindow的效果,但除了可以正確的操作上面的控制項外,也可以同時操作地圖。該介面的呈現,很明顯不是由繼承PopupWindow的類別所完成,而必須要重新以其他方式撰寫,所以雖然好不容易PopupWindow已經可以使用,最後還是重新手工打造,做出類似PopupWindow卻可以同時操作地圖的視窗。

效果:

Android學習_客製化ListView_點擊後保持highlight

有時候我們會希望點擊完ListView上任一項目後,該項目可以highlight(高亮?),讓使用者清楚的對應目前內容;就想像上,應該會有一個屬性,把他設為true我們的ListView立刻就會有這一個功能?但想像總是美好的,這必須要客製化放入ListView的Adapter,才能正確無誤的顯示。

註:使用別種方法,有可能在ListView項目超出螢幕時產生重繪的錯亂,造成多筆變色或是變色項目亂跳的情況,所以完成後應先確認上述情況是否有發生。

若你並沒有已經客製化的Adapter,可以參考Android學習_客製化ListView_加上Button

----------------------實作----------------------
1. 對Adapter加工

A. 建立一記載點擊項次的變數

private int selectItem=-1;


B. 增加setSelectItem的公開方法

public void setSelectItem(int selectItem) {
this.selectItem = selectItem;
}


C. 於getView方法中,依照記載的項次變色。

if (position == selectItem) {
convertView.setBackgroundResource(R.drawable.green);
}
else {
convertView.setBackgroundResource(Color.TRANSPARENT);
}


2. 於ListView點擊時利用setSelectItem設定selectItem的值

private ListView.OnItemClickListener lv_itemClick = new ListView.OnItemClickListener(){
@Override
public void onItemClick(AdapterView parent,View v,int id,long arg3)
{
Btnadapter.setSelectItem(id);
Btnadapter.notifyDataSetInvalidated();
}
};

效果(綠色為上次點擊項目,藍色為預設手指目前點擊項目):

Android學習_客製化ListView_改變底線顏色

ListView分隔各Item的底線為白色,當我們使用淺色做底時,勢必需要進行更改。

android:divider="@drawable/listview_divider"
android:dividerHeight="1dip"

很難想像divider代表那條線。

Android學習_客製化ListView_加上Button

正覺得iOS寫的順手時,又很快樂的轉換回Android,最不習慣的莫過於介面上的配置,iOS幫開發者很貼心的加上許多美工部分,我們可以較容易地做出好看又顯專業的介面,但Android就必須要花很多時間在介面的配置上,其中包含許多設定上的小技巧,才能讓美感不佳如我的人做出差強人意的畫面。而在Android裡ListView可以說是一個倘若做的好,程式先有60分的一個重要控制項,所以這次花了很多時間在ListView上面,先看效果:

如標題所說,本篇主要介紹如何做出含有按鈕之ListView。

正文-------------------------------------------------
在iOS的UITableView中,有一種預設的模式會有文字與一個小圖示:

若是直接點擊文字或是空白處,會觸發didSelectRowAtIndexPath,若點擊旁邊的小圖示,則會觸發accessoryButtonTappendForRowWithIndexPath,所以在GIS系統開發上,就可以很容易的將定位與顯示屬性分別在這兩個事件上實現,提供使用者一個很不錯的操作方式。

但反觀Android,這樣的需求就必須要經過自己重新撰寫,才能達到類似的效果;在之前曾經有發過相關文章,這篇剛好可以補足完整客製化時的教學。
一維陣列:Android學習_ArrayAdapter的使用
自行處理的二維陣列:Android學習_SimpleAdapter的使用
Cursor的處理:Android學習_SimpleCursorAdapter的使用
光是單純的變化都需要自行實作,更何況在ListView上面加個與事件綁定的小圖示。

--------------------------實作-------------------------
所以本篇的目標,就是客製化一個帶有按鈕的ListView,目標像下面這張:

可以顯示相關小圖示,主要標題、副標與一個帶有事件的按鈕。

觀念:觀察要將資料放入ListView的方法是setAdapter(adapter),所以唯一方法即是客製化adapter。

步驟:
1. 一個依照需求設計好的adapter.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="3dip"
android:descendantFocusability="blocksDescendants" >

<ImageView
android:id="@+id/ItemImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="2dip"
android:contentDescription="@string/adapter_btnText"
/>

<LinearLayout android:layout_toRightOf="@id/ItemImage"
android:layout_toLeftOf="@+id/ItemButton"
android:layout_alignTop="@+id/ItemImage"
android:layout_alignBottom="@+id/ItemImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">

<TextView
android:id="@+id/ItemName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left|center_vertical"
android:textSize="20dip"
/>

<TextView
android:id="@+id/ItemInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left|center_vertical"
android:textSize="20dip"
/>
</LinearLayout>

<Button android:id="@+id/ItemButton"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:background="@drawable/ic_launcher"
android:contentDescription="@string/adapter_btnText"
/>

</RelativeLayout>

2. 建立一個繼承於Adapter的類別(本篇使用BaseAdapter)


可以看到若是繼承於BaseAdapter,預設會有四個方法:
A. public int getCount()
B. public Object getItem(int position)
C. public long getItemId(int position)
D. public View getView(int position, View convertView, ViewGroup parent)
當中最重要的方法是getView,該方法會在每次重新繪製ListView任一個Item時被呼叫,也就是說我們要客製化每一列,就必須在這個方法中描繪我們需要的內容,並返回一個處理好的View。

除了上述四個方法必須要複寫外,通常還會增加一個建構函式,在建立該Adapter時將所需要的外部變數丟入,也就是丟入我們要顯示的值與圖案。

最後,因為我們希望除了點擊ListView可以有反應外,點擊自己加上的按鈕也可以有相對應的事件觸發,所以需要增加一個OnClickListener來監聽。

程式碼:

package tw.com.wangshifu.ola;

import java.util.ArrayList;
import java.util.HashMap;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class lv_BtnAdapter extends BaseAdapter {

private ArrayList<HashMap<String, Object>> mAppList;
private LayoutInflater mInflater;
private Context mContext;
private String[] keyString;
private int[] valueViewID;

private ItemView itemView;

private class ItemView {
ImageView ItemImage;
TextView ItemName;
TextView ItemInfo;
Button ItemButton;
}

public lv_BtnAdapter(Context c, ArrayList<HashMap<String, Object>> appList, int resource, String[] from, int[] to) {
mAppList = appList;
mContext = c;
mInflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
keyString = new String[from.length];
valueViewID = new int[to.length];
System.arraycopy(from, 0, keyString, 0, from.length);
System.arraycopy(to, 0, valueViewID, 0, to.length);
}

@Override
public int getCount() {
// TODO Auto-generated method stub
//return 0;
return mAppList.size();
}

@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
//return null;
return mAppList.get(position);
}

@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
//return 0;
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
//return null;

if (convertView != null) {
itemView = (ItemView) convertView.getTag();
} else {
convertView = mInflater.inflate(R.layout.adapter_button, null);
itemView = new ItemView();
itemView.ItemImage = (ImageView)convertView.findViewById(valueViewID[0]);
itemView.ItemName = (TextView)convertView.findViewById(valueViewID[1]);
itemView.ItemInfo = (TextView)convertView.findViewById(valueViewID[2]);
itemView.ItemButton = (Button)convertView.findViewById(valueViewID[3]);
convertView.setTag(itemView);
}

HashMap<String, Object> appInfo = mAppList.get(position);
if (appInfo != null) {

int mid = (Integer)appInfo.get(keyString[0]);
String name = (String) appInfo.get(keyString[1]);
String info = (String) appInfo.get(keyString[2]);
int bid = (Integer)appInfo.get(keyString[3]);
itemView.ItemName.setText(name);
itemView.ItemInfo.setText(info);
itemView.ItemImage.setImageDrawable(itemView.ItemImage.getResources().getDrawable(mid));
itemView.ItemButton.setBackgroundDrawable(itemView.ItemButton.getResources().getDrawable(bid));
itemView.ItemButton.setOnClickListener(new ItemButton_Click(position));
}

return convertView;
}

class ItemButton_Click implements OnClickListener {
private int position;

ItemButton_Click(int pos) {
position = pos;
}

@Override
public void onClick(View v) {
int vid=v.getId();
if (vid == itemView.ItemButton.getId())
Log.v("ola_log",String.valueOf(position) );
}
}
}

3. 使用步驟二所建立的adapter,置入ListView中
我們用簡單的迴圈模擬外部要放入的資料,並且將剛剛所建立的adapter new起來:

protected void putDataToListView()
{
ArrayList<HashMap<String, Object>> Item = new ArrayList<HashMap<String, Object>>();
for(int i=0; i<20; i++)
{
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("ItemImage", R.drawable.ic_launcher);
map.put("ItemName", "Name");
map.put("ItemInfo", "Info");
map.put("ItemButton", R.drawable.ic_launcher);
Item.add(map);
}

lv_BtnAdapter Btnadapter = new lv_BtnAdapter(
this,
Item,
R.layout.adapter_button,
new String[] {"ItemImage","ItemName", "ItemInfo","ItemButton"},
new int[] {R.id.ItemImage,R.id.ItemName,R.id.ItemInfo,R.id.ItemButton}
);
lv.setAdapter(Btnadapter);
}

效果:

稍微對於輸入的內容做些變更,就可以看出客製化的效果:

最後的列表效果可以說是非常之讚。

2012年3月5日 星期一

iOS小品(使用ArcGIS Server SDK for iOS與Google Map API)

準備要轉換回Android,把一些平常日、假日測試的程式碼整理後,完成這一個看似比較完整的當作逗點吧...

平台:iOS

使用技術:
1. ArcGIS Server SDK for iOS
2. Geoprocessing Service
3. Google Map API
4. Google Map Street View
5. Google Direction Service

註:若要觀看,請注意四下無人,並請戴耳機。

2012年3月2日 星期五

Sorry, My Dear Firends

這兩週想了很多,我慢慢可以瞭解無奈地消極面對事情的感覺,慢慢知道分享互助風氣之所以不盛的原因,也突然覺得自己之前想分享、想討論、想團隊合作的態度,也許已經造成許多人的困擾,因為我的愚昧在明的暗的說著我認為好的態度,自顧自的說卻不去設身處地想想別人可能的經歷,憑什麼希望別人也花時間在這些就某方面來說一點意義都沒有的事情?

我由衷的想向你們道歉,每個人都有自己心中重要的事情,每個人都有自己面對事情的態度與方法,我不應該認為我覺得好的事情你們也應該參與,對不起。

我由衷的向你道歉,我不應該對著一個還有些許熱情的人,一股腦的希望你應該一起做這個對於組織不正常的行為,甚至在過程中講超過了,只因為我覺得一起會更HIGH,對不起。

我由衷的向你道歉,本來你的加入可以讓這有趣的事情更加有趣,但我的新堅持超越了我原本對於這些事情的小小初衷,對不起。

我由衷向自己道歉,我做了自己最討厭的決定,對不起。

我知道我看大了自己,不太有人會在乎小人物的想法,我知道我的小小決定不會影響到任何人,但影響了我自己。